From cf796e9112524df25bcde0f419b9850be72b4a79 Mon Sep 17 00:00:00 2001 From: dansl <dansl@LAPTOP-SIKRVJU7.ern.nps.edu> Date: Tue, 6 Jun 2023 13:40:23 -0700 Subject: [PATCH] Commit additions for Steady State and Transient Stats --- MV3302ClassCode/newJavaFile.java | 18 ++ MV3302ClassCode/output.csv | 0 .../src/mv3302/EntityArrivalProcess.java | 50 ++++ MV3302ClassCode/src/mv3302/EntityServer.java | 235 ++++++++++++++++++ .../src/mv3302/StoppedPartArrivalProcess.java | 62 +++++ .../src/mv3302/TransientStats.java | 53 ++++ .../mv3302/run/RunSteadyStateAnalysis.java | 77 ++++++ .../src/mv3302/run/RunTransientAnalysis.java | 72 ++++++ 8 files changed, 567 insertions(+) create mode 100644 MV3302ClassCode/newJavaFile.java create mode 100644 MV3302ClassCode/output.csv create mode 100644 MV3302ClassCode/src/mv3302/EntityArrivalProcess.java create mode 100644 MV3302ClassCode/src/mv3302/EntityServer.java create mode 100644 MV3302ClassCode/src/mv3302/StoppedPartArrivalProcess.java create mode 100644 MV3302ClassCode/src/mv3302/TransientStats.java create mode 100644 MV3302ClassCode/src/mv3302/run/RunSteadyStateAnalysis.java create mode 100644 MV3302ClassCode/src/mv3302/run/RunTransientAnalysis.java diff --git a/MV3302ClassCode/newJavaFile.java b/MV3302ClassCode/newJavaFile.java new file mode 100644 index 0000000000..6592d790c5 --- /dev/null +++ b/MV3302ClassCode/newJavaFile.java @@ -0,0 +1,18 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Other/File.java to edit this template + */ + +/** + * + * @author dansl + */ +public class newJavaFile { + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + // TODO code application logic here + } +} diff --git a/MV3302ClassCode/output.csv b/MV3302ClassCode/output.csv new file mode 100644 index 0000000000..e69de29bb2 diff --git a/MV3302ClassCode/src/mv3302/EntityArrivalProcess.java b/MV3302ClassCode/src/mv3302/EntityArrivalProcess.java new file mode 100644 index 0000000000..16fd60ce98 --- /dev/null +++ b/MV3302ClassCode/src/mv3302/EntityArrivalProcess.java @@ -0,0 +1,50 @@ +package mv3302; + +import simkit.Entity; +import simkit.random.RandomVariate; + +/** + * Instantiates an <code>Entity</code> at each Arrival event and schedules an + * Arrival event with that as its argument + * + * @author ahbuss + */ +public class EntityArrivalProcess extends ArrivalProcess { + + /** + * Zero-argument constructor + */ + public EntityArrivalProcess() { + super(); + } + + /** + * Instantiate an <code>EntityArrivalProcess</code> with the given + * <code>interarrivalTimeGenerator</code> + * + * @param interarrivalTimeGenerator Given + * <code>interarrivalTimeGenerator</code> + */ + public EntityArrivalProcess(RandomVariate interarrivalTimeGenerator) { + super(interarrivalTimeGenerator); + } + + /** + * Schedule Arrival(Entity) with a new instance of <code>Entity</code><br> + */ + @Override + public void doArrival() { + super.doArrival(); + var entity = new Entity(); + waitDelay("Arrival", 0.0, entity); + } + + /** + * Does nothing, since this is only to be "heard" + * + * @param entity Given Entity + */ + public void doArrival(Entity entity) { + } + +} diff --git a/MV3302ClassCode/src/mv3302/EntityServer.java b/MV3302ClassCode/src/mv3302/EntityServer.java new file mode 100644 index 0000000000..531632f680 --- /dev/null +++ b/MV3302ClassCode/src/mv3302/EntityServer.java @@ -0,0 +1,235 @@ +package mv3302; + +import static java.lang.Double.NaN; +import java.util.SortedSet; +import java.util.TreeSet; +import simkit.Entity; +import static simkit.Priority.HIGH; +import simkit.SimEntityBase; +import simkit.random.RandomVariate; + +/** + * Implementation of the multiple server queue model using<code>Entity</code> + * objects to represent individual customers. This allows the model to + * explicitly tally measures such as delay in queue and time in system. + * + * @author ahbuss + */ +public class EntityServer extends SimEntityBase { + + /** + * Number of servers (k) + */ + private int totalNumberServers; + + /** + * Generates service times ({t<sub>S</sub>}) + */ + private RandomVariate serviceTimeGenerator; + + /** + * # of available servers (S) + */ + protected int numberAvailableServers; + + /** + * Container of waiting customers (q) + */ + protected SortedSet<Entity> queue; + + /** + * time a given customer spends in queue (D - a transient state) + */ + protected double delayInQueue; + + /** + * time a given customer spends in the system (W - a transient state) + */ + protected double timeInSystem; + + /** + * Total number who complete service + */ + protected int numberServed; + + /** + * Instantiate an EntityServer with the given titalNumberServers and + * serviceTimeGenerator. Note: should call <code>this()</code> to ensure + * that <code>queue</code> is instantiated + * + * @param totalNumberServers + * @param serviceTimeGenerator + */ + public EntityServer(int totalNumberServers, RandomVariate serviceTimeGenerator) { + this(); + setTotalNumberServers(totalNumberServers); + setServiceTimeGenerator(serviceTimeGenerator); + } + + /** + * Instantiate the <code>queue</code>state variable + */ + public EntityServer() { + this.queue = new TreeSet<>(); + } + + /** + * Initialize state variables:<ul> + * <li>Empty <code>queue</code> + * <li>set numberAvailableServers to totalNumberServers + * <li>Set numberServed to 0 + * <li>Set delayInQueue to NaN + * <li>Set timeInSystem to NaN </ul> + */ + @Override + public void reset() { + super.reset(); + queue.clear(); + numberAvailableServers = getTotalNumberServers(); + numberServed = 0; + delayInQueue = NaN; + timeInSystem = NaN; + } + + /** + * Fire property changes for time-varying states + */ + public void doRun() { + firePropertyChange("queue", getQueue()); + firePropertyChange("numberAvailableServers", getNumberAvailableServers()); + firePropertyChange("numberServed", getNumberServed()); + } + + /** + * Stamp time and add customer to <code>queue</code><br> + * if available server, schedule StartService with delay of 0.0 + * + * @param customer Arriving customer + */ + public void doArrival(Entity customer) { + customer.stampTime(); + var oldQueue = getQueue(); + queue.add(customer); + firePropertyChange("queue", oldQueue, getQueue()); + + if (numberAvailableServers > 0) { + waitDelay("StartService", 0.0, HIGH); + } + } + + /** + * Decrement numbervailableServers<br> + * Remove first customer from <code>queue</code><br> + * Compute delayInQueue as elapsed time<br> + * Schedule EndSrevice with delay generated by serviceTimeGenerator + */ + public void doStartService() { + var oldNumberAvailableServers = getNumberAvailableServers(); + numberAvailableServers -= 1; + firePropertyChange("numberAvailableServers", oldNumberAvailableServers, getNumberAvailableServers()); + + var oldQueue = getQueue(); + var customer = queue.first(); + queue.remove(customer); + firePropertyChange("queue", oldQueue, getQueue()); + + delayInQueue = customer.getElapsedTime(); + firePropertyChange("delayInQueue", getDelayInQueue()); + + waitDelay("EndService", serviceTimeGenerator, customer); + } + + /** + * Increment numberAvailableServers<br> + * Compute timeInSystem as customer's elapsedTime<br> + * Increment numberServed<br> + * If customer(s) in <code>queue</code>, schedule StartService with delay of 0.0 + * + * @param customer Given customer completing service + */ + public void doEndService(Entity customer) { + var oldNumberAvailableServers = getNumberAvailableServers(); + numberAvailableServers += 1; + firePropertyChange("numberAvailableServers", oldNumberAvailableServers, getNumberAvailableServers()); + + timeInSystem = customer.getElapsedTime(); + firePropertyChange("timeInSystem", getTimeInSystem()); + + var oldNumberServed = getNumberServed(); + numberServed += 1; + firePropertyChange("numberServed", oldNumberServed, getNumberServed()); + + if (!queue.isEmpty()) { + waitDelay("StartService", 0.0, HIGH); + } + + } + + /** + * @return the totalNumberServers + */ + public int getTotalNumberServers() { + return totalNumberServers; + } + + /** + * @param totalNumberServers the totalNumberServers to set + * @throws IllegalArgumentException if totalNumberServers ≤ 0 + */ + public void setTotalNumberServers(int totalNumberServers) { + if (totalNumberServers <= 0) { + throw new IllegalArgumentException("totalNumberServers must be > 0: " + totalNumberServers); + } + this.totalNumberServers = totalNumberServers; + } + + /** + * @return the serviceTimeGenerator + */ + public RandomVariate getServiceTimeGenerator() { + return serviceTimeGenerator; + } + + /** + * @param serviceTimeGenerator the serviceTimeGenerator to set + */ + public void setServiceTimeGenerator(RandomVariate serviceTimeGenerator) { + this.serviceTimeGenerator = serviceTimeGenerator; + } + + /** + * @return the numberAvailableServers + */ + public int getNumberAvailableServers() { + return numberAvailableServers; + } + + /** + * @return the queue + */ + public SortedSet<Entity> getQueue() { + return new TreeSet<>(queue); + } + + /** + * @return the numberServed + */ + public int getNumberServed() { + return numberServed; + } + + /** + * @return the delayInQueue + */ + public double getDelayInQueue() { + return delayInQueue; + } + + /** + * @return the timeInSystem + */ + public double getTimeInSystem() { + return timeInSystem; + } + +} diff --git a/MV3302ClassCode/src/mv3302/StoppedPartArrivalProcess.java b/MV3302ClassCode/src/mv3302/StoppedPartArrivalProcess.java new file mode 100644 index 0000000000..61ab12cebc --- /dev/null +++ b/MV3302ClassCode/src/mv3302/StoppedPartArrivalProcess.java @@ -0,0 +1,62 @@ +/* + * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license + * Click nbfs://nbhost/SystemFileSystem/Templates/Beans/Bean.java to edit this template + */ +package mv3302; + +import simkit.random.RandomVariate; + +/** + * + * @author dansl + */ +public final class StoppedPartArrivalProcess extends PartArrivalProcess { + + private RandomVariate interarrivalTimeGenerator; + + //int stopTime = 480; + /** + * Zero-argument constructor + */ + public StoppedPartArrivalProcess() { + super(); + } + + /** + * Instantiate with the given parameters + * + * @param interarrivalTimes Given inter arrival times + */ + public StoppedPartArrivalProcess(RandomVariate interarrivalTimeGenerator) { + setInterarrivalTimeGenerator(interarrivalTimeGenerator); + } + + @Override + public void doRun() { + waitDelay("StopArrivals", interarrivalTimeGenerator); + } + + /** + * Schedule next Arrival<br> + * Schedule Arrival(index) + */ + public void doStopArrivals() { + interrupt("Arrival"); + } + + /** + * @return the interarrivalTimeGenerator + */ + @Override + public RandomVariate getInterarrivalTimeGenerator() { + return interarrivalTimeGenerator; + } + + /** + * @param interarrivalTimeGenerator the interarrivalTimeGenerator to set + */ + @Override + public void setInterarrivalTimeGenerator(RandomVariate interarrivalTimeGenerator) { + this.interarrivalTimeGenerator = interarrivalTimeGenerator; + } +} diff --git a/MV3302ClassCode/src/mv3302/TransientStats.java b/MV3302ClassCode/src/mv3302/TransientStats.java new file mode 100644 index 0000000000..9d7bd1901b --- /dev/null +++ b/MV3302ClassCode/src/mv3302/TransientStats.java @@ -0,0 +1,53 @@ +package mv3302; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.ArrayList; +import java.util.List; +import simkit.stat.SimpleStatsTally; + +/** + * + * @author dansl + */ +public class TransientStats implements PropertyChangeListener { + + private final String state; + + protected List<SimpleStatsTally> data; + + protected int nextObs; + + public TransientStats(String state) { + this.state = state; + data = new ArrayList<>(); + nextObs = 0; + } + + + public void reset() { + nextObs = 0; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (!evt.getPropertyName().equals(state)) { + return; + } + if (nextObs >= getRawData().size()) { + data.add(new SimpleStatsTally("Data " + nextObs)); + } + if (evt.getNewValue() instanceof Number) { + data.get(nextObs).newObservation(((Number)evt.getNewValue()).doubleValue()); + } + nextObs += 1; + } + + /** + * @return the data + */ + public List<SimpleStatsTally> getRawData() { + return new ArrayList<>(data); + } + +} diff --git a/MV3302ClassCode/src/mv3302/run/RunSteadyStateAnalysis.java b/MV3302ClassCode/src/mv3302/run/RunSteadyStateAnalysis.java new file mode 100644 index 0000000000..ab7af7fd32 --- /dev/null +++ b/MV3302ClassCode/src/mv3302/run/RunSteadyStateAnalysis.java @@ -0,0 +1,77 @@ + +package mv3302.run; + + +import static java.lang.Math.sqrt; +import mv3302.PartArrivalProcess; +import mv3302.TransferLineComponent; +import simkit.Schedule; +import simkit.random.RandomVariate; +import simkit.random.RandomVariateFactory; +import simkit.stat.SimpleStatsTally; +import simkit.stat.StudentT; +import simkit.stat.TruncatingSimpleStatsTally; + +/** + * + * @author dansl + */ +public class RunSteadyStateAnalysis { + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + RandomVariate interarrivalTimeGenerator = RandomVariateFactory.getInstance( + "Exponential", 2.5); + PartArrivalProcess arrivalProcess = new PartArrivalProcess(interarrivalTimeGenerator); + + RandomVariate[] processingTimeGenerator = + {RandomVariateFactory.getInstance("Exponential", 2.4), RandomVariateFactory.getInstance("Gamma", 3.2, 3.3), RandomVariateFactory.getInstance("Uniform", 4.5, 6.7), RandomVariateFactory.getInstance("Exponential", 3.0)}; + + int[] totalNumberWorkstations = new int[4]; + totalNumberWorkstations[0] = 1; + totalNumberWorkstations[1] = 5; + totalNumberWorkstations[2] = 4; + totalNumberWorkstations[3] = 2; + + TransferLineComponent transferLineComponent = new TransferLineComponent(processingTimeGenerator, totalNumberWorkstations); + + arrivalProcess.addSimEventListener(transferLineComponent); + + int warmup = 1000; + int observations = 10000; + + SimpleStatsTally delayInQueueStat = new TruncatingSimpleStatsTally("delayInQueue", 2000); + + transferLineComponent.addPropertyChangeListener(delayInQueueStat); + + System.out.println(arrivalProcess); + System.out.println(transferLineComponent); + + SimpleStatsTally outerDelayInQueueStat = new SimpleStatsTally("outerDelayInQueue"); + + Schedule.stopOnEvent(warmup + observations, "Arrival"); + + int numberReplications = 15; + double alpha = 0.05; + + System.out.println("Avg Delay In Queue"); + for (int replication = 1; replication <= numberReplications; ++replication) { + + Schedule.reset(); + delayInQueueStat.reset(); + + Schedule.startSimulation(); + outerDelayInQueueStat.newObservation(delayInQueueStat.getMean()); + + System.out.printf("%d %.3f ± %.3f%n", + replication, + outerDelayInQueueStat.getMean(), + outerDelayInQueueStat.getStandardDeviation() + * StudentT.getQuantile(1.0 - 0.5 * alpha, outerDelayInQueueStat.getCount() - 1) / sqrt(outerDelayInQueueStat.getCount()) + ); + } + + } +} \ No newline at end of file diff --git a/MV3302ClassCode/src/mv3302/run/RunTransientAnalysis.java b/MV3302ClassCode/src/mv3302/run/RunTransientAnalysis.java new file mode 100644 index 0000000000..0d7fa00a6b --- /dev/null +++ b/MV3302ClassCode/src/mv3302/run/RunTransientAnalysis.java @@ -0,0 +1,72 @@ +package mv3302.run; + +import static java.lang.Math.sqrt; +import mv3302.StoppedPartArrivalProcess; +import mv3302.TransferLineComponent; +import mv3302.TransientStats; +import simkit.Schedule; +import simkit.random.RandomVariate; +import simkit.random.RandomVariateFactory; +import simkit.stat.SimpleStatsTally; +import simkit.stat.StudentT; + +/** + * + * @author dansl + */ +public class RunTransientAnalysis { + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + RandomVariate interarrivalTimeGenerator = RandomVariateFactory.getInstance( + "Exponential", 2.5); + StoppedPartArrivalProcess arrivalProcess = new StoppedPartArrivalProcess(interarrivalTimeGenerator); + + RandomVariate[] processingTimeGenerator + = {RandomVariateFactory.getInstance("Exponential", 2.4), RandomVariateFactory.getInstance("Gamma", 3.2, 3.3), RandomVariateFactory.getInstance("Uniform", 4.5, 6.7), RandomVariateFactory.getInstance("Exponential", 3.0)}; + + int[] totalNumberWorkstations = new int[4]; + totalNumberWorkstations[0] = 1; + totalNumberWorkstations[1] = 5; + totalNumberWorkstations[2] = 4; + totalNumberWorkstations[3] = 2; + + TransferLineComponent transferLineComponent = new TransferLineComponent(processingTimeGenerator, totalNumberWorkstations); + + arrivalProcess.addSimEventListener(transferLineComponent); + + TransientStats delayInQueueTransient = new TransientStats("delayInQueue"); + + SimpleStatsTally delayInQueueStat = new SimpleStatsTally("delayInQueue"); + + transferLineComponent.addPropertyChangeListener(delayInQueueTransient); + + System.out.println(arrivalProcess); + System.out.println(transferLineComponent); + + SimpleStatsTally outerDelayInQueueStat = new SimpleStatsTally("outerDelayInQueue"); + + int stopTime = 50; + double alpha = 0.05; + Schedule.stopOnEvent(stopTime, "Arrival"); + + System.out.println("Avg Delay In Queue"); + for (int replication = 1; replication <= stopTime; ++replication) { + Schedule.reset(); + delayInQueueTransient.reset(); + Schedule.startSimulation(); + + outerDelayInQueueStat.newObservation(delayInQueueStat.getMean()); + + System.out.printf("%d %.3f ± %.3f%n", + replication, + outerDelayInQueueStat.getMean(), + outerDelayInQueueStat.getStandardDeviation() + * StudentT.getQuantile(1.0 - 0.5 * alpha, outerDelayInQueueStat.getCount() - 1) / sqrt(outerDelayInQueueStat.getCount()) + ); + } + + } +} -- GitLab