8.3 Modeling the Test and Repair System with Movable Resources

The results of the constrained resource analysis in Section 8.1.1 indicated that modeling constrained transfer for the parts in the test and repair system may have a significant effect on the system’s ability to meet the contract requirements. This may be due to having the workers share the roles of tending the machines and transporting the parts. The following example investigates whether or not a set of dedicated workers would make sense for this system. In particular, the number of workers to dedicate to the transport task needs to be determined. Since there is a lot of walking involved, the model needs to be more precise in the physical modeling of the situation. This could also allow different layout configurations to be simulated if the relocation of the stations would make a difference in the efficiency of the system.

To model this situation using movable resources, the distance between the stations and a way to model the velocity of transport are required. Since the workers have a natural variability in the speed of their walking, a model for human walking speed is needed. Based on some time study data, the velocity of a worker walking in the facility has been determined to be distributed according to a triangular distribution with a minimum of 22.86, a mode of 45.72, and a maximum of 52.5, all in meters per minute. Since this distribution will be used in many locations in the model, a random variable should be defined to represent the velocity.

Based on measuring the distance between the stations, the approximate distance between the stations has been determined as given in Table 8.1. Recall that both the loaded and unloaded distances for the movement should be specified. For example, even though no parts are routed from repair to diagnostics, the distance from repair to diagnostics should be given because the worker (transporter) may be at the repair station when something needs to be moved from the diagnostic station. Thus, the worker must walk from the repair station to the diagnostic station (unloaded) in order to pick up the part. Notice also that the distances do not have to be symmetric (i.e. the distance from test 1 to test 2 does not have to be the same as the distance from test 2 to test 1).

Table 8.1: Transporter distances between stations
Station Diagnostics Test 1 Test 2 Test 3 Repair
Diagnostics 40 70 90 100
Test 1 43 10 60 80
Test 2 70 15 65 20
Test 3 90 80 60 25
Repair 110 85 25 30

Starting with the finished model from Example 7.4 of Section 7.1.3 we can make small changes in order to utilize movable resources. The first step is to define the locations and walking speed for the transport workers.

    // velocity is in meters/min
    private val myWalkingSpeedRV = RandomVariable(this, TriangularRV(22.86, 45.72, 52.5))
    private val dm = DistancesModel()
    private val diagnosticStation = dm.Location("DiagnosticStation")
    private val testStation1 = dm.Location("TestStation1")
    private val testStation2 = dm.Location("TestStation2")
    private val testStation3 = dm.Location("TestStation3")
    private val repairStation = dm.Location("RepairStation")

Since the transport workers need to walk without carrying a part, we need to define the distances to and from the locations as shown in the following code. Notice that the walking speed is used for the default velocity of movement within the distance model.

    init {
        // distance is in meters
        dm.addDistance(diagnosticStation, testStation1, 40.0)
        dm.addDistance(diagnosticStation, testStation2, 70.0)
        dm.addDistance(diagnosticStation, testStation3, 90.0)
        dm.addDistance(diagnosticStation, repairStation, 100.0)

        dm.addDistance(testStation1, diagnosticStation, 43.0)
        dm.addDistance(testStation1, testStation2, 10.0)
        dm.addDistance(testStation1, testStation3, 60.0)
        dm.addDistance(testStation1, repairStation, 80.0)

        dm.addDistance(testStation2, diagnosticStation, 70.0)
        dm.addDistance(testStation2, testStation1, 15.0)
        dm.addDistance(testStation2, testStation3, 65.0)
        dm.addDistance(testStation2, repairStation, 20.0)

        dm.addDistance(testStation3, diagnosticStation, 90.0)
        dm.addDistance(testStation3, testStation1, 80.0)
        dm.addDistance(testStation3, testStation2, 60.0)
        dm.addDistance(testStation3, repairStation, 25.0)

        dm.addDistance(repairStation, diagnosticStation, 110.0)
        dm.addDistance(repairStation, testStation1, 85.0)
        dm.addDistance(repairStation, testStation2, 25.0)
        dm.addDistance(repairStation, testStation3, 30.0)

        dm.defaultVelocity = myWalkingSpeedRV
        spatialModel = dm
    }

