Job-Shop Model

Simlib to simulate a model of manufacturing system. This simulation illustrates how simulation can be used to identify bottlenecks in a production process. A manufacturing system consists of five work stations, and at present stations 1,2,…,5 consist of 3,2,4,3, and 1 identical machine(s), respectively. In effect, the system is a network of five multiserver queues. …………………………………………………

jobshop.c

/* External definitions for job-shop model. */

#include “simlib.h”              /* Required for use of simlib.c. */

#define EVENT_ARRIVAL         1  /* Event type for arrival of a job to the
system. */
#define EVENT_DEPARTURE       2  /* Event type for departure of a job from a
particular station. */
#define EVENT_END_SIMULATION  3  /* Event type for end of the simulation. */
#define STREAM_INTERARRIVAL   1  /* Random-number stream for interarrivals. */
#define STREAM_JOB_TYPE       2  /* Random-number stream for job types. */
#define STREAM_SERVICE        3  /* Random-number stream for service times. */
#define MAX_NUM_STATIONS      5  /* Maximum number of stations. */
#define MAX_NUM_JOB_TYPES     3  /* Maximum number of job types. */

/* Declare non-simlib global variables. */

int   num_stations, num_job_types, i, j, num_machines[MAX_NUM_STATIONS + 1],
num_tasks[MAX_NUM_JOB_TYPES +1],
route[MAX_NUM_JOB_TYPES +1][MAX_NUM_STATIONS + 1],
num_machines_busy[MAX_NUM_STATIONS + 1], job_type, task;
float mean_interarrival, length_simulation, prob_distrib_job_type[26],
mean_service[MAX_NUM_JOB_TYPES +1][ MAX_NUM_STATIONS + 1];
FILE  *infile, *outfile;

/* Declare non-simlib functions. */

void  arrive(int new_job);
void  depart(void);
void  report(void);

int main()  /* Main function. */
{
/* Open input and output files. */

infile  = fopen(“jobshop.in”,  “r”);
outfile = fopen(“jobshop.out”, “w”);

/* Read input parameters. */

fscanf(infile, “%d %d %f %f”, &num_stations, &num_job_types,
&mean_interarrival, &length_simulation);
for (j = 1; j <= num_stations; ++j)
fscanf(infile, “%d”, &num_machines[j]);
for (i = 1; i <= num_job_types; ++i)
fscanf(infile, “%d”, &num_tasks[i]);
for (i = 1; i <= num_job_types; ++i) {
for (j = 1; j <= num_tasks[i]; ++j)
fscanf(infile, “%d”, &route[i][j]);
for (j = 1; j <= num_tasks[i]; ++j)
fscanf(infile, “%f”, &mean_service[i][j]);
}
for (i = 1; i <= num_job_types; ++i)
fscanf(infile, “%f”, &prob_distrib_job_type[i]);

/* Write report heading and input parameters. */

fprintf(outfile, “Job-shop model\n\n”);
fprintf(outfile, “Number of work stations%21d\n\n”, num_stations);
fprintf(outfile, “Number of machines in each station     “);
for (j = 1; j <= num_stations; ++j)
fprintf(outfile, “%5d”, num_machines[j]);
fprintf(outfile, “\n\nNumber of job types%25d\n\n”, num_job_types);
fprintf(outfile, “Number of tasks for each job type      “);
for (i = 1; i <= num_job_types; ++i)
fprintf(outfile, “%5d”, num_tasks[i]);
fprintf(outfile, “\n\nDistribution function of job types  “);
for (i = 1; i <= num_job_types; ++i)
fprintf(outfile, “%8.3f”, prob_distrib_job_type[i]);
fprintf(outfile, “\n\nMean interarrival time of jobs%14.2f hours\n\n”,
mean_interarrival);
fprintf(outfile, “Length of the simulation%20.1f eight-hour days\n\n\n”,
length_simulation);
fprintf(outfile, “Job type     Work stations on route”);
for (i = 1; i <= num_job_types; ++i) {
fprintf(outfile, “\n\n%4d        “, i);
for (j = 1; j <= num_tasks[i]; ++j)
fprintf(outfile, “%5d”, route[i][j]);
}
fprintf(outfile, “\n\n\nJob type     “);
fprintf(outfile, “Mean service time (in hours) for successive tasks”);
for (i = 1; i <= num_job_types; ++i) {
fprintf(outfile, “\n\n%4d    “, i);
for (j = 1; j <= num_tasks[i]; ++j)
fprintf(outfile, “%9.2f”, mean_service[i][j]);
}

/* Initialize all machines in all stations to the idle state. */

for (j = 1; j <= num_stations; ++j)
num_machines_busy[j] = 0;

/* Initialize simlib */

init_simlib();

/* Set maxatr = max(maximum number of attributes per record, 4) */

maxatr = 4;  /* NEVER SET maxatr TO BE SMALLER THAN 4. */

/* Schedule the arrival of the first job. */

event_schedule(expon(mean_interarrival, STREAM_INTERARRIVAL),
EVENT_ARRIVAL);

/* Schedule the end of the simulation.  (This is needed for consistency of
units.) */

event_schedule(8 * length_simulation, EVENT_END_SIMULATION);

/* Run the simulation until it terminates after an end-simulation event
(type EVENT_END_SIMULATION) occurs. */

do {

/* Determine the next event. */

timing();

/* Invoke the appropriate event function. */

switch (next_event_type) {
case EVENT_ARRIVAL:
arrive(1);
break;
case EVENT_DEPARTURE:
depart();
break;
case EVENT_END_SIMULATION:
report();
break;
}

/* If the event just executed was not the end-simulation event (type
EVENT_END_SIMULATION), continue simulating.  Otherwise, end the
simulation. */

} while (next_event_type != EVENT_END_SIMULATION);

fclose(infile);
fclose(outfile);

return 0;
}

