/* * JaamSim Discrete Event Simulation * Copyright (C) 2016 JaamSim Software Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.jaamsim.ProcessFlow; import java.util.ArrayList; import com.jaamsim.BasicObjects.DowntimeEntity; import com.jaamsim.Thresholds.Threshold; import com.jaamsim.Thresholds.ThresholdUser; import com.jaamsim.basicsim.Simulation; import com.jaamsim.input.EntityListInput; import com.jaamsim.input.Keyword; import com.jaamsim.input.Output; import com.jaamsim.states.DowntimeUser; import com.jaamsim.states.StateEntity; public abstract class StateUserEntity extends StateEntity implements ThresholdUser, DowntimeUser { @Keyword(description = "A list of thresholds that must be satisfied for the object to " + "operate. Operation is stopped immediately when one of the thresholds " + "closes. If a threshold closes part way though processing an entity, " + "the work is considered to be partly done and the remainder is " + "completed once the threshold re-opens.", exampleList = {"ExpressionThreshold1 TimeSeriesThreshold1 SignalThreshold1"}) protected final EntityListInput<Threshold> immediateThresholdList; @Keyword(description = "A list of thresholds that must be satisfied for the object to " + "operate. Operation is stopped immediately when one of the thresholds " + "closes. If a threshold closes part way though processing an entity, " + "the work is interrupted and the entity is released.", exampleList = {"ExpressionThreshold1 TimeSeriesThreshold1 SignalThreshold1"}) protected final EntityListInput<Threshold> immediateReleaseThresholdList; @Keyword(description = "A list of thresholds that must be satisfied for the object to " + "operate. If a threshold closes part way though processing an entity, " + "the remaining work is completed and the entity is released before the " + "object is closed.", exampleList = {"ExpressionThreshold1 TimeSeriesThreshold1 SignalThreshold1"}) protected final EntityListInput<Threshold> operatingThresholdList; @Keyword(description = "A list of DowntimeEntities representing planned maintenance that " + "must be performed immediately, interrupting any work underway at " + "present.", exampleList = {"DowntimeEntity1 DowntimeEntity2 DowntimeEntity3"}) protected final EntityListInput<DowntimeEntity> immediateMaintenanceList; @Keyword(description = "A list of DowntimeEntities representing planned maintenance that " + "must begin as soon as task underway at present is finished.", exampleList = {"DowntimeEntity1 DowntimeEntity2 DowntimeEntity3"}) protected final EntityListInput<DowntimeEntity> forcedMaintenanceList; @Keyword(description = "A list of DowntimeEntities representing planned maintenance that " + "can wait until task underway at present is finished and the queue " + "of tasks is empty.", exampleList = {"DowntimeEntity1 DowntimeEntity2 DowntimeEntity3"}) protected final EntityListInput<DowntimeEntity> opportunisticMaintenanceList; @Keyword(description = "A list of DowntimeEntities representing unplanned maintenance that " + "must be performed immediately, interrupting any work underway at " + "present.", exampleList = {"DowntimeEntity1 DowntimeEntity2 DowntimeEntity3"}) protected final EntityListInput<DowntimeEntity> immediateBreakdownList; @Keyword(description = "A list of DowntimeEntities representing unplanned maintenance that " + "must begin as soon as task underway at present is finished.", exampleList = {"DowntimeEntity1 DowntimeEntity2 DowntimeEntity3"}) protected final EntityListInput<DowntimeEntity> forcedBreakdownList; @Keyword(description = "A list of DowntimeEntities representing unplanned maintenance that " + "can wait until task underway at present is finished and the queue " + "of tasks is empty.", exampleList = {"DowntimeEntity1 DowntimeEntity2 DowntimeEntity3"}) protected final EntityListInput<DowntimeEntity> opportunisticBreakdownList; private boolean busy; // indicates that work is being performed { immediateThresholdList = new EntityListInput<>(Threshold.class, "ImmediateThresholdList", "Thresholds", new ArrayList<Threshold>()); this.addInput(immediateThresholdList); immediateReleaseThresholdList = new EntityListInput<>(Threshold.class, "ImmediateReleaseThresholdList", "Thresholds", new ArrayList<Threshold>()); this.addInput(immediateReleaseThresholdList); operatingThresholdList = new EntityListInput<>(Threshold.class, "OperatingThresholdList", "Thresholds", new ArrayList<Threshold>()); this.addInput(operatingThresholdList); immediateMaintenanceList = new EntityListInput<>(DowntimeEntity.class, "ImmediateMaintenanceList", "Maintenance", new ArrayList<DowntimeEntity>()); this.addInput(immediateMaintenanceList); forcedMaintenanceList = new EntityListInput<>(DowntimeEntity.class, "ForcedMaintenanceList", "Maintenance", new ArrayList<DowntimeEntity>()); this.addInput(forcedMaintenanceList); opportunisticMaintenanceList = new EntityListInput<>(DowntimeEntity.class, "OpportunisticMaintenanceList", "Maintenance", new ArrayList<DowntimeEntity>()); this.addInput(opportunisticMaintenanceList); immediateBreakdownList = new EntityListInput<>(DowntimeEntity.class, "ImmediateBreakdownList", "Maintenance", new ArrayList<DowntimeEntity>()); this.addInput(immediateBreakdownList); forcedBreakdownList = new EntityListInput<>(DowntimeEntity.class, "ForcedBreakdownList", "Maintenance", new ArrayList<DowntimeEntity>()); this.addInput(forcedBreakdownList); opportunisticBreakdownList = new EntityListInput<>(DowntimeEntity.class, "OpportunisticBreakdownList", "Maintenance", new ArrayList<DowntimeEntity>()); this.addInput(opportunisticBreakdownList); } public StateUserEntity() {} @Override public void earlyInit() { super.earlyInit(); busy = false; this.addState("Idle"); this.addState("Working"); this.addState("Stopped"); this.addState("Maintenance"); this.addState("Breakdown"); } @Override public boolean isValidState(String state) { return true; } // ******************************************************************************************** // THRESHOLDS // ******************************************************************************************** @Override public ArrayList<Threshold> getThresholds() { ArrayList<Threshold> ret = new ArrayList<>(operatingThresholdList.getValue()); ret.addAll(immediateThresholdList.getValue()); ret.addAll(immediateReleaseThresholdList.getValue()); return ret; } public boolean isImmediateThresholdClosure() { for (Threshold thresh : immediateThresholdList.getValue()) { if (!thresh.isOpen()) return true; } return false; } public boolean isImmediateReleaseThresholdClosure() { for (Threshold thresh : immediateReleaseThresholdList.getValue()) { if (!thresh.isOpen()) return true; } return false; } // ******************************************************************************************** // PRESENT STATE // ******************************************************************************************** protected void setBusy(boolean bool) { busy = bool; } public final boolean isBusy() { return busy; } /** * Tests whether all the thresholds are open. * @return true if all the thresholds are open. */ public final boolean isOpen() { for (Threshold thr : immediateThresholdList.getValue()) { if (!thr.isOpen()) return false; } for (Threshold thr : immediateReleaseThresholdList.getValue()) { if (!thr.isOpen()) return false; } for (Threshold thr : operatingThresholdList.getValue()) { if (!thr.isOpen()) return false; } return true; } public boolean isMaintenance() { for (DowntimeEntity de : immediateMaintenanceList.getValue()) { if (de.isDown()) return true; } for (DowntimeEntity de : forcedMaintenanceList.getValue()) { if (de.isDown()) return true; } for (DowntimeEntity de : opportunisticMaintenanceList.getValue()) { if (de.isDown()) return true; } return false; } public boolean isBreakdown() { for (DowntimeEntity de : immediateBreakdownList.getValue()) { if (de.isDown()) return true; } for (DowntimeEntity de : forcedBreakdownList.getValue()) { if (de.isDown()) return true; } for (DowntimeEntity de : opportunisticBreakdownList.getValue()) { if (de.isDown()) return true; } return false; } public boolean isAvailable() { return isOpen() && !isMaintenance() && !isBreakdown(); } /** * Tests whether the entity is available for work. * <p> * There are three mutually exclusive states: Busy, Idle, and UnableToWork. The UnableToWork * condition is divided into three separate states: Maintenance, Breakdown, and Stopped. * @return true if the LinkedService is available for work */ public boolean isIdle() { return !isBusy() && isAvailable(); } /** * Tests whether something is preventing work from being performed. * <p> * There are three mutually exclusive states: Busy, Idle, and UnableToWork. The UnableToWork * condition is divided into three separate states: Maintenance, Breakdown, and Stopped. * @return true if something is preventing work from being performed */ public boolean isUnableToWork() { return !isBusy() && !isAvailable(); } @Override public void setPresentState() { // Working (Busy) if (this.isBusy()) { this.setPresentState("Working"); return; } // Not working because of maintenance or a closure (UnableToWork) if (this.isMaintenance()) { this.setPresentState("Maintenance"); return; } if (this.isBreakdown()) { this.setPresentState("Breakdown"); return; } if (!this.isOpen()) { this.setPresentState("Stopped"); return; } // Not working because there is nothing to do (Idle) this.setPresentState("Idle"); return; } // ******************************************************************************************** // MAINTENANCE AND BREAKDOWNS // ******************************************************************************************** @Override public ArrayList<DowntimeEntity> getMaintenanceEntities() { ArrayList<DowntimeEntity> ret = new ArrayList<>(); ret.addAll(immediateMaintenanceList.getValue()); ret.addAll(forcedMaintenanceList.getValue()); ret.addAll(opportunisticMaintenanceList.getValue()); return ret; } @Override public ArrayList<DowntimeEntity> getBreakdownEntities() { ArrayList<DowntimeEntity> ret = new ArrayList<>(); ret.addAll(immediateBreakdownList.getValue()); ret.addAll(forcedBreakdownList.getValue()); ret.addAll(opportunisticBreakdownList.getValue()); return ret; } public boolean isImmediateDowntime(DowntimeEntity down) { return immediateMaintenanceList.getValue().contains(down) || immediateBreakdownList.getValue().contains(down); } public boolean isForcedDowntime(DowntimeEntity down) { return forcedMaintenanceList.getValue().contains(down) || forcedBreakdownList.getValue().contains(down); } public boolean isOpportunisticDowntime(DowntimeEntity down) { return opportunisticMaintenanceList.getValue().contains(down) || opportunisticBreakdownList.getValue().contains(down); } // ******************************************************************************************** // OUTPUTS // ******************************************************************************************** @Output(name = "Open", description = "Returns TRUE if all the thresholds specified by the OperatingThresholdList, " + "ImmediateThresholdList, and ImmediateReleaseThresholdList keywords are open.", sequence = 1) public boolean getOpen(double simTime) { return isOpen(); } @Output(name = "Working", description = "Returns TRUE if work is being performed.", sequence = 2) public boolean isBusy(double simTime) { return isBusy(); } @Output(name = "Maintenance", description = "Returns TRUE if maintenance is being performed.", sequence = 3) public boolean isMaintenance(double simTime) { return isMaintenance(); } @Output(name = "Breakdown", description = "Returns TRUE if a breakdown is being repaired.", sequence = 4) public boolean isBreakdown(double simTime) { return isBreakdown(); } @Output(name = "Utilisation", description = "The fraction of calendar time (excluding the initialisation period) that " + "this object is in the Working state.", reportable = true, sequence = 5) public double getUtilisation(double simTime) { double total = simTime; if (simTime > Simulation.getInitializationTime()) total -= Simulation.getInitializationTime(); double working = this.getTimeInState(simTime, "Working"); return working/total; } @Output(name = "Commitment", description = "The fraction of calendar time (excluding the initialisation period) that " + "this object is in any state other than Idle.", reportable = true, sequence = 6) public double getCommitment(double simTime) { double total = simTime; if (simTime > Simulation.getInitializationTime()) total -= Simulation.getInitializationTime(); double idle = this.getTimeInState(simTime, "Idle"); return 1.0d - idle/total; } @Output(name = "Availability", description = "The fraction of calendar time (excluding the initialisation period) that " + "this object is in any state other than Maintenance or Breakdown.", reportable = true, sequence = 7) public double getAvailability(double simTime) { double total = simTime; if (simTime > Simulation.getInitializationTime()) total -= Simulation.getInitializationTime(); double maintenance = this.getTimeInState(simTime, "Maintenance"); double breakdown = this.getTimeInState(simTime, "Breakdown"); return 1.0d - (maintenance + breakdown)/total; } @Output(name = "Reliability", description = "The ratio of Working time to the sum of Working time and Breakdown time. " + "All times exclude the initialisation period.", reportable = true, sequence = 8) public double getReliability(double simTime) { double working = this.getTimeInState(simTime, "Working"); double breakdown = this.getTimeInState(simTime, "Breakdown"); return working / (working + breakdown); } }