Now, we can define the transport workers as a pool of movable resources. We will specify that there will be three workers dedicated to the transport task. In this case, the workers will start active at the diagnostics station. For the purposes of this example, we will rely on the default movable resource selection and allocation rules.

    private val transportWorkers = MovableResourcePoolWithQ(
        this, 3, diagnosticStation, myWalkingSpeedRV, name = "TransportWorkerPool")

Since this situation involves travelling to and from the stations, we need to make a slight change to the test plan definitions given in Example 7.4 of Section 7.1.3. We need to add the destination location to the test plan sequences.

    // define steps to represent a plan, include location information
    inner class TestPlanStep(
        val testMachine: ResourceWithQ,
        val processTime: RandomIfc,
        val testStation: LocationIfc)

    // make all the plans
    private val testPlan1 = listOf(
        TestPlanStep(myTest2, t11, testStation2), TestPlanStep(myTest3, t12, testStation3),
        TestPlanStep(myTest2, t13, testStation2), TestPlanStep(myTest1, t14, testStation1)
    )

Notice that the property testStation has been added to the TestPlanStep class. This property will hold the destination information for transport from the entity’s current location to its destination. The code illustrates how the information for test plan 1 has been updated. Recall from Example 7.4 that the test machine visitation sequence for test plan 1 is \(2-3-2-1\). This information has been added to the test plan steps for test plan 1. The other test plans are updated in a similar manner. The process description for the test and repair activities becomes straightforward.

    private inner class Part : Entity() {
        val plan: List<TestPlanStep> = planList.randomElement

        val testAndRepairProcess: KSLProcess = process(isDefaultProcess = true) {
            currentLocation = diagnosticStation
            wip.increment()
            timeStamp = time
            //every part goes to diagnostics
            use(diagnosticWorkers, delayDuration = diagnosticTime)
            // get the iterator
            val itr = plan.iterator()
            // iterate through the plan
            while (itr.hasNext()) {
                val tp = itr.next()
                // goto the location
                transportWith(transportWorkers, toLoc = tp.testStation)
                // use the tester
                use(tp.testMachine, delayDuration = tp.processTime)
            }
            // visit repair
            transportWith(transportWorkers, toLoc = repairStation)
            use(repairWorkers, delayDuration = repairTimes[plan]!! )
            timeInSystem.value = time - timeStamp
            wip.decrement()
        }
    }

Notice that the property plan is randomly determined when the part is created. The testAndRepairProcess has the entity starting at the diagnostic station by setting the part’s currenLocation property to the diagnostic station location. Then, the part uses the diagnostic workers. Because the test plan has the destination of the next station, the transport is placed at the top of the iteration through the test plan sequence. The transportWith() function is used to transport the part using the transportWorkers movable resource pool. Then, the appropriate test machine is used for the appropriate processing time for the test plan step. After visiting all the test machines on its sequence the part then transports to the repair station, where it uses the repair workers.

The following provides the results from running the model under the same settings as in Example 7.4.

Statistical Summary Report

Name Count Average Half-Width
DiagnosticWorkers:InstantaneousUtil 10 0.75 0.005
DiagnosticWorkers:NumBusyUnits 10 1.5 0.011
DiagnosticWorkers:ScheduledUtil 10 0.75 0.005
DiagnosticWorkers:Q:NumInQ 10 1.928 0.107
DiagnosticWorkers:Q:TimeInQ 10 38.512 2.167
DiagnosticWorkers:WIP 10 3.428 0.114
Test1:InstantaneousUtil 10 0.857 0.007
Test1:NumBusyUnits 10 0.857 0.007
Test1:ScheduledUtil 10 0.857 0.007
Test1:Q:NumInQ 10 3.232 0.266
Test1:Q:TimeInQ 10 57.414 4.459
Test1:WIP 10 4.088 0.271
Test2:InstantaneousUtil 10 0.776 0.008
Test2:NumBusyUnits 10 0.776 0.008
Test2:ScheduledUtil 10 0.776 0.008
Test2:Q:NumInQ 10 1.584 0.138
Test2:Q:TimeInQ 10 42.121 3.445
Test2:WIP 10 2.36 0.142
Test3:InstantaneousUtil 10 0.862 0.005
Test3:NumBusyUnits 10 0.862 0.005
Test3:ScheduledUtil 10 0.862 0.005
Test3:Q:NumInQ 10 2.587 0.158
Test3:Q:TimeInQ 10 51.666 3.03
Test3:WIP 10 3.449 0.16
RepairWorkers:InstantaneousUtil 10 0.868 0.005
RepairWorkers:NumBusyUnits 10 2.605 0.014
RepairWorkers:ScheduledUtil 10 0.868 0.005
RepairWorkers:Q:NumInQ 10 1.294 0.081
RepairWorkers:Q:TimeInQ 10 25.864 1.559
RepairWorkers:WIP 10 3.899 0.09
TransportWorkerPool:R1:InstantaneousUtil 10 0.224 0.002
TransportWorkerPool:R1:NumBusyUnits 10 0.224 0.002
TransportWorkerPool:R1:ScheduledUtil 10 0.224 0.002
TransportWorkerPool:R1:FracTimeMoving 10 0.224 0.002
TransportWorkerPool:R1:FracTimeTransporting 10 0.147 0.001
TransportWorkerPool:R1:FracTimeMovingEmpty 10 0.076 0.001
TransportWorkerPool:R2:InstantaneousUtil 10 0.158 0.001
TransportWorkerPool:R2:NumBusyUnits 10 0.158 0.001
TransportWorkerPool:R2:ScheduledUtil 10 0.158 0.001
TransportWorkerPool:R2:FracTimeMoving 10 0.158 0.001
TransportWorkerPool:R2:FracTimeTransporting 10 0.104 0.001
TransportWorkerPool:R2:FracTimeMovingEmpty 10 0.054 0
TransportWorkerPool:R3:InstantaneousUtil 10 0.085 0.001
TransportWorkerPool:R3:NumBusyUnits 10 0.085 0.001
TransportWorkerPool:R3:ScheduledUtil 10 0.085 0.001
TransportWorkerPool:R3:FracTimeMoving 10 0.085 0.001
TransportWorkerPool:R3:FracTimeTransporting 10 0.057 0.001
TransportWorkerPool:R3:FracTimeMovingEmpty 10 0.029 0.001
TransportWorkerPool:NumBusy 10 0.467 0.003
TransportWorkerPool:FractionBusy 10 0.156 0.001
TransportWorkerPool:Q:NumInQ 10 0.001 0
TransportWorkerPool:Q:TimeInQ 10 0.005 0
TestAndRepairWithMovableResources:NumInSystem 10 17.692 0.363
TestAndRepairWithMovableResources:TimeInSystem 10 353.457 5.965
ProbWithinLimit 10 0.811 0.015
DiagnosticWorkers:SeizeCount 10 12498.4 75.757
Test1:SeizeCount 10 14038.7 112.996
Test2:SeizeCount 10 9377.7 97.686
Test3:SeizeCount 10 12491 74.153
RepairWorkers:SeizeCount 10 12485.3 73.123
TransportWorkerPool:R1:SeizeCount 10 23121.6 165.847
TransportWorkerPool:R2:SeizeCount 10 16375.3 133.58
TransportWorkerPool:R3:SeizeCount 10 8905.1 137.667

As can be seen in the results, the utilization of the three transporters is very low (0.156). Less than three workers are probably needed for the transport task. The reader is asked to explore this issue as an exercise. These results match very closely with the results based on a commercial simulation package discussed in this book..