void arrive(int new_job)  /* Function to serve as both an arrival event of a job
to the system, as well as the non-event of a job’s
arriving to a subsequent station along its
route. */
{
int station;

/* If this is a new arrival to the system, generate the time of the next
arrival and determine the job type and task number of the arriving
job. */

if (new_job == 1) {

event_schedule(sim_time + expon(mean_interarrival, STREAM_INTERARRIVAL),
EVENT_ARRIVAL);
job_type = random_integer(prob_distrib_job_type, STREAM_JOB_TYPE);
task     = 1;
}

/* Determine the station from the route matrix. */

station = route[job_type][task];

/* Check to see whether all machines in this station are busy. */

if (num_machines_busy[station] == num_machines[station]) {

/* All machines in this station are busy, so place the arriving job at
the end of the appropriate queue. Note that the following data are
stored in the record for each job:
1. Time of arrival to this station.
2. Job type.
3. Current task number. */

transfer[1] = sim_time;
transfer[2] = job_type;
transfer[3] = task;
list_file(LAST, station);
}

else {

/* A machine in this station is idle, so start service on the arriving
job (which has a delay of zero). */

sampst(0.0, station);                              /* For station. */
sampst(0.0, num_stations + job_type);              /* For job type. */
++num_machines_busy[station];
timest((float) num_machines_busy[station], station);

/* Schedule a service completion.  Note defining attributes beyond the
first two for the event record before invoking event_schedule. */

transfer[3] = job_type;
transfer[4] = task;
event_schedule(sim_time
+ erlang(2, mean_service[job_type][task],
STREAM_SERVICE),
EVENT_DEPARTURE);
}
}

void depart(void)  /* Event function for departure of a job from a particular
station. */
{
int station, job_type_queue, task_queue;

/* Determine the station from which the job is departing. */

job_type = transfer[3];
task     = transfer[4];
station  = route[job_type][task];

/* Check to see whether the queue for this station is empty. */

if (list_size[station] == 0) {

/* The queue for this station is empty, so make a machine in this
station idle. */

–num_machines_busy[station];
timest((float) num_machines_busy[station], station);
}

else {

/* The queue is nonempty, so start service on first job in queue. */

list_remove(FIRST, station);

/* Tally this delay for this station. */

sampst(sim_time – transfer[1], station);

/* Tally this same delay for this job type. */

job_type_queue = transfer[2];
task_queue     = transfer[3];
sampst(sim_time – transfer[1], num_stations + job_type_queue);

/* Schedule end of service for this job at this station.  Note defining
attributes beyond the first two for the event record before invoking
event_schedule. */

transfer[3] = job_type_queue;
transfer[4] = task_queue;
event_schedule(sim_time
+ erlang(2, mean_service[job_type_queue][task_queue],
STREAM_SERVICE),
EVENT_DEPARTURE);
}

/* If the current departing job has one or more tasks yet to be done, send
the job to the next station on its route. */

if (task < num_tasks[job_type]) {
++task;
arrive(2);
}
}

void report(void)  /* Report generator function. */
{
int   i;
float overall_avg_job_tot_delay, avg_job_tot_delay, sum_probs;

/* Compute the average total delay in queue for each job type and the
overall average job total delay. */

fprintf(outfile, “\n\n\n\nJob type     Average total delay in queue”);
overall_avg_job_tot_delay = 0.0;
sum_probs                 = 0.0;
for (i = 1; i <= num_job_types; ++i) {
avg_job_tot_delay = sampst(0.0, -(num_stations + i)) * num_tasks[i];
fprintf(outfile, “\n\n%4d%27.3f”, i, avg_job_tot_delay);
overall_avg_job_tot_delay += (prob_distrib_job_type[i] – sum_probs)
* avg_job_tot_delay;
sum_probs = prob_distrib_job_type[i];
}
fprintf(outfile, “\n\nOverall average job total delay =%10.3f\n”,
overall_avg_job_tot_delay);

/* Compute the average number in queue, the average utilization, and the
average delay in queue for each station. */

fprintf(outfile,
“\n\n\n Work      Average number      Average       Average delay”);
fprintf(outfile,
“\nstation       in queue       utilization        in queue”);
for (j = 1; j <= num_stations; ++j)
fprintf(outfile, “\n\n%4d%17.3f%17.3f%17.3f”, j, filest(j),
timest(0.0, -j) / num_machines[j], sampst(0.0, -j));
}

simlib.c, simlib.h, simlibdefs.h can be found here

jobshop.in – Simulation Input

Input Parameters : Number of stations, number of job types, mean interarrival times, and the length of simulation.

Jobshop.out – Simulation Result

Reference :
Textbook : Simulation Modeling and Analysis

Strive to be independence

April 15, 2008
Taipei City
High Speed Network Lab

Udin Harun

Comments are closed.

%d bloggers like this: