package nl.tudelft.simulation.dsol.swing.gui.test; import java.io.Serializable; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; import org.djutils.logger.CategoryLogger; import nl.tudelft.simulation.dsol.SimRuntimeException; import nl.tudelft.simulation.dsol.model.AbstractDSOLModel; import nl.tudelft.simulation.dsol.simtime.dist.DistContinuousSimulationTime; import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface; import nl.tudelft.simulation.dsol.statistics.SimPersistent; import nl.tudelft.simulation.dsol.statistics.SimTally; import nl.tudelft.simulation.jstats.distributions.DistExponential; import nl.tudelft.simulation.jstats.distributions.DistTriangular; import nl.tudelft.simulation.jstats.streams.MersenneTwister; import nl.tudelft.simulation.jstats.streams.StreamInterface; /** * Simple M/M/1 queuing model, which can be changed into a X/X/c model by changing the parameters. *

* Copyright (c) 2020-2022 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See * for project information DSOL Manual. The DSOL * project is distributed under a three-clause BSD-style license, which can be found at * DSOL License. *

* @author Alexander Verbraeck */ public class MM1Model extends AbstractDSOLModel.TimeDouble { /** */ private static final long serialVersionUID = 1L; /** resource capacity. */ private int capacity = 1; /** busy units. */ private int busy = 0; /** the stream. */ private StreamInterface stream = new MersenneTwister(12L); /** inter-arrival time. */ private DistContinuousSimulationTime.TimeDouble interarrivalTime = new DistContinuousSimulationTime.TimeDouble(new DistExponential(this.stream, 1.0)); /** processing time. */ private DistContinuousSimulationTime.TimeDouble processingTime = new DistContinuousSimulationTime.TimeDouble(new DistTriangular(this.stream, 0.8, 0.9, 1.1)); /** queue of waiting entities. */ private List> queue = new ArrayList>(); /** entity counter for id. */ private int entityCounter = 0; /** statistics for the utilization. */ @SuppressWarnings("checkstyle:visibilitymodifier") SimPersistent.TimeDouble persistentUtilization; /** statistics for the queue length. */ @SuppressWarnings("checkstyle:visibilitymodifier") SimPersistent.TimeDouble persistentQueueLength; /** statistics for the time in queue. */ @SuppressWarnings("checkstyle:visibilitymodifier") SimTally.TimeDouble tallyTimeInQueue; /** statistics for the time in system. */ @SuppressWarnings("checkstyle:visibilitymodifier") SimTally.TimeDouble tallyTimeInSystem; /** * @param simulator DEVSSimulator.TimeDouble; */ public MM1Model(final DEVSSimulatorInterface.TimeDouble simulator) { super(simulator); } /** {@inheritDoc} */ @Override public Serializable getSourceId() { return "MM1Model"; } /** {@inheritDoc} */ @Override public void constructModel() throws SimRuntimeException { try { this.persistentUtilization = new SimPersistent.TimeDouble("utilization", this.simulator); this.persistentQueueLength = new SimPersistent.TimeDouble("queue length", this.simulator); this.tallyTimeInQueue = new SimTally.TimeDouble("time in queue", this.simulator); this.tallyTimeInSystem = new SimTally.TimeDouble("time in system", this.simulator); } catch (RemoteException exception) { exception.printStackTrace(); } generate(); } /** * Generate new items. Reschedules itself. * @throws SimRuntimeException on simulation error */ protected void generate() throws SimRuntimeException { Entity entity = new Entity(this.entityCounter++, this.simulator.getSimulatorTime()); System.out.println("Generated: " + entity); CategoryLogger.always().info("Generated: " + entity); synchronized (this.queue) { if (this.capacity - this.busy >= 1) { // process startProcess(entity); } else { // queue this.persistentQueueLength.ingest(this.queue.size()); this.queue.add(new QueueEntry(entity, this.simulator.getSimulatorTime())); System.out.println("In Queue: " + entity); } } this.simulator.scheduleEventRel(this.interarrivalTime.draw(), this, this, "generate", null); } /** * @param entity Entity; entity to process * @throws SimRuntimeException on simulation error */ protected void startProcess(final Entity entity) throws SimRuntimeException { System.out.println("Start Process: " + entity); this.persistentUtilization.ingest(this.busy); this.busy++; this.persistentUtilization.ingest(this.busy); this.simulator.scheduleEventRel(this.processingTime.draw(), this, this, "endProcess", new Object[] {entity}); this.tallyTimeInQueue.ingest(this.simulator.getSimulatorTime() - entity.getCreateTime()); } /** * @param entity Entity; entity to stop processing * @throws SimRuntimeException on simulation error */ protected void endProcess(final Entity entity) throws SimRuntimeException { System.out.println("End Process: " + entity); this.persistentUtilization.ingest(this.busy); this.busy--; this.persistentUtilization.ingest(this.busy); if (!this.queue.isEmpty()) { this.persistentQueueLength.ingest(this.queue.size()); startProcess(this.queue.remove(0).getEntity()); } this.tallyTimeInSystem.ingest(this.simulator.getSimulatorTime() - entity.getCreateTime()); } /******************************************************************************************************/ protected class Entity { /** time of creation for statistics. */ private final double createTime; /** id number. */ private final int id; /** * @param id int; entity id number * @param createTime double; time of creation for statistics */ public Entity(final int id, final double createTime) { super(); this.id = id; this.createTime = createTime; } /** * @return time of creation for statistics */ public double getCreateTime() { return this.createTime; } /** * @return entity id number */ public int getId() { return this.id; } /** {@inheritDoc} */ @Override public String toString() { return "Entity [createTime=" + this.createTime + ", id=" + this.id + "]"; } } /******************************************************************************************************/ /** * Queue entry of an entity of type E. * @param the entity type in the queue */ protected class QueueEntry { /** time of queue entry for statistics. */ private final double queueInTime; /** entity in the queue. */ private final E entity; /** * @param entity E; the entity to insert in the queue * @param queueInTime double; the time it gets into the queue */ public QueueEntry(final E entity, final double queueInTime) { super(); this.entity = entity; this.queueInTime = queueInTime; } /** * @return queueInTime */ public double getQueueInTime() { return this.queueInTime; } /** * @return entity */ public E getEntity() { return this.entity; } /** {@inheritDoc} */ @Override public String toString() { return "QueueEntry [queueInTime=" + this.queueInTime + ", entity=" + this.entity + "]"; } } }