/* * JaamSim Discrete Event Simulation * Copyright (C) 2014 Ausenco Engineering Canada 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 com.jaamsim.Graphics.DisplayEntity; import com.jaamsim.Samples.SampleInput; import com.jaamsim.input.Input; import com.jaamsim.input.Keyword; import com.jaamsim.input.Output; import com.jaamsim.input.UnitTypeInput; import com.jaamsim.units.Unit; import com.jaamsim.units.UserSpecifiedUnit; /** * Collects basic statistical information on the entities that are received. * @author Harry King * */ public class Statistics extends LinkedComponent { @Keyword(description = "The unit type for the variable whose statistics will be collected.", exampleList = {"DistanceUnit"}) private final UnitTypeInput unitType; @Keyword(description = "The variable for which statistics will be collected.", exampleList = {"'this.obj.attrib1'"}) private final SampleInput sampleValue; private double minValue; private double maxValue; private double totalValue; private double totalSquaredValue; private double lastValue; private double lastUpdateTime; private double totalTimeValue; private double totalSquaredTimeValue; private double firstSampleTime; { stateAssignment.setHidden(true); unitType = new UnitTypeInput("UnitType", "Key Inputs", UserSpecifiedUnit.class); unitType.setRequired(true); this.addInput(unitType); sampleValue = new SampleInput("SampleValue", "Key Inputs", null); sampleValue.setUnitType(UserSpecifiedUnit.class); sampleValue.setEntity(this); sampleValue.setRequired(true); this.addInput(sampleValue); } public Statistics() {} @Override public void updateForInput(Input<?> in) { super.updateForInput(in); if (in == unitType) { Class<? extends Unit> ut = unitType.getUnitType(); sampleValue.setUnitType(ut); return; } } @Override public void earlyInit() { super.earlyInit(); minValue = Double.POSITIVE_INFINITY; maxValue = Double.NEGATIVE_INFINITY; totalValue = 0.0; totalSquaredValue = 0.0; lastValue = 0.0; lastUpdateTime = 0.0; totalTimeValue = 0.0; totalSquaredTimeValue = 0.0; firstSampleTime = 0.0; } @Override public void addEntity(DisplayEntity ent) { super.addEntity(ent); double simTime = this.getSimTime(); // Update the statistics double val = sampleValue.getValue().getNextSample(simTime); minValue = Math.min(minValue, val); maxValue = Math.max(maxValue, val); totalValue += val; totalSquaredValue += val*val; // Calculate the time average if (this.getNumberAdded(simTime) == 1L) { firstSampleTime = simTime; } else { double weightedVal = lastValue * (simTime - lastUpdateTime); totalTimeValue += weightedVal; totalSquaredTimeValue += lastValue*weightedVal; } lastValue = val; lastUpdateTime = simTime; // Pass the entity to the next component this.sendToNextComponent(ent); } @Override public void clearStatistics() { super.clearStatistics(); minValue = Double.POSITIVE_INFINITY; maxValue = Double.NEGATIVE_INFINITY; totalValue = 0.0; totalSquaredValue = 0.0; totalTimeValue = 0.0; lastValue = 0.0; lastUpdateTime = 0.0; totalSquaredTimeValue = 0.0; firstSampleTime = 0.0; } @Override public Class<? extends Unit> getUserUnitType() { return unitType.getUnitType(); } // ****************************************************************************************************** // OUTPUT METHODS // ****************************************************************************************************** @Output(name = "SampleMinimum", description = "The smallest value that was recorded.", unitType = UserSpecifiedUnit.class, reportable = true, sequence = 0) public double getSampleMinimum(double simTime) { return minValue; } @Output(name = "SampleMaximum", description = "The largest value that was recorded.", unitType = UserSpecifiedUnit.class, reportable = true, sequence = 1) public double getSampleMaximum(double simTime) { return maxValue; } @Output(name = "SampleAverage", description = "The average of the values that were recorded.", unitType = UserSpecifiedUnit.class, reportable = true, sequence = 2) public double getSampleAverage(double simTime) { long num = this.getNumberAdded(simTime); if (num == 0L) return 0.0d; return totalValue/num; } @Output(name = "SampleStandardDeviation", description = "The standard deviation of the values that were recorded.", unitType = UserSpecifiedUnit.class, reportable = true, sequence = 3) public double getSampleStandardDeviation(double simTime) { long num = this.getNumberAdded(simTime); if (num == 0L) return 0.0d; double mean = totalValue/num; return Math.sqrt(totalSquaredValue/num - mean*mean); } @Output(name = "StandardDeviationOfTheMean", description = "The estimated standard deviation of the sample mean.", unitType = UserSpecifiedUnit.class, reportable = true, sequence = 4) public double getStandardDeviationOfTheMean(double simTime) { long num = this.getNumberAdded(simTime); if (num <= 1L) return 0.0d; return this.getSampleStandardDeviation(simTime)/Math.sqrt(num-1L); } @Output(name = "TimeAverage", description = "The average of the values recorded, weighted by the duration of each value.", unitType = UserSpecifiedUnit.class, reportable = true, sequence = 5) public double getTimeAverage(double simTime) { long num = this.getNumberAdded(simTime); if (num == 0L) return 0.0d; if (num == 1L) return lastValue; double dt = simTime - lastUpdateTime; return (totalTimeValue + lastValue*dt)/(simTime - firstSampleTime); } @Output(name = "TimeStandardDeviation", description = "The standard deviation of the values recorded, weighted by the duration of each value.", unitType = UserSpecifiedUnit.class, reportable = true, sequence = 6) public double getTimeStandardDeviation(double simTime) { long num = this.getNumberAdded(simTime); if (num <= 1L) return 0.0d; double mean = this.getTimeAverage(simTime); double dt = simTime - lastUpdateTime; double meanOfSquare = (totalSquaredTimeValue + lastValue*lastValue*dt)/(simTime - firstSampleTime); return Math.sqrt(meanOfSquare - mean*mean); } }