package SimkitOpenDis7Examples; import edu.nps.moves.dis7.enumerations.DisPduType; import edu.nps.moves.dis7.pdus.EntityStatePdu; import edu.nps.moves.dis7.utilities.DisChannel; import edu.nps.moves.dis7.utilities.PduFactory; import java.util.SortedSet; import java.util.TreeSet; import simkit.Priority; import simkit.SimEntityBase; /** * Add DIS outputs to TwoCraneBerths simkit simulation * @see TwoCraneBerths * @see SimkitOpenDis7Examples.run.RunTwoCranesBerth * @see SimkitOpenDis7Examples.run.RunTwoCranesBerthOpenDis7 * @see <a href="run/RunTwoCranesBerthOpenDis7Log.txt">RunTwoCranesBerthOpenDis7Log.txt</a> * @see <a href="TwoCraneBerthsAssignment05.docx">TwoCraneBerthsAssignment05.docx</a> * @see <a href="TwoCraneBerthsAssignment05Solution.docx">TwoCraneBerthsAssignment05Solution.docx</a> * @author abuss@nps.edu@nps.edu * @author brutzman@nps.edu */ public class TwoCraneBerthsOpenDis7 extends SimEntityBase { private final DisChannel disChannel = new DisChannel(); /** * Queue of Ships waiting to go into the berth */ protected SortedSet<Ship> queue; /** * Contains 0, 1, or two Ships being unloaded */ protected SortedSet<Ship> berth; /** * Time in the system for each Ship */ protected double timeInSystem; /** * Delay in the queue for each Ship */ protected double delayInQueue; /** * Instantiate queue and berth containers */ public TwoCraneBerthsOpenDis7() { this.queue = new TreeSet<>(); this.berth = new TreeSet<>(); } /** * Clear queue and berth containers */ @Override public void reset() { super.reset(); queue.clear(); berth.clear(); timeInSystem = Double.NaN; delayInQueue = Double.NaN; } /** * Only PropertyChangeEvents */ public void doRun() { firePropertyChange("queue", getQueue()); firePropertyChange("berth", getBerth()); firePropertyChange("timeInSystem", getTimeInSystem()); firePropertyChange("delayInQueue", getDelayInQueue()); } /** * Add the given Ship to queue<br> * If berths is empty, schedule StartUnloadingTwoCranes<br> * If berths has 1 Ship, schedule SwitchToOneCrane * * @param ship Given Ship arriving to harbor */ public void doArrival(Ship ship) { ship.stampTime(); SortedSet<Ship> oldQueue = getQueue(); queue.add(ship); firePropertyChange("queue", oldQueue, getQueue()); if (berth.isEmpty()) { waitDelay("StartUnloadingTwoCranes", 0.0, Priority.HIGH); } if (berth.size() == 1) { waitDelay("SwitchToOneCrane", 0.0); } } /** * Remove the first Ship from queue<br> * DelayInQueue is elapsedTime of that Ship<br> * Add the ship to berth container<br> * Schedule EndUnloadingTwoCranes at half the remaining time */ public void doStartUnloadingTwoCranes() { SortedSet<Ship> oldQueue = getQueue(); Ship ship = queue.first(); queue.remove(ship); firePropertyChange("queue", oldQueue, getQueue()); delayInQueue = ship.getElapsedTime(); firePropertyChange("delayInQueue", getDelayInQueue()); ship.stampTime(); SortedSet<Ship> oldBerth = getBerth(); berth.add(ship); firePropertyChange("berth", oldBerth, getBerth()); waitDelay("EndUnloadingTwoCranes", 0.5 * ship.getRemainingUnloadingTime()); } /** * Remove the (one) Ship from berth<br> * TimeInSystem is the age of the Ship */ public void doEndUnloadingTwoCranes() { SortedSet<Ship> oldBerth = getBerth(); Ship ship = berth.first(); berth.remove(ship); firePropertyChange("berth", oldBerth, getBerth()); timeInSystem = ship.getAge(); firePropertyChange("timeInSystem", getTimeInSystem()); } /** * This event is when a Ship arrives to find only one other Ship being * unloaded.<br> * Credit the ship in the berth with work at a rate of 2 (since 2 cranes * have been unloading it<br> * Interrupt EndUnloadingTwoCranes<br> * Schedule EndUnloadingOneCrane with the Ship already in the berth<br> * Schedule StartUnloadingOneCrane */ public void doSwitchToOneCrane() { Ship ship = berth.first(); ship.work(2.0); ship.stampTime(); interrupt("EndUnloadingTwoCranes"); waitDelay("EndUnloadingOneCrane", ship.getRemainingUnloadingTime(), ship); waitDelay("StartUnloadingOneCrane", 0.0, Priority.HIGH); } /** * Pop the first Ship from the queue<br> * delayInQueue is elapsedTime (from Arrival event)<br> * Add that Ship to berth container<br> * Schedule EndUnloadingOneCrane with that Ship */ public void doStartUnloadingOneCrane() { SortedSet<Ship> oldQueue = getQueue(); Ship ship = queue.first(); // TODO rename ship queue queue.remove(ship); firePropertyChange("queue", oldQueue, getQueue()); delayInQueue = ship.getElapsedTime(); firePropertyChange("delayInQueue", getDelayInQueue()); ship.stampTime(); SortedSet<Ship> oldBerth = getBerth(); berth.add(ship); firePropertyChange("berth", oldBerth, getBerth()); performCraneUnloadOperations( 10, // numberOfContainers 0.0 // initial position ); // TODO indicate berth waitDelay("EndUnloadingOneCrane", ship.getRemainingUnloadingTime(), ship); } PduFactory pduFactory = new PduFactory(); public void performCraneUnloadOperations( // which crane // which berth int numberOfContainers, double positionOfCrane // lenthOfCrane ) { double craneLinearSpeed = 1.0; // m/sec double craneRotationRate = 10.0; // degrees/second double containerHookupTime = 60.0; // seconds average double containerDetachTime = 30.0; // seconds average EntityStatePdu espduCrane = (EntityStatePdu) pduFactory.createPdu(DisPduType.ENTITY_STATE); // 1. Crane at head of pier, operatior present, boom elevated vertically in stow postion // espduCrane1.setPosition 0 0 0 // 2, Ship arrives, tug departs // shop PDU here or assum it happened earlier // 3. Crane moves to position of ship espduCrane.setEntityLocation(positionOfCrane, 0.0, 0.0); // TODO compute travel time // update: travel to positionOfCrane by craneLinearSpeed // 4. repeat until done: Crane rotates, lift container, rotates, lower container for (int containerIndex = 1; containerIndex <= numberOfContainers; containerIndex++) { // perform one operation espduCrane.setEntityOrientation(0, 0, 0); disChannel.sendSinglePdu(espduCrane); espduCrane.setEntityOrientation(0, 0, 0); double rotationDelay = 90.0 / craneRotationRate; disChannel.sendCommentPdu(disChannel.COMMENTPDU_NARRATIVE, "Hooking up Container " + containerIndex + " to crane"); disChannel.sendSinglePduDelayed(containerHookupTime, espduCrane); disChannel.sendCommentPdu(disChannel.COMMENTPDU_NARRATIVE, "Container hooked up"); disChannel.sendSinglePduDelayed(containerHookupTime, espduCrane); espduCrane.setEntityOrientation(90, 0, 0); disChannel.sendSinglePduDelayed(rotationDelay, espduCrane); // unhook // rotate back // if this container is special, meaning on watchlist, report it } // 4. Crane stows boom in vertical position // espcudCrnet orientation // 5. Crane returns to head of pier // update: travel from positionOfCrane to head by craneLinearSpeed espduCrane.setEntityLocation(positionOfCrane, 0.0, 0.0); disChannel.sendSinglePdu(espduCrane); } /** * Remove given Ship from berth<br> * If Ships in queue, schedule StartUnloadingOneCrane<br> * If queue is empty, schedule SwitchToTwoCranes<br> * timeInSystem is age of Ship * * @param ship Given Ship */ public void doEndUnloadingOneCrane(Ship ship) { SortedSet<Ship> oldBerth = getBerth(); berth.remove(ship); firePropertyChange("berth", oldBerth, getBerth()); if (queue.size() > 0) { waitDelay("StartUnloadingOneCrane", 0.0, Priority.HIGH); } if (queue.isEmpty() && berth.size() == 1) { waitDelay("SwitchToTwoCranes", 0.0); } timeInSystem = ship.getAge(); firePropertyChange("timeInSystem", getTimeInSystem()); } /** * Credit the work of the remaining Ship in berth at unit rate<br> * Interrupt EndUnloadingOneCrane<br> * Schedule EndUnloadingTwoCranes at double the rate (i.e., half the remaining time) */ public void doSwitchToTwoCranes() { Ship ship = berth.first(); ship.work(1.0); ship.stampTime(); interrupt("EndUnloadingOneCrane", ship); waitDelay("EndUnloadingTwoCranes", 0.5 * ship.getRemainingUnloadingTime()); } /** * Get tree of sorted Ship set queue * @return Shallow copy of queue */ public SortedSet<Ship> getQueue() { return new TreeSet<>(queue); } /** * Get tree of sorted Ship set berths * @return Shallow copy of berth */ public SortedSet<Ship> getBerth() { return new TreeSet<>(berth); } /** * accessor method to get a state variable * @return The timeInSystem */ public double getTimeInSystem() { return timeInSystem; } /** * accessor method to get a state variable * @return The delayInQueue */ public double getDelayInQueue() { return delayInQueue; } }