View Javadoc
1   package nl.tudelft.simulation.dsol.demo.des.mm1.step09;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.djutils.event.Event;
7   import org.djutils.event.EventListener;
8   
9   import nl.tudelft.simulation.dsol.SimRuntimeException;
10  import nl.tudelft.simulation.dsol.experiment.Replication;
11  import nl.tudelft.simulation.dsol.model.AbstractDsolModel;
12  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterDouble;
13  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterException;
14  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterInteger;
15  import nl.tudelft.simulation.dsol.model.inputparameters.InputParameterMap;
16  import nl.tudelft.simulation.dsol.simulators.DevsSimulatorInterface;
17  import nl.tudelft.simulation.dsol.statistics.SimPersistent;
18  import nl.tudelft.simulation.dsol.statistics.SimTally;
19  import nl.tudelft.simulation.jstats.distributions.DistContinuous;
20  import nl.tudelft.simulation.jstats.distributions.DistExponential;
21  
22  /**
23   * Model with a generator that generates entities.
24   * <p>
25   * Copyright (c) 2025-2025 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
26   * for project information <a href="https://simulation.tudelft.nl/" target="_blank"> https://simulation.tudelft.nl</a>. The DSOL
27   * project is distributed under a three-clause BSD-style license, which can be found at
28   * <a href="https://https://simulation.tudelft.nl/dsol/docs/latest/license.html" target="_blank">
29   * https://https://simulation.tudelft.nl/dsol/docs/latest/license.html</a>.
30   * </p>
31   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
32   */
33  class DesQueueingModel9 extends AbstractDsolModel<Double, DevsSimulatorInterface<Double>> implements EventListener
34  {
35      /** the queue in which entities might be placed. */
36      private List<QueueEntry<Entity>> queue = new ArrayList<>();;
37  
38      /** the entity counter to provide a unique number. */
39      private int entityCounter = 0;
40  
41      /** the capacity of the server. */
42      private int capacity = 1;
43  
44      /** the capacity of the server. */
45      private int batchSize = 1;
46  
47      /** the number of busy units. */
48      private int busy = 0;
49  
50      /** the distribution of the interarrival time between entities. */
51      private DistContinuous interArrivalTime;
52  
53      /** the distribution of the processing time of entities. */
54      private DistContinuous processingTime;
55  
56      /** statistic to store the time entities spend in the queue. */
57      private SimTally<Double> tallyTimeInQueue;
58  
59      /** statistic to store the time entities spend in the system. */
60      private SimTally<Double> tallyTimeInSystem;
61  
62      /** statistic to store the utilization of the server. */
63      private SimPersistent<Double> persistentUtilization;
64  
65      /** statistic to store the length of the queue. */
66      private SimPersistent<Double> persistentQueueLength;
67  
68      /**
69       * Constructor for the model. This provides the distribution functions and the simulator to the model.
70       * @param simulator the simulator on which to schedule new events
71       */
72      public DesQueueingModel9(final DevsSimulatorInterface<Double> simulator)
73      {
74          super(simulator);
75          try
76          {
77              InputParameterMap generatorMap = new InputParameterMap("generator", "Generator", "Generator", 1.0);
78              generatorMap
79                      .add(new InputParameterDouble("intervalTime", "Average interval time", "Average interval time", 1.0, 1.0));
80              generatorMap.add(new InputParameterDouble("startTime", "Generator start time", "Generator start time", 0.0, 2.0));
81              generatorMap.add(new InputParameterInteger("batchSize", "Batch size", "batch size", 1, 3.0));
82              this.inputParameterMap.add(generatorMap);
83              InputParameterMap resourceMap = new InputParameterMap("resource", "Resource", "Resource", 2.0);
84              resourceMap.add(new InputParameterInteger("capacity", "Resource capacity", "Resource capacity", 1, 1.0));
85              resourceMap.add(new InputParameterDouble("serviceTime", "Average service time", "Average service time", 0.9, 2.0));
86              this.inputParameterMap.add(resourceMap);
87              this.simulator.addListener(this, Replication.END_REPLICATION_EVENT);
88          }
89          catch (InputParameterException e)
90          {
91              throw new SimRuntimeException("Error defining parameters for the model", e);
92          }
93      }
94  
95      @Override
96      public void constructModel() throws SimRuntimeException
97      {
98          double startTime = 0.0;
99          try
100         {
101             this.capacity = (Integer) getInputParameter("resource.capacity");
102             this.batchSize = (Integer) getInputParameter("generator.batchSize");
103             startTime = (Double) getInputParameter("generator.startTime");
104             double iat = (Double) getInputParameter("generator.intervalTime");
105             this.interArrivalTime = new DistExponential(getDefaultStream(), iat);
106             double st = (Double) getInputParameter("resource.serviceTime");
107             this.processingTime = new DistExponential(getDefaultStream(), st);
108         }
109         catch (InputParameterException e)
110         {
111             throw new SimRuntimeException("Error retrieving parameters for the model", e);
112         }
113 
114         this.tallyTimeInQueue = new SimTally<>("tQ", "Time in queue", this);
115         this.tallyTimeInSystem = new SimTally<>("tS", "Time in system", this);
116         this.persistentQueueLength = new SimPersistent<>("lQ", "Queue length", this);
117         this.persistentUtilization = new SimPersistent<>("Ut", "Server utilization", this);
118         this.persistentQueueLength.register(0.0, 0.0);
119         this.persistentUtilization.register(0.0, 0.0);
120 
121         this.simulator.scheduleEventRel(startTime, () -> generate());
122     }
123 
124     /**
125      * Generate one or more entities, based on batchSize.
126      */
127     protected void generate()
128     {
129         double time = getSimulator().getSimulatorTime();
130         for (int i = 0; i < this.batchSize; i++)
131         {
132             Entity entity = new Entity(this.entityCounter++, time);
133             if (this.capacity - this.busy >= 1)
134             {
135                 // process
136                 this.tallyTimeInQueue.register(0.0); // no waiting
137                 startProcess(entity);
138             }
139             else
140             {
141                 // queue
142                 this.queue.add(new QueueEntry<Entity>(entity, time));
143                 this.persistentQueueLength.register(time, this.queue.size());
144             }
145         }
146         this.simulator.scheduleEventRel(this.interArrivalTime.draw(), () -> generate());
147     }
148 
149     /**
150      * Start the processing of an entity by the server.
151      * @param entity the entity to be processed
152      */
153     protected void startProcess(final Entity entity)
154     {
155         double time = getSimulator().getSimulatorTime();
156         this.busy++;
157         this.persistentUtilization.register(time, this.busy);
158         this.simulator.scheduleEventRel(this.processingTime.draw(), () -> endProcess(entity));
159     }
160 
161     /**
162      * End the processing of an entity by the server.
163      * @param entity the entity that is being processed, and should leave the server
164      */
165     protected void endProcess(final Entity entity)
166     {
167         double time = getSimulator().getSimulatorTime();
168         this.busy--;
169         this.persistentUtilization.register(time, this.busy);
170         if (!this.queue.isEmpty())
171         {
172             QueueEntry<Entity> nextQueueEntry = this.queue.remove(0);
173             this.persistentQueueLength.register(time, this.queue.size());
174             this.tallyTimeInQueue.register(time - nextQueueEntry.getQueueInTime());
175             startProcess(nextQueueEntry.getEntity());
176         }
177         this.tallyTimeInSystem.register(time - entity.getCreateTime());
178     }
179 
180     /**
181      * Report statistics at the end of a replication.
182      */
183     protected void reportStats()
184     {
185         this.persistentUtilization.endObservations(getSimulator().getReplication().getRunLength());
186         this.persistentQueueLength.endObservations(getSimulator().getReplication().getRunLength());
187 
188         System.out.println(SimTally.reportHeader());
189         System.out.println(this.tallyTimeInQueue.reportLine());
190         System.out.println(this.tallyTimeInSystem.reportLine());
191         System.out.println(SimTally.reportFooter());
192 
193         System.out.println(SimPersistent.reportHeader());
194         System.out.println(this.persistentQueueLength.reportLine());
195         System.out.println(this.persistentUtilization.reportLine());
196         System.out.println(SimPersistent.reportFooter());
197     }
198 
199     @Override
200     public void notify(final Event event)
201     {
202         if (event.getType().equals(Replication.END_REPLICATION_EVENT))
203         {
204             reportStats();
205         }
206     }
207 
208 }