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 &le; 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