diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..4ef2717
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+
+*.log
diff --git a/.project b/.project
new file mode 100644
index 0000000..22029d3
--- /dev/null
+++ b/.project
@@ -0,0 +1,11 @@
+
+
This information is part of the Business Simulation Library (BSL).
+This package contains some common constants that are considered useful for System Dynamics modeling and simulation.
+It is generally advisable to set up models in SIunits of time so that they will be compatibale with models from other domains. To enter and display times and rates in a convenient fashion the displayUnit
attribute should be used. This should be conveniently handled by Modelica tools which most often will allow to make such a choice by drop-down menu.
In that sense, the constants timeBaseUnits
and timeBaseConversionFactors
are usually not needed.
+Tutorial.UnitsInBusinessSimulations, +TimeConversion
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y is given as the absolute value of the input u.
+The function abs()
is used to compute the absolute value so no event will be generated.
This information is part of the Business Simulation Library (BSL).
+The Real output y is the value of the accumulation function at any time t in the simulation given the variable rate of interest according to input u. By definition the accumulation function will give the factor to determing the future value A(t) for an investment with a present value A(0) of 1 monetary units:
+A(t) = A(0) · a(t) = 1 · a(t)
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "a(t)", fontName = "Lato Black", textStyle = {TextStyle.Bold, TextStyle.Italic})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end AccumulationFunction; diff --git a/BusinessSimulation/Converters/Add_2.mo b/BusinessSimulation/Converters/Add_2.mo new file mode 100644 index 0000000..3b06409 --- /dev/null +++ b/BusinessSimulation/Converters/Add_2.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Converters; + +block Add_2 "Sum of two inputs" + extends Interfaces.PartialConverters.SI2SO; +equation + y = u1 + u2; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is obtained as the sum of the inputs u1 and u2.
+This information is part of the Business Simulation Library (BSL).
+The output y is calculated as the sum of the inputs u1, u2, and u3.
+This information is part of the Business Simulation Library (BSL).
+The input u will be clipped to make sure that it is within the interval [minValue, maxValue]
before it is given as output y. Alternatively, variable inputs can be used to set the limits (hasConstantLimits = false
).
The component internally uses the →Limiter and the →VariableLimiter from the Modelica Standard Library.
+Functions.clip, Vector.Clip, ClipProcessTime, ZeroIfNegative
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-36.812, -12}, {36.812, 12}}, textString = "CLIP", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Clip; diff --git a/BusinessSimulation/Converters/ClipProcessTime.mo b/BusinessSimulation/Converters/ClipProcessTime.mo new file mode 100644 index 0000000..a30bceb --- /dev/null +++ b/BusinessSimulation/Converters/ClipProcessTime.mo @@ -0,0 +1,26 @@ +within BusinessSimulation.Converters; + +block ClipProcessTime "Limit any time input to be no smaller than dt" + extends Interfaces.PartialConverters.SISO(redeclare replaceable type OutputType = Units.Time); + parameter Boolean strict = true "= true, if strict limits with noEvent(..)" annotation(Evaluate = true, Dialog(tab = "Advanced")); +protected + outer ModelSettings modelSettings; +equation + if strict then + y = smooth(0, noEvent(if u < modelSettings.dt then modelSettings.dt else u)); + else + y = smooth(0, if u < modelSettings.dt then modelSettings.dt else u); + end if; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The global parameter modelSettings.dt
gives the smallest possible average duration for any explicitly modeled process within a model (e.g. the shortest possible delay time). The time input u (usually a duration) will thus be clipped so that the output y will never be smaller than dt
.
In the default setting (strict = true
) in the Advanced tab no events will be generated:
if strict then + y = smooth(0, noEvent(if u < modelSettings.dt then modelSettings.dt else u)); + else + y = smooth(0, if u < modelSettings.dt then modelSettings.dt else u); + end if;
This information is part of the Business Simulation Library (BSL).
+The parameter value
is used to set the continous output y making it a constant-valued signal.
ConstantConverterRate, ConstantConverterTime, ConstantConverterBoolean
", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-28.253, -28.253}, {28.253, 28.253}}), Line(visible = true, rotation = -270, points = {{0, 40}, {0, -40}}, color = {0, 0, 128}, thickness = 3), Text(visible = true, origin = {0, 60}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-20, -20}, {20, 20}}), Line(visible = true, origin = {0, -0.205}, rotation = -810, points = {{-30, 0}, {30, 0}}, color = {0, 0, 128}, thickness = 5), Text(visible = true, origin = {-50, 0}, textColor = {128, 0, 128}, extent = {{-44.917, -32.251}, {44.917, 32.251}}, textString = "%value", fontSize = 30, fontName = "Arial"), Text(visible = true, origin = {0, -56.852}, textColor = {128, 0, 128}, extent = {{-141.113, -29.508}, {141.113, 29.508}}, textString = "%name", fontName = "Arial")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConstantConverter; diff --git a/BusinessSimulation/Converters/ConstantConverterRate.mo b/BusinessSimulation/Converters/ConstantConverterRate.mo new file mode 100644 index 0000000..32d63ee --- /dev/null +++ b/BusinessSimulation/Converters/ConstantConverterRate.mo @@ -0,0 +1,31 @@ +within BusinessSimulation.Converters; + +block ConstantConverterRate "A constant rate is turned into a constant-valued signal" + import BusinessSimulation.Units.{Rate,Dimensionless}; + import BusinessSimulation.Types.TimeBases; + extends Icons.ConstantConverter; + extends Interfaces.Basics.OutputTypeChoice_Rate; + replaceable type ValueType = Types.Reals "Basic type for the quantity that is transported per unit of time"; + RealOutput y "Constant output signal" annotation(Placement(visible = true, transformation(origin = {161.795, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter ValueType value "Constant rate given in unit and displayUnit pertaining to ValueType per time base"; + parameter String timeBaseString = "second" "Time base of the rate entered (default = second)" annotation(choices(choice = "second", choice = "minute", choice = "hour", choice = "day", choice = "week", choice = "month", choice = "quarter", choice = "year")); +protected + parameter TimeBases timeBase = Functions.stringToTimeBase(timeBaseString) "Element of the enumeration TimeBases corresponding to the timeBase given as string" annotation(Dialog(tab = "Initialization", enable = false)); + ConstantConverter rateInTimeBase(value = value) annotation(Placement(visible = true, transformation(origin = {0, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + RateConversion convertRate(timeBaseA = timeBase, timeBaseB = TimeBases.seconds) "Convert the rate input to a rate per seconds" annotation(Placement(visible = true, transformation(origin = {70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(convertRate.y, y) annotation(Line(visible = true, origin = {119.897, 0}, points = {{-41.897, 0}, {41.897, -0}}, color = {1, 37, 163})); + connect(rateInTimeBase.y, convertRate.u) annotation(Line(visible = true, origin = {34, 0}, points = {{-28, -0}, {28, 0}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The parameter value
is used to set the continous output y making it a constant-valued signal. The output will always give rates per second, but rates can be entered in non-SI-units of time using the parameter timeBaseString
.
ValueType
is chosen to be Types.Reals
so that the entered rate will be a fractional rate (1 per unit of time
). A different choice for ValueType
may give more convenience: Selecting ValueType = Amount
allows to use `displayUnit = \"thousand\"` and we can enter value = 1
and timeBaseString = \"year\"
to come up with a rate of 1 thousand per year
nicely converted internally into an equivalent rate per second.ValueType
to select say a basic physical quantity like energy (not EnergyFlowRate!). With value = 1000
, displayUnit = \"kW.h\"
, and timeBaseString = \"year\"
we will thus obtain a rate of 1000 kw.H per year
that is internally converted into SI-units of 114.155 J/s
.OutputType
(default = Rate
) and ValueType
. The value
entered will have unit = ValueType.unit/s
and the selected OutputType
should be set to make sure that y.unit
reflects this: In the energy example above, the user should have selected OutputType = EnergyFlowRate
to have units for input and output match.ConstantConverter, ConstantConverterTime
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-28.253, -28.253}, {28.253, 28.253}}), Line(visible = true, rotation = -270, points = {{0, 40}, {0, -40}}, color = {0, 0, 128}, thickness = 3), Text(visible = true, origin = {0, 60}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value per %timeBaseString", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-20, -20}, {20, 20}}), Line(visible = true, origin = {0, -0.205}, rotation = -810, points = {{-30, 0}, {30, 0}}, color = {0, 0, 128}, thickness = 5), Text(visible = true, origin = {-50, 0}, textColor = {128, 0, 128}, extent = {{-44.917, -32.251}, {44.917, 32.251}}, textString = "%value", fontSize = 30, fontName = "Arial"), Text(visible = true, origin = {0, -56.852}, textColor = {128, 0, 128}, extent = {{-141.113, -29.508}, {141.113, 29.508}}, textString = "%name", fontName = "Arial")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConstantConverterRate; diff --git a/BusinessSimulation/Converters/ConstantConverterTime.mo b/BusinessSimulation/Converters/ConstantConverterTime.mo new file mode 100644 index 0000000..2c26f51 --- /dev/null +++ b/BusinessSimulation/Converters/ConstantConverterTime.mo @@ -0,0 +1,16 @@ +within BusinessSimulation.Converters; + +block ConstantConverterTime "A constant time value is turned into a constant signal" + import BusinessSimulation.Units.Time; + extends Icons.ConstantConverter; + extends Interfaces.Basics.OutputTypeChoice_Time; + RealOutput y "Constant value of time in the time base given" annotation(Placement(visible = true, transformation(origin = {161.795, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter OutputType value "Constant value of time"; +equation + y = value; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The parameter value
is used to set the continous output y making it a constant-valued signal. The output will always give times in seconds [s]
, but values can be entered in non-SI-units of time using displayUnit
.
ConstantConverter, ConstantConverterRate
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-28.253, -28.253}, {28.253, 28.253}}), Line(visible = true, rotation = -270, points = {{0, 40}, {0, -40}}, color = {0, 0, 128}, thickness = 3), Text(visible = true, origin = {0, 60}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-20, -20}, {20, 20}}), Line(visible = true, origin = {0, -0.205}, rotation = -810, points = {{-30, 0}, {30, 0}}, color = {0, 0, 128}, thickness = 5), Text(visible = true, origin = {-50, 0}, textColor = {128, 0, 128}, extent = {{-44.917, -32.251}, {44.917, 32.251}}, textString = "%value", fontSize = 30, fontName = "Arial"), Text(visible = true, origin = {0, -56.852}, textColor = {128, 0, 128}, extent = {{-141.113, -29.508}, {141.113, 29.508}}, textString = "%name", fontName = "Arial")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConstantConverterTime; diff --git a/BusinessSimulation/Converters/DiscreteDelay/DelayFixed.mo b/BusinessSimulation/Converters/DiscreteDelay/DelayFixed.mo new file mode 100644 index 0000000..d242adb --- /dev/null +++ b/BusinessSimulation/Converters/DiscreteDelay/DelayFixed.mo @@ -0,0 +1,83 @@ +within BusinessSimulation.Converters.DiscreteDelay; + +model DelayFixed "Pipeline information delay without awareness" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.Time; + import BusinessSimulation.Constants.inf; + extends Interfaces.PartialConverters.SmoothSISO; + Interfaces.Connectors.RealInput u_history if hasExogenousHistory "Historical input to be used in an initial period (up to maximumDelaytime)" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 50}, extent = {{-10, 10}, {10, -10}}, rotation = -810))); + Interfaces.Connectors.RealOutput y_lookupTime if hasExogenousHistory "Time for looking up historical input" annotation(Placement(visible = true, transformation(origin = {160, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 30}, extent = {{10, -10}, {-10, 10}}, rotation = -360))); + Interfaces.Connectors.RealInput u_delayTime if not hasConstantDelayTime "Delay time input" annotation(Placement(visible = true, transformation(origin = {-145, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 50}, extent = {{-10, 10}, {10, -10}}, rotation = -810))); + parameter Time delayTime(min = modelSettings.dt) = 1 "Constant delay time (optional)" annotation(Dialog(enable = hasConstantDelayTime)); + parameter Time maximumDelayTime = 50 "Maximal value allowed for delay time (needed for variable delay time)" annotation(Evaluate = true, Dialog(enable = not hasConstantDelayTime)); + parameter Real initialValue = 0 "Initial constant output, if no exogenous history is given" annotation(Dialog(enable = not init == InitializationOptions.SteadyState and not hasExogenousHistory)); + parameter Boolean hasConstantDelayTime = true "= true, if the delay time is given by the parameter 'delayTime'" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasExogenousHistory = false "= true, if the input 'u_history' gives the output for an initial period, otherwise the initial output will remain constant until delayTime is reached" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter InitializationOptions init = modelSettings.init "Provide InitializationOptions (Free, FixedValue, SteadyState)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + outer ModelSettings modelSettings; +protected + parameter Real initialOutput(start = initialValue, fixed = false) "Constant output if no exogenous history is provided; initialOutput.start = initialValue" annotation(Dialog(tab = "Initialization", enable = false)); + parameter Time initialDelayTime(fixed = false) "Delay time at initial time" annotation(Dialog(tab = "Initialization", enable = false)); + Add_2 historyHorizon "The modelStartTime plus the actual delayTime" annotation(Placement(visible = true, transformation(origin = {10, 55}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + ConstantConverterTime parStartTime(value = modelSettings.modelStartTime) "The model's start time" annotation(Placement(visible = true, transformation(origin = {-32.804, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + ConstantConverterTime parDelayTime(value = delayTime) if hasConstantDelayTime "Constant delay time (optional)" annotation(Placement(visible = true, transformation(origin = {-130, 40}, extent = {{10, 10}, {-10, -10}}, rotation = 180))); + ConstantConverter parInitialOutput(value = initialOutput) if not hasExogenousHistory "Initial output if not history is given" annotation(Placement(visible = true, transformation(origin = {-120, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Clip clippedDelayTime(minValue = modelSettings.dt, maxValue = if not hasConstantDelayTime then maximumDelayTime else inf) "DelayTime has to be in the interval (dt, maximumDelayTime)" annotation(Placement(visible = true, transformation(origin = {-85, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableDelay delayedInput(delayMax = maximumDelayTime) if not hasConstantDelayTime annotation(Placement(visible = true, transformation(origin = {-10, -30}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + PassThrough history annotation(Placement(visible = true, transformation(origin = {-50, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + InformationSources.TimeInput clock "Provide time since start time (=0)" annotation(Placement(visible = true, transformation(origin = {65, 95}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Logical.Less historyNeededQ "Is historical trajectory needed for output?" annotation(Placement(visible = true, transformation(origin = {60, 30}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Logical.Switch switchedOutput "Either return historical value or delayed input" annotation(Placement(visible = true, transformation(origin = {60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.FixedDelay delayedInputConstant(delayTime = delayTime) if hasConstantDelayTime "Delayed input with constant delay time" annotation(Placement(visible = true, transformation(origin = {-10, 10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Gap lookupTime if hasExogenousHistory "Time that needs to be looked up in historical input data" annotation(Placement(visible = true, transformation(origin = {90, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +initial equation + initialDelayTime = clippedDelayTime.y; + if init == InitializationOptions.FixedValue then + initialOutput = initialValue; + elseif init == InitializationOptions.SteadyState then + initialOutput = u; + end if; +equation + connect(u_delayTime, clippedDelayTime.u) annotation(Line(visible = true, origin = {-102, 50}, points = {{-43, 10}, {2, 10}, {2, 10}, {9, 10}}, color = {1, 37, 163})); + connect(u_history, history.u) annotation(Line(visible = true, origin = {-85.75, -50}, points = {{-59.25, 10}, {5.75, 10}, {5.75, -10}, {27.75, -10}}, color = {1, 37, 163})); + connect(parInitialOutput.y, history.u) annotation(Line(visible = true, origin = {-83.25, -70}, points = {{-31.75, -10}, {3.25, -10}, {3.25, 10}, {25.25, 10}}, color = {1, 37, 163})); + connect(clock.y, historyNeededQ.u1) annotation(Line(visible = true, origin = {65, 62.819}, points = {{0, 24.819}, {0, -24.819}}, color = {1, 37, 163})); + connect(historyNeededQ.y, switchedOutput.u_cond) annotation(Line(visible = true, origin = {60.006, 15.156}, points = {{-0.006, 7.481}, {-0.006, -0.156}, {0.006, -0.156}, {0.006, -7.168}}, color = {1, 37, 163})); + connect(delayedInput.y, switchedOutput.u2) annotation(Line(visible = true, origin = {16.25, -17.5}, points = {{-15.25, -12.5}, {-10.25, -12.5}, {-10.25, 12.5}, {35.75, 12.5}}, color = {1, 37, 163})); + connect(switchedOutput.y, y) annotation(Line(visible = true, origin = {113.681, 0}, points = {{-46.319, 0}, {46.319, 0}}, color = {1, 37, 163})); + connect(history.y, switchedOutput.u1) annotation(Line(visible = true, origin = {27.341, -27.5}, points = {{-69.979, -32.5}, {12.659, -32.5}, {12.659, 32.5}, {24.659, 32.5}}, color = {1, 37, 163})); + connect(u, delayedInput.u) annotation(Line(visible = true, origin = {-85.5, -2.5}, points = {{-84.5, 2.5}, {45.5, 2.5}, {45.5, -27.5}, {63.5, -27.5}}, color = {1, 37, 163})); + connect(u, delayedInputConstant.u) annotation(Line(visible = true, origin = {-78.423, 5}, points = {{-91.577, -5}, {38.423, -5}, {38.423, 5}, {56.423, 5}}, color = {1, 37, 163})); + connect(delayedInputConstant.y, switchedOutput.u2) annotation(Line(visible = true, origin = {28.25, 2.5}, points = {{-27.25, 7.5}, {-8.25, 7.5}, {-8.25, -7.5}, {23.75, -7.5}}, color = {1, 37, 163})); + connect(parDelayTime.y, clippedDelayTime.u) annotation(Line(visible = true, origin = {-98.25, 50}, points = {{-26.75, -10}, {-11.75, -10}, {-11.75, 10}, {5.25, 10}}, color = {1, 37, 163})); + connect(clippedDelayTime.y, delayedInput.delayTime) annotation(Line(visible = true, origin = {-74.106, 25.333}, points = {{-3.532, 34.667}, {14.106, 34.667}, {14.106, -49.333}, {52.106, -49.333}}, color = {1, 37, 163})); + connect(clippedDelayTime.y, lookupTime.u2) annotation(Line(visible = true, origin = {-31.409, 62.5}, points = {{-46.228, -2.5}, {-33.591, -2.5}, {-33.591, 2.5}, {113.409, 2.5}}, color = {1, 37, 163})); + connect(clock.y, lookupTime.u1) annotation(Line(visible = true, origin = {70.667, 79.213}, points = {{-5.667, 8.425}, {-5.667, -4.213}, {11.333, -4.213}}, color = {1, 37, 163})); + connect(lookupTime.y, y_lookupTime) annotation(Line(visible = true, origin = {129, 70}, points = {{-31, 0}, {31, 0}}, color = {1, 37, 163})); + connect(parStartTime.y, historyHorizon.u2) annotation(Line(visible = true, origin = {-12.402, 50}, points = {{-14.402, -0}, {14.402, 0}}, color = {1, 37, 163})); + connect(clippedDelayTime.y, historyHorizon.u1) annotation(Line(visible = true, origin = {-28.75, 57.5}, points = {{-48.25, 2.5}, {8.75, 2.5}, {8.75, 2.5}, {30.75, 2.5}}, color = {1, 37, 163})); + connect(historyHorizon.y, historyNeededQ.u2) annotation(Line(visible = true, origin = {42.667, 49.333}, points = {{-24.667, 5.667}, {12.333, 5.667}, {12.333, -11.333}}, color = {1, 37, 163})); + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-99.005, -12}, {99.005, 12}}, textString = "DELAY FIXED", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The real output y is the real input u delayed by a fixed delay time which can be constant (delayTime
) or variable (u_delayTime
) during the simulation.
y[t] = u[t - delayTime]
The input signal is thus effectively shifted forward in time.
+During an initial period (at most as long as the initial delayTime
or the maximumDelayTime
when the delay time can vary over time), we need to provide information about the historical input u (e.g. the input before the start time of the simulation). The historical input can either be given by a constant value (either the initialValue
or the initial input u) or by a function of time (usually a TableFunction), that will take the output connector y_timeHistory
as input and then provide the relevant historical input via the input connector u_history
.
DelayInformation
and DelayFixed
are quite similiar, but there is a subtle difference:DelayInformation
models the delay in perceiving information where the recipient is aware of the delay time and thus will disregard informatiion that is older than the one he already has.DelayFixed
we will strictly delay any information given the actual delay time at any point in time and thus may receive information that is actually older than previous information when the delay time increases.DelayFixed
is an information delay, that is used to model delays in updating beliefs and perceptions; unlike a material delay matter is not conserved [20]. init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial output y.initialValue
as an initial guess.DelayInformation, Smooth, SmoothN, Conveyor
+")); +end DelayFixed; diff --git a/BusinessSimulation/Converters/DiscreteDelay/DelayInformation.mo b/BusinessSimulation/Converters/DiscreteDelay/DelayInformation.mo new file mode 100644 index 0000000..2fdc0ad --- /dev/null +++ b/BusinessSimulation/Converters/DiscreteDelay/DelayInformation.mo @@ -0,0 +1,102 @@ +within BusinessSimulation.Converters.DiscreteDelay; + +model DelayInformation "Pipeline information delay with awareness" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.Time; + import BusinessSimulation.Constants.{inf,small}; + extends Interfaces.PartialConverters.SmoothSISO; + Interfaces.Connectors.RealInput u_history if hasExogenousHistory "Input of recent history (start time - initial delay time)" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 50}, extent = {{-10, 10}, {10, -10}}, rotation = -810))); + Interfaces.Connectors.RealOutput y_lookupTime if hasExogenousHistory "Time for looking up historical input" annotation(Placement(visible = true, transformation(origin = {158.118, 65}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 30}, extent = {{10, -10}, {-10, 10}}, rotation = -360))); + Interfaces.Connectors.RealInput u_delayTime if not hasConstantDelayTime "Delay time input" annotation(Placement(visible = true, transformation(origin = {-145, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 50}, extent = {{-10, 10}, {10, -10}}, rotation = -810))); + parameter Time delayTime(min = modelSettings.dt) = 1 "Constant delay time (optional)" annotation(Dialog(enable = hasConstantDelayTime)); + parameter Time maximumDelayTime = 50 "Maximal value allowed for delay time (needed for variable delay time)" annotation(Evaluate = true, Dialog(enable = not hasConstantDelayTime)); + parameter OutputType initialValue = 0 "Initial constant output, if no exogenous history is given" annotation(Dialog(enable = not init == InitializationOptions.SteadyState and not hasExogenousHistory)); + parameter Boolean hasConstantDelayTime = true "= true, if the delay time is given by the parameter 'delayTime'" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasExogenousHistory = false "= true, if the input 'u_history' gives the output for an initial period, otherwise the initial output will remain constant until delayTime is reached" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter InitializationOptions init = modelSettings.init "Provide InitializationOptions (Free, FixedValue, SteadyState)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + parameter Time samplingPeriod(min = small, max = modelSettings.dt) = modelSettings.samplingPeriod "Interval at which to check for increases in delay time" annotation(Evaluate = true, Dialog(tab = "Advanced")); + outer ModelSettings modelSettings; +protected + // variables + parameter Real initialOutput(start = initialValue, fixed = false) "Constant output if no exogenous history is provided" annotation(Dialog(tab = "Initialization", enable = false)); + parameter Time initialDelayTime(fixed = false) "Delay time at initial time" annotation(Dialog(tab = "Initialization", enable = false)); + Time t_delayed "Time stamp for the delayed time (if less than zero => use historical input)"; + discrete Real sampledDelayedInformation "Delayed information sampled when the delay time increased"; + discrete Time t_sample "Time, when the delay time last increased"; + // components + ConstantConverterTime parDelayTime(value = delayTime) if hasConstantDelayTime "Constant delay time (optional)" annotation(Placement(visible = true, transformation(origin = {-87.5, 40}, extent = {{10, 10}, {-10, -10}}, rotation = 180))); + ConstantConverter parInitialOutput(value = initialOutput) if not hasExogenousHistory "Initial output if not history is given" annotation(Placement(visible = true, transformation(origin = {-77.5, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Clip clippedDelayTime(minValue = modelSettings.dt, maxValue = if not hasConstantDelayTime then maximumDelayTime else inf) "DelayTime has to be in the interval (dt, maximumDelayTime)" annotation(Placement(visible = true, transformation(origin = {-42.5, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.VariableDelay delayedInput(delayMax = maximumDelayTime) if not hasConstantDelayTime annotation(Placement(visible = true, transformation(origin = {27.5, -30}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + PassThrough history annotation(Placement(visible = true, transformation(origin = {-7.5, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Modelica.Blocks.Nonlinear.FixedDelay delayedInputConstant(delayTime = delayTime) if hasConstantDelayTime "Delayed input with constant delay time" annotation(Placement(visible = true, transformation(origin = {27.5, 10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + PassThrough delayedInformation "Delayed input to use for further processing" annotation(Placement(visible = true, transformation(origin = {70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + InformationSources.TimeInput clock "Provide time starting with 0" annotation(Placement(visible = true, transformation(origin = {45, 85}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Gap lookupTime if hasExogenousHistory "Time that needs to be looked up in historical input data" annotation(Placement(visible = true, transformation(origin = {90, 65}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +initial equation + initialDelayTime = clippedDelayTime.y; + if init == InitializationOptions.FixedValue then + initialOutput = initialValue; + elseif init == InitializationOptions.SteadyState then + initialOutput = u; + end if; + pre(t_sample) = modelSettings.modelStartTime - initialDelayTime; + pre(sampledDelayedInformation) = delayedInformation.y; +algorithm + // check for increase in delay time at samplingPeriod-intervals + when sample(modelSettings.modelStartTime + samplingPeriod, samplingPeriod) then + if noEvent(pre(clippedDelayTime.y) < clippedDelayTime.y) then + // sample delayed information and store the time of sampling + t_sample := clock.y; + sampledDelayedInformation := pre(delayedInformation.y); + end if; + end when; + t_delayed := max(t_sample, clock.y - clippedDelayTime.y); + // while the historical information is more recent (e.g t_delayed < 0), use it + // otherwise decide if the last sample or the actual delayed information is more recent + y := if t_delayed < modelSettings.modelStartTime then history.y elseif t_sample > clock.y - clippedDelayTime.y then sampledDelayedInformation else delayedInformation.y; +equation + connect(u_delayTime, clippedDelayTime.u) annotation(Line(visible = true, origin = {-59.5, 50}, points = {{-85.5, 10}, {2, 10}, {2, 10}, {9, 10}}, color = {1, 37, 163})); + connect(u_history, history.u) annotation(Line(visible = true, origin = {-43.25, -50}, points = {{-101.75, 10}, {5.75, 10}, {5.75, -10}, {27.75, -10}}, color = {1, 37, 163})); + connect(parInitialOutput.y, history.u) annotation(Line(visible = true, origin = {-40.75, -70}, points = {{-31.75, -10}, {3.25, -10}, {3.25, 10}, {25.25, 10}}, color = {1, 37, 163})); + connect(u, delayedInput.u) annotation(Line(visible = true, origin = {-43, -2.5}, points = {{-127, 2.5}, {5.5, 2.5}, {5.5, -27.5}, {58.5, -27.5}}, color = {1, 37, 163})); + connect(u, delayedInputConstant.u) annotation(Line(visible = true, origin = {-35.923, 5}, points = {{-134.077, -5}, {-1.577, -5}, {-1.577, 5}, {51.423, 5}}, color = {1, 37, 163})); + connect(parDelayTime.y, clippedDelayTime.u) annotation(Line(visible = true, origin = {-55.75, 50}, points = {{-26.75, -10}, {-11.75, -10}, {-11.75, 10}, {5.25, 10}}, color = {1, 37, 163})); + connect(clippedDelayTime.y, delayedInput.delayTime) annotation(Line(visible = true, origin = {-31.606, 25.333}, points = {{-3.532, 34.667}, {31.606, 34.667}, {31.606, -49.333}, {47.106, -49.333}}, color = {1, 37, 163})); + connect(delayedInputConstant.y, delayedInformation.u) annotation(Line(visible = true, origin = {46.875, 5}, points = {{-8.375, 5}, {-3.375, 5}, {-3.375, -5}, {15.125, -5}}, color = {1, 37, 163})); + connect(delayedInput.y, delayedInformation.u) annotation(Line(visible = true, origin = {46.875, -15}, points = {{-8.375, -15}, {-3.375, -15}, {-3.375, 15}, {15.125, 15}}, color = {1, 37, 163})); + connect(clock.y, lookupTime.u1) annotation(Line(visible = true, origin = {63.591, 77.5}, points = {{-11.228, 7.5}, {-3.591, 7.5}, {-3.591, -7.5}, {18.409, -7.5}}, color = {1, 37, 163})); + connect(clippedDelayTime.y, lookupTime.u2) annotation(Line(visible = true, origin = {41.716, 62.5}, points = {{-76.853, -2.5}, {18.284, -2.5}, {18.284, -2.5}, {40.284, -2.5}}, color = {1, 37, 163})); + connect(lookupTime.y, y_lookupTime) annotation(Line(visible = true, origin = {128.059, 65}, points = {{-30.059, 0}, {30.059, 0}}, color = {1, 37, 163})); + annotation(Diagram(coordinateSystem(extent = {{-148.5, -100}, {146.892, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 12.5}, textColor = {0, 0, 128}, extent = {{-99.005, -12}, {99.005, 12}}, textString = "DELAY", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -12.5}, textColor = {0, 0, 128}, extent = {{-100, -12}, {100, 12}}, textString = "INFORMATION", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The real output y is the real input u delayed by a fixed delay time which can be constant (delayTime
) or variable (u_delayTime
) during the simulation.
y[t] = u[t - delayTime]
The input signal is thus effectively shifted forward in time.
+During an initial period (at most as long as the initial delayTime
or the maximumDelayTime
when the delay time can vary over time), we need to provide information about the historical input u (e.g. the input before the start time of the simulation). The historical input can either be given by a constant value (either the initialValue
or the initial input u) or by a function of time (usually a TableFunction), that will take the output connector y_timeHistory
as input and then provide the relevant historical input via the input connector u_history
.
Given, that the delay time may be variable, we must distinguish two kinds of changes:
+Internally a TimeInput
component is used to provide a clock starting at modelSettings.modelStartTime
. Whenever the clipped delay time increases, the delayed information and the time it was sampled (t_sampled
) will be stored. As long as max(t_sampled, clock.y - clippedDelayTime.y)
is less than modelSetting.modelStartTime
, the historical information (either the constant initialValue
or the input u_hist
) is reported as output y.
Once the current delayed output becomes more recent (either because time has proceeded beyond the initial delay time or the current delay time has significantly decreased), it will be used. From then on, the last stored information (e.g. information that is on hold due to an increase in delay time) will be compared with the currently delayed information output and whatever is more recent will be returned.
+As checking for increases in the delay time can introduce a lot of events, the checks will only be done a regular time events given by the parameter samplingPeriod
in the Advanced tab.
DelayInformation
and DelayFixed
are quite similiar, but there is a subtle difference:DelayInformation
models the delay in perceiving information where the recipient is aware of the delay time and thus will disregard older informatiion than the one he already has.DelayFixed
we will strictly delay any information given the actual delay time at any point in time and thus may receive information that is actually older than previous information when the delay time increases.DelayInformation
is an information delay, that is used to model delays in updating beliefs and perceptions; unlike a material delay matter is not conserved [20]. init
in the Advanced tab allows to select →InitializationOptions (but hasExogenousHistory = true
will allways have priority):initialValue
to determine the initial output y.initialValue
as an initial guess.DelayFixed, Smooth, SmoothN, Conveyor
+")); +end DelayInformation; diff --git a/BusinessSimulation/Converters/DiscreteDelay/SampleIfTrue.mo b/BusinessSimulation/Converters/DiscreteDelay/SampleIfTrue.mo new file mode 100644 index 0000000..e9f2eb9 --- /dev/null +++ b/BusinessSimulation/Converters/DiscreteDelay/SampleIfTrue.mo @@ -0,0 +1,42 @@ +within BusinessSimulation.Converters.DiscreteDelay; + +block SampleIfTrue "Samples input, if Boolean trigger is true" + import BusinessSimulation.Types.InitializationOptions; + extends Interfaces.PartialConverters.SmoothSISO(redeclare discrete RealOutput y); + extends Icons.DiscreteSmoothLabel; + Interfaces.Connectors.BooleanInput trigger "Triggers sampling upon `true`" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0.12, 49.88}, extent = {{-10.12, -10.12}, {10.12, 10.12}}, rotation = -450))); + parameter OutputType initialValue = 0 "Initial Value to be reported before sampling starts" annotation(Dialog(enable = not init == InitializationOptions.SteadyState)); + parameter InitializationOptions init = modelSettings.init "Provide InitializationOptions (Free, FixedValue, SteadyState)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + outer ModelSettings modelSettings; +protected + parameter Real initialOutput(start = initialValue, fixed = false) "Initial output for the sampler" annotation(Dialog(tab = "Initialization", enable = false)); +initial equation + if init == InitializationOptions.FixedValue then + initialOutput = initialValue; + elseif init == InitializationOptions.SteadyState then + initialOutput = u; + end if; + pre(y) = initialOutput; +algorithm + when trigger then + y := u; + end when; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The (discrete) output y is sampled from the input u whenever the Boolean input trigger
becomes true
.
init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial output y to be given before the sampling starts.initialValue
as an initial guess.+Sampler +
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 12.5}, textColor = {0, 0, 128}, extent = {{-51.371, -12}, {51.371, 12}}, textString = "SAMPLE", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Bitmap(visible = true, origin = {178.304, 50}, fileName = "", imageSource = "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGeYUxB9wAAACBjSFJNAAB6JQAAgIMAAPn/AACA6AAAUggAARVYAAA6lwAAF2/XWh+QAAAB7klEQVR42mJsufTiPwMZACCAWP5//4Fd4tcnBsndRQzyn/aA+Q/5XBieu/Yx/GHjA/MBAojl3zfsGmWOlDHo/N7DoKEA4Qu83MPAfKCM4Z7NBDAfIIBY/uKwUebtDrAmDlYIX0OcgeHDgx0Mt6HqAQKI5Q8OjbgATD1AALH8xuHUJ8IeDDde7gDbBAI3XkLEYOoBAojlF5Dx69dvhrev34MFePm4GXh4uRkuCqcw/P39B+g8ROBcAYrBNAIEEMuXT18Y3rx6z2Ctp8hgoCbNMHfTcYY/QIM4uTgYTgjlgDEc/AIREI0AAcTy+uU7BjtDZYZkP0uGn7/+MOSFOzBMXHGA4dfP3wzs7KwM////Z/j06SvDnz9/wRp4eLjA4gABxGRvpMKQEWjN8PfvPzCWEOJjSAPyQbZ+/vyN4cOHLwwC3BwMsV5mDN7W2gw/f/wEiwMEEOOPn7///wDa9PP3bwYwDcQg+tGLdwwLt55kYGVlYQhxNADb9gNo2Kt3nxkOXbjLABBATH/+AW0C4j9QG2G0iAAPQ5iLETDg/jDce/oGIg5Ux83FzmCqJccAEEBMCMX/Ic5FMkiIj4vBz06X4fiVBwwPnr+Fe4eLnY0BIIBYYDaAFf/7B5f8CzVMgJeTwcdGG+yFPyDDoeoAAgwAAiQQgeLRB5kAAAAASUVORK5CYII=", extent = {{-1.696, -0}, {1.696, 0}}), Text(visible = true, origin = {0, -12.5}, textColor = {0, 0, 128}, extent = {{-51.371, -12}, {51.371, 12}}, textString = "IF TRUE", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); +end SampleIfTrue; diff --git a/BusinessSimulation/Converters/DiscreteDelay/Sampler.mo b/BusinessSimulation/Converters/DiscreteDelay/Sampler.mo new file mode 100644 index 0000000..89afa57 --- /dev/null +++ b/BusinessSimulation/Converters/DiscreteDelay/Sampler.mo @@ -0,0 +1,45 @@ +within BusinessSimulation.Converters.DiscreteDelay; + +block Sampler "Ideal periodic sampler of input" + import BusinessSimulation.Units.Time; + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Constants.small; + extends Interfaces.PartialConverters.SmoothSISO(redeclare discrete RealOutput y); + extends Icons.DiscreteSmoothLabel; + parameter Time samplingPeriod(min = small) "Interval at which to sample the input" annotation(Evaluate = true); + parameter Time offsetStartTime = samplingPeriod "Sampling will begin at startTime = modelStartTime + offsetStartTime"; + parameter OutputType initialValue = 0 "Initial Value to be reported before startTime" annotation(Dialog(enable = not init == InitializationOptions.SteadyState)); + parameter InitializationOptions init = modelSettings.init "Provide InitializationOptions (Free, FixedValue, SteadyState)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + outer ModelSettings modelSettings; +protected + parameter Real initialOutput(start = initialValue, fixed = false) "Initial output for the sampler" annotation(Dialog(tab = "Initialization", enable = false)); +initial equation + if init == InitializationOptions.FixedValue then + initialOutput = initialValue; + elseif init == InitializationOptions.SteadyState then + initialOutput = u; + end if; + pre(y) = initialOutput; +algorithm + when sample(modelSettings.modelStartTime + offsetStartTime, samplingPeriod) then + y := u; + end when; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The (discrete) output y is obtained by sampling every samplingPeriod
starting at modelSettings.modelStartTime + offsetStartTime
from the input u.
init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial output y to be given before the sampling starts.initialValue
as an initial guess.+SampleIfTrue +
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-51.371, -12}, {51.371, 12}}, textString = "SAMPLER", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Sampler; diff --git a/BusinessSimulation/Converters/DiscreteDelay/Smooth.mo b/BusinessSimulation/Converters/DiscreteDelay/Smooth.mo new file mode 100644 index 0000000..09a39e5 --- /dev/null +++ b/BusinessSimulation/Converters/DiscreteDelay/Smooth.mo @@ -0,0 +1,59 @@ +within BusinessSimulation.Converters.DiscreteDelay; + +block Smooth "First-order exponential smooth" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.Time; + extends Interfaces.PartialConverters.SmoothSISO; + Interfaces.Connectors.RealInput u_delayTime if not hasConstantDelayTime "Delay time" annotation(Placement(visible = true, transformation(origin = {0, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {0, 50}, extent = {{-10, 10}, {10, -10}}, rotation = -810))); + parameter Time delayTime = 1 "Constant delay time (optional)" annotation(Dialog(enable = hasConstantDelayTime)); + parameter OutputType initialValue = 0 "Output at startTime" annotation(Dialog(enable = not init == InitializationOptions.SteadyState)); + parameter InitializationOptions init = modelSettings.init "Provide InitializationOptions (Free, FixedValue, SteadyState)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + parameter Boolean hasConstantDelayTime = true "= true, if delayTime is given by the parameter instead of the input" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + outer ModelSettings modelSettings; +protected + parameter Real initialOutput(start = initialValue, fixed = false) "Value to be used for initialization of the implicit stock" annotation(Dialog(enable = false, tab = "Initialization")); + SourcesOrSinks.ExogenousChange changingPerception annotation(Placement(visible = true, transformation(origin = {-50, 5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Gap gap "Difference between acutal information and perceived information" annotation(Placement(visible = true, transformation(origin = {-107.215, 50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Division_Guarded rateOfChange(outputIfZero = 0) "Rate of change in perceived information" annotation(Placement(visible = true, transformation(origin = {-68.12, 45}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.InformationLevel perceivedInformation(initialValue = initialOutput, init = BusinessSimulation.Types.InitializationOptions.FixedValue) "Smoothed information" annotation(Placement(visible = true, transformation(origin = {0, 5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + ClipProcessTime positiveDelayTime "Delay time shall never be less than dt" annotation(Placement(visible = true, transformation(origin = {-70, 80}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + ConstantConverterTime parDelayTime(value = delayTime) if hasConstantDelayTime "Constant delay time (optional)" annotation(Placement(visible = true, transformation(origin = {-35, 95}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); +initial equation + if init == InitializationOptions.FixedValue then + initialOutput = initialValue; + elseif init == InitializationOptions.SteadyState then + initialOutput = u; + end if; +equation + connect(u, gap.u1) annotation(Line(visible = true, origin = {-130.661, 22.5}, points = {{-39.339, -22.5}, {10.446, -22.5}, {10.446, 22.5}, {15.446, 22.5}}, color = {0, 0, 127})); + connect(gap.y, rateOfChange.u1) annotation(Line(visible = true, origin = {-87.986, 50}, points = {{-11.866, 0}, {11.866, 0}}, color = {0, 0, 127})); + connect(rateOfChange.y, changingPerception.u) annotation(Line(visible = true, origin = {-56.919, 35}, points = {{-3.838, 10}, {1.919, 10}, {1.919, -20}}, color = {0, 0, 127})); + connect(changingPerception.massPort, perceivedInformation.inflow) annotation(Line(visible = true, origin = {-25, 5}, points = {{-15, 0}, {15, 0}}, color = {128, 0, 128})); + connect(perceivedInformation.y, gap.u2) annotation(Line(visible = true, origin = {-69.643, 53.124}, points = {{74.643, -37.724}, {74.643, 11.876}, {-50.357, 11.876}, {-50.357, 1.876}, {-45.572, 1.876}}, color = {0, 0, 127})); + connect(perceivedInformation.y1, y) annotation(Line(visible = true, origin = {62.625, -2.5}, points = {{-52.125, 2.5}, {-22.625, 2.5}, {-22.625, 2.5}, {97.375, 2.5}}, color = {1, 37, 163})); + connect(positiveDelayTime.y, rateOfChange.u2) annotation(Line(visible = true, origin = {-83.371, 62.5}, points = {{5.371, 17.5}, {-6.629, 17.5}, {-6.629, -22.5}, {7.251, -22.5}}, color = {1, 37, 163})); + connect(parDelayTime.y, positiveDelayTime.u) annotation(Line(visible = true, origin = {-44, 83}, points = {{9, 6}, {9, -3}, {-18, -3}}, color = {1, 37, 163})); + connect(u_delayTime, positiveDelayTime.u) annotation(Line(visible = true, origin = {-20.667, 86.667}, points = {{20.667, 13.333}, {20.667, -6.667}, {-41.333, -6.667}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A smooth is a first-order exponential information delay. It is typically used to model time lags in forming an expectation or in perceiving some information.
+Inside the converter there actually is a stock x that stores the perceived or expected value of the information input u. The output y is derived immediately from x as can be seen from these equations where τ denotes the delayTime
:
delayTime
given (either as constant parameter or continuous signal) will be clipped to a minimum value of modelSettings.dt
, which denotes the smallest possible process time anywhere in the model. The time of delay for the process of information perception or expectation formation can thus never be zero or negative.init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial output y.initialValue
as an initial guess.This information is part of the Business Simulation Library (BSL).
+A smooth is an exponential information delay. It is typically used to model time lags in forming an expectation or in perceiving some information. A smooth of order n
is modeled as a cascade of n
first-order exponential smooth components, where the output of a preceding component is the input for its successor. The delay time for each smooth in the cascade will be delayTime/n
.
delayTime
given (either as constant parameter or continuous signal) will effectively be clipped to a minimum value of n × modelSettings.dt
. The delay time for any first-order smooth in the cascade can thus never become smalle than dt
, which denotes the minimum process time anywhere in the model.init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial output y.initialValue
as an initial guess.This information is part of the Business Simulation Library (BSL).
+This package contains converters which have an internal stock or state—exemplified by rectangular icons. This can be discrete processes of information collection as in the Sampler
or SampleIfTrue
converters, or it can be information delays where the perceived or reported information will follow the actual information with some lag.
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y is obtained by unguarded division of the nominator input u1 and the denominator input u2:
+y = u1/u2;+
This information is part of the Business Simulation Library (BSL).
+The output y is obtained by guarded division of the nominator input u1 and the denominator input u2:
+y = u1/u2
If u2 is equal to zero, then outputIfZero
is returned.
y = if noEvent(u2 < 0 or u2 > 0) then u1 / u2 else outputIfZero;
This information is part of the Business Simulation Library (BSL).
+The output y is obtained by guarded division of the input u by some reference value. The reference value can either be a constant (referenceValue
) or a variable input (u_reference
). If the reference value is zero the output will be zero also.
Since there is just regular division, care has to be taken in case of negative values for either input or reference value.
+As the reference value should have the same dimension as the input, the output will effectively be dimensionless.
+This information is part of the Business Simulation Library (BSL).
+The output y is the natural exponential function of the input u.
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "EXP", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Exp; diff --git a/BusinessSimulation/Converters/ForceOfInterest.mo b/BusinessSimulation/Converters/ForceOfInterest.mo new file mode 100644 index 0000000..88ad617 --- /dev/null +++ b/BusinessSimulation/Converters/ForceOfInterest.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Converters; + +block ForceOfInterest "Calculates the force of interest (continuous compounding rate)" + extends Interfaces.PartialConverters.SISO; +equation + y = log(1 + u); + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-54.133, -12}, {54.133, 12}}, textString = "Ln (1 + u)", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Force of Interest y is calculated according to the formula:
+y = log( 1+ u)
It can be used to convert a periodically compounding rate to a continuously coumpounding rate.
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ForceOfInterest; diff --git a/BusinessSimulation/Converters/Gain.mo b/BusinessSimulation/Converters/Gain.mo new file mode 100644 index 0000000..4d2949c --- /dev/null +++ b/BusinessSimulation/Converters/Gain.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Converters; + +block Gain "Input is multiplied by constant parameter" + extends Interfaces.PartialConverters.SISO; + parameter Real c "Gain factor (constant multiplier)"; +equation + y = u * c; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is obtained by multiplying the input u with a constant gain factor c:
+y = c * u;", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {5, -30}, textColor = {64, 64, 64}, extent = {{-55, -6}, {45, 6}}, textString = "%c", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, textColor = {0, 0, 128}, extent = {{-99.005, -12}, {99.005, 12}}, textString = "GAIN", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Gain; diff --git a/BusinessSimulation/Converters/Gap.mo b/BusinessSimulation/Converters/Gap.mo new file mode 100644 index 0000000..21eb52d --- /dev/null +++ b/BusinessSimulation/Converters/Gap.mo @@ -0,0 +1,11 @@ +within BusinessSimulation.Converters; + +block Gap "Compare goal (u1) and current value (u2) to determine gap" + extends Interfaces.PartialConverters.SI2SO; +equation + y = u1 - u2; + annotation(Documentation(info = " +
This information is part of the Business Simulation Library (BSL).
+The output y is obtained by subtracting input u2 from input u1:
+y = u1 - u2;", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-32.809, -50}, rotation = -990, points = {{-0, 27.191}, {-0, 1.074}}, color = {255, 0, 0}, thickness = 3), Line(visible = true, origin = {-21.062, -30}, rotation = -270, points = {{-20, 14.231}, {20, -14.231}}, color = {255, 0, 0}, thickness = 3, arrowSize = 10), Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {5, 5, 125}, fillPattern = FillPattern.Solid, extent = {{-11.872, -11.872}, {11.872, 11.872}}), Line(visible = true, origin = {-19.639, 27.324}, points = {{-14.516, 20.778}, {14.516, -20.778}}, color = {5, 5, 125}, thickness = 3, arrowSize = 10), Line(visible = true, origin = {33.017, 0}, rotation = -270, points = {{0, 25.332}, {0, -25.332}}, color = {5, 5, 125}, thickness = 3, arrowSize = 10), Line(visible = true, origin = {-29.824, 50}, rotation = -990, points = {{-0, 30.176}, {-0, 4.373}}, color = {0, 0, 128}, thickness = 3), Text(visible = true, origin = {1.181, 42.115}, textColor = {0, 0, 128}, extent = {{-21.181, -20}, {21.181, 20}}, textString = "+", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {1.402, -36}, textColor = {255, 0, 0}, extent = {{-15.402, -20}, {15.402, 20}}, textString = "‒", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Gap; diff --git a/BusinessSimulation/Converters/Log.mo b/BusinessSimulation/Converters/Log.mo new file mode 100644 index 0000000..5e3aaa6 --- /dev/null +++ b/BusinessSimulation/Converters/Log.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Converters; + +block Log "Logarithm of the input to a given base" + extends Interfaces.PartialConverters.SISO; + import BusinessSimulation.Constants.{e,small}; + parameter Real base(min = small) = e "Base of the logarithm (default = Euler's number)" annotation(Evaluate = true); +equation + y = log(u) / log(base); + annotation(Documentation(info = " +
This information is part of the Business Simulation Library (BSL).
+The output y is obtained as the logarithm of the input u to base base
with the default base being Euler's number.
This information is part of the Business Simulation Library (BSL).
+The Boolean output y is true
, if all Boolean elements of the input vector u are true
, and false
otherwise.
This information is part of the Business Simulation Library (BSL).
+The Boolean output y is true
, if both Boolean inputs u1 and u2 are true
, and false
else.
This information is part of the Business Simulation Library (BSL).
+The Boolean output y is true
, if any of the Boolean elements of the input vector u are true
, and false
otherwise.
This information is part of the Business Simulation Library (BSL).
+The real output y will be 1 if the boolean input u is true
and 0 if it is false
.
This information is part of the Business Simulation Library (BSL).
+The boolean output y is equal to the boolean parameter value
during a simulation.
This information is part of the Business Simulation Library (BSL).
+The boolean output y will be true
, if the real input u1 is greater than the real input u2 and otherwise be false
.
This information is part of the Business Simulation Library (BSL).
+The boolean output y will be true
, if the real input u1 is greater than or equal to the real input u2 and otherwise be false
.
This information is part of the Business Simulation Library (BSL).
+The boolean output y will be true
, if the real input u1 is less than the real input u2 and otherwise be false
.
This information is part of the Business Simulation Library (BSL).
+The boolean output y will be true
, if the real input u1 is less than or equal to the real input u2 and otherwise be false
.
This information is part of the Business Simulation Library (BSL).
+The Boolean output y is true
, if none of the Boolean elements of the input vector u are true
, and false
otherwise.
This information is part of the Business Simulation Library (BSL).
+The boolean output y is true
, if the Boolean input u is false
, and false otherwise.
This information is part of the Business Simulation Library (BSL).
+The boolean output y is true
, if the real input u is not equal to zero, and false
else.
If the inputs are restricted to either 0 or 1, then NotZero can be seen as an inverse Boole.
+This information is part of the Business Simulation Library (BSL).
+The boolean output y is true
, if either or both boolean inputs u1 and u2 are true
, and false
else.
This information is part of the Business Simulation Library (BSL).
+Depending upon the boolean input u_cond
the output y will be equal to either the input u1 (u_cond = true
) or the input u2 (u_cond = false
).
This information is part of the Business Simulation Library (BSL).
+The SwitchN switches up to n
times between the inputs u1 (u_cond = true
) and u2 (u_cond = false
). After each switching an internal counter will be increased and checked so that there are at most n
switches.
This information is part of the Business Simulation Library (BSL).
+The boolean output y is true
, if the real input u is greather than threshold
, and false
otherwise.
This information is part of the Business Simulation Library (BSL).
+The boolean output y is true
, if either (but not both) boolean inputs u1 and u2 are true
, and false
else.
This information is part of the Business Simulation Library (BSL).
+This package contains converters where at least input or output signals are Boolean variables.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y is derived using the formula:
+ +The function will go through the point (0,y0) and the output will be 0 for u ≥ 1 and y0 for u ≤ 0. The input u should thus be in the range [0,1]. The following graph shows plots for the function for different slopes:
++ |
ConcaveLookupPositive, ConvexLookupNegative, ConvexLookupPositive
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {10.816, -30}, points = {{-46.394, 0}, {32.732, 0}, {13.662, 0}}, color = {128, 128, 128}, thickness = 1), Line(visible = true, origin = {-35.548, 9.209}, rotation = -270, points = {{-39.209, 0}, {18.362, 0}, {20.847, 0}}, color = {128, 128, 128}, thickness = 1), Text(visible = true, origin = {7.341, -37.537}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "u", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-43.292, 4.265}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "y", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {4, -6.714}, rotation = -180, points = {{-16, 23.286}, {6.446, -3.219}, {38.948, -6.714}}, color = {0, 0, 128}, thickness = 3, smooth = Smooth.Bezier), Ellipse(visible = true, origin = {19.097, -30}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Text(visible = true, origin = {30, 0}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "(1,0)", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConcaveLookupNegative; diff --git a/BusinessSimulation/Converters/Lookup/ConcaveLookupPositive.mo b/BusinessSimulation/Converters/Lookup/ConcaveLookupPositive.mo new file mode 100644 index 0000000..7ec2f96 --- /dev/null +++ b/BusinessSimulation/Converters/Lookup/ConcaveLookupPositive.mo @@ -0,0 +1,30 @@ +within BusinessSimulation.Converters.Lookup; + +block ConcaveLookupPositive "Concave Lookup with positive slope; fixpoints are (0,y0) and (1,1)" + extends Interfaces.PartialConverters.SISO; + parameter Real s(min = 0, max = 1) = 0.5 "Slope parameter (0< slope <= 1)"; + parameter Real y0(min = 0, max = 1) = 0 "Value of y when input is zero or less (intercept)"; +equation + assert(y0 >= 0 and y0 <= 1, "Intercept should be within the closed unit interval [0,1]", level = AssertionLevel.warning); + assert(s > 0 and s <= 1, "Slope should be within the interval (0,1]", level = AssertionLevel.warning); + y = if noEvent(u <= 0) then y0 else y0 + (1 - y0) * u ^ s; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is derived using the formula:
+ +The function will go through the points (1,1) and (0,y0). The output will be y0 for u ≤ 0.
++ |
y0
(intercept) should be within the interval [0,1).s
(slope) should be within the interval (0,1].ConcaveLookupNegative, ConvexLookupPositive, ConvexLookupNegative
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {10.816, -30}, points = {{-46.394, 0}, {32.732, 0}, {13.662, 0}}, color = {128, 128, 128}, thickness = 1), Line(visible = true, origin = {-35.548, 9.209}, rotation = -270, points = {{-39.209, 0}, {18.362, 0}, {20.847, 0}}, color = {128, 128, 128}, thickness = 1), Text(visible = true, origin = {7.341, -37.537}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "u", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-43.292, 4.265}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "y", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {4, -6.714}, rotation = -180, points = {{-35, -17.714}, {15, -2.472}, {37.931, 22.286}}, color = {0, 0, 128}, thickness = 3, smooth = Smooth.Bezier), Line(visible = true, origin = {-16.901, -11.709}, points = {{-18.396, 1.709}, {-2.099, 1.709}}, color = {128, 128, 128}, pattern = LinePattern.Dot, thickness = 1), Line(visible = true, origin = {-16.686, -42.099}, rotation = -90, points = {{-32.099, 1.709}, {-14.975, 1.709}}, color = {128, 128, 128}, pattern = LinePattern.Dot, thickness = 1), Ellipse(visible = true, origin = {-14.903, -10}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Ellipse(visible = true, origin = {-35, -10}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Ellipse(visible = true, origin = {-14.903, -30}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Text(visible = true, origin = {-8.921, 18}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "(1,1)", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConcaveLookupPositive; diff --git a/BusinessSimulation/Converters/Lookup/ConvexLookupNegative.mo b/BusinessSimulation/Converters/Lookup/ConvexLookupNegative.mo new file mode 100644 index 0000000..958c2eb --- /dev/null +++ b/BusinessSimulation/Converters/Lookup/ConvexLookupNegative.mo @@ -0,0 +1,28 @@ +within BusinessSimulation.Converters.Lookup; + +block ConvexLookupNegative "Convex Lookup with negative slope usually defined for the range [0,∞) passing through the fixpoint (1,1)" + extends Interfaces.PartialConverters.SISO; + import BusinessSimulation.Constants.eps; + parameter Real y0(min = 1) = 2 "Value of y (intercept) when input is zero or less (y0>1)"; +equation + assert(y0 > 1, "Intercept should be greater than 1", level = AssertionLevel.warning); + y = smooth(3, if u <= 0 then y0 else y0 ^ (1 - u)); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is derived using the formula:
+ +The function will go through the point (1,1) and (0,y0). The output will be y0 for u ≤ 0. The following graph shows plots for the function for different values of y0:
++ |
y0
(intercept) should be greater than 1.ConvexLookupPositive, ConcaveLookupNegative, ConcaveLookupPositive
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {10.816, -30}, points = {{-46.394, 0}, {32.732, 0}, {13.662, 0}}, color = {128, 128, 128}, thickness = 1), Line(visible = true, origin = {-35.548, 9.209}, rotation = -270, points = {{-39.209, 0}, {18.362, 0}, {20.847, 0}}, color = {128, 128, 128}, thickness = 1), Line(visible = true, origin = {16, 10.357}, points = {{27.931, -35}, {-31.224, -28.273}, {-50.578, 13.643}}, color = {0, 0, 128}, thickness = 3, smooth = Smooth.Bezier), Text(visible = true, origin = {7.341, -37.537}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "u", fontName = "Lato"), Text(visible = true, origin = {-43.292, 4.265}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "y", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {-16.901, -11.709}, points = {{-18.396, 1.709}, {-2.099, 1.709}}, color = {128, 128, 128}, pattern = LinePattern.Dot, thickness = 1), Line(visible = true, origin = {-16.686, -42.099}, rotation = -90, points = {{-32.099, 1.709}, {-14.975, 1.709}}, color = {128, 128, 128}, pattern = LinePattern.Dot, thickness = 1), Ellipse(visible = true, origin = {-14.903, -10}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Ellipse(visible = true, origin = {-35, -10}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Ellipse(visible = true, origin = {-14.903, -30}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Text(visible = true, origin = {10, 8}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "(1,1)", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConvexLookupNegative; diff --git a/BusinessSimulation/Converters/Lookup/ConvexLookupPositive.mo b/BusinessSimulation/Converters/Lookup/ConvexLookupPositive.mo new file mode 100644 index 0000000..4dc2236 --- /dev/null +++ b/BusinessSimulation/Converters/Lookup/ConvexLookupPositive.mo @@ -0,0 +1,30 @@ +within BusinessSimulation.Converters.Lookup; + +block ConvexLookupPositive "Convex Lookup with positive slope; usually with fixpoint (0,y0) and fixpoint (1,1)" + extends Interfaces.PartialConverters.SISO; + parameter Real s(min = 1) = 1 "Slope parameter (s>1)"; + parameter Real y0(min = 0, max = 1) = 0 "Value of y when input is zero or less"; +equation + assert(s > 1, "Slope should be greater than 1", level = AssertionLevel.warning); + assert(y0 >= 0 and y0 <= 1, "Intercept should be within the closed unit interval [0,1]", level = AssertionLevel.warning); + y = if noEvent(u <= 0) then y0 else y0 + (1 - y0) * u ^ s; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is derived using the formula:
+ +The function will go through the point (1,1) and the output will be y0 for u ≤ 0.
++ |
y0
(intercept) should be within the interval [0,1).s
(slope) should be greater than 1.ConvexLookupNegative, ConcaveLookupPositive, ConcaveLookupNegative
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {10.816, -30}, points = {{-46.394, 0}, {32.732, 0}, {13.662, 0}}, color = {128, 128, 128}, thickness = 1), Line(visible = true, origin = {-35.548, 9.209}, rotation = -270, points = {{-39.209, 0}, {18.362, 0}, {20.847, 0}}, color = {128, 128, 128}, thickness = 1), Line(visible = true, origin = {-6.931, 6}, points = {{-27.931, -35}, {15.901, -25}, {37.931, 22.286}}, color = {0, 0, 128}, thickness = 3, smooth = Smooth.Bezier), Text(visible = true, origin = {7.341, -37.537}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "u", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-43.292, 4.265}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "y", fontName = "Lato", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConvexLookupPositive; diff --git a/BusinessSimulation/Converters/Lookup/JanoschekNegative.mo b/BusinessSimulation/Converters/Lookup/JanoschekNegative.mo new file mode 100644 index 0000000..dd38422 --- /dev/null +++ b/BusinessSimulation/Converters/Lookup/JanoschekNegative.mo @@ -0,0 +1,64 @@ +within BusinessSimulation.Converters.Lookup; + +block JanoschekNegative "Janoschek's (S-shaped) growth curve with negative slope" + extends Interfaces.PartialConverters.SISO; + parameter Real upperBound = 2 "Upper asymptote for u <= 0 (upperBound > lowerBound)"; + parameter Real lowerBound = 0 "Lower asymptote for u -> infinity"; + parameter Real growthRate(min = 0) = 2 "Determines the gradient of the curve"; + parameter Real x_ref(min = 0) = 1 "x-value for point of inflection(>0)"; + parameter Real y_ref = 1 "y-value for point of inflection(lowerBound < y_ref < upperBound)"; +protected + Real k; +equation + assert(lowerBound < upperBound, "lowerBound must be smaller than upperBound"); + assert(y_ref > lowerBound and y_ref < upperBound, "y_ref needs to be between lowerBound and upperBound"); + assert(x_ref > 0, "x_ref needs to be greater than zero"); + // parameter k is determined by the constraint: f(x_ref) = y_ref + // for negative sloping curve upperBound and lowerBound simply need to be switched + k = x_ref ^ (-growthRate) * log(((-upperBound) + lowerBound) / (lowerBound - y_ref)); + y = smooth(5, if u <= 0 then upperBound else Functions.janoschek(x = u, l = lowerBound, b = upperBound, k = k, d = growthRate)); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This negative sloping Janoschek-Growth-Curve is simply a modification of the positive version. For more detail see JanoschekPositive.
+The function is given by the following equation:
+ +Where l is the lower bound, β is the upper bound, and δ is a parameter that determines the rate of growth (e.g. steepness of the curve). Given the point of inflection (x_ref,y_ref
) the parameter k can be obtained in closed form, which is made use of in this implementation.
The following animation shows a growth curve with the following parameters:
+Parameter | +Value | +
---|---|
upperBound |
+
+ 2 + |
+
lowerBound |
+
+ 0.1 + |
+
(x_ref, y_ref) |
+
+ (1,1) + |
+
growthRate |
+
+ 1, ... ,10 + |
+
The lowerBound
must be smaller than the upperBound
. Also y_ref
needs to be in the range [lowerBound, upperBound
], while x_ref
has to be a positive number larger than zero.
This information is part of the Business Simulation Library (BSL).
+Many natural growth processes can be very closely described by s-shaped parametric functions (e.g. logistic curve). A. Janoschek [19] has proposed a growth curve that is determined by four parameters in 1957, which is very similar to the Weibull growth curve.
+The function is given by the following equation:
+ +Where l is the upper bound, β is the lower bound, and δ is a parameter that determines the rate of growth (e.g. steepness of the curve). Given the point of inflection (x_ref,y_ref) the parameter k can be obtained in closed form, which is made use of in this implementation.
+The following animation shows a growth curve with the following parameters:
+Parameter | +Value | +
---|---|
upperBound |
+
+ 2 + |
+
lowerBound |
+
+ 0.1 + |
+
(x_ref, y_ref) |
+
+ (1,1) + |
+
growthRate |
+
+ 1, ... ,10 + |
+
The lowerBound
must be smaller than the upperBound
. Also y_ref
needs to be in the range [lowerBound, upperBound
], while x_ref
has to be a positive number larger than zero.
This information is part of the Business Simulation Library (BSL).
+The output y is the dimensionless degree of membership to the set of \"good performances\" or \"good outcomes\" according to a chosen type of membership function. Using the PerformanceIndicator allows to quickly grasp how a system is currently performing with regard to some criteria: a value of 1 indicates best possible performance, while a value of 0 indicates unsustainable performance.
+The following grid displays all available membership function types without inversion (invertResults = false
):
+
+ |
+
Membership Function Type | +a | +b | +c | +d | +
---|---|---|---|---|
ramp | +foot | +shoulder | ++ | + |
triangular | +left foot | +center | +right foot | ++ |
trapezoidal | +left foot | +left shoulder | +right shoulder | +right foot | +
sshaped | +foot | +shoulder | ++ | + |
sigmoidal | +steepness of transition area | ++ | center of transition area | ++ |
pishaped | +left foot | +left shoulder | +right shoulder | +right foot | +
psigmoidal | +steepness of left transition | +center of left transition area | +steepness of right transition | +center of right transition area | +
gaussian | +half width at half maximum | ++ | center of curve (maximum) | ++ |
bell | +width of core | +steepness | +center of core | ++ |
When inversion is turned on (invertResult = true
) the result obtained from the membership function as specified will be subtracted from 1. Thus the ramp shown above can be made to ramp down from left to right with a
being the shoulder and b
the foot by inverting the results.
rampmf, trapmf, trimf, smf, sigmf, pimf, psigmf, gaussmf, gbellmf
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-11.686, -22.099}, rotation = -90, points = {{-44.186, 1.686}, {-14.975, 1.709}}, color = {128, 128, 128}, pattern = LinePattern.Dot, thickness = 1), Line(visible = true, origin = {-8.485, -8.173}, points = {{-46.394, 0}, {32.732, 0}, {13.662, 0}}, color = {128, 128, 128}, thickness = 1), Text(visible = true, origin = {0, -30}, textColor = {0, 0, 128}, extent = {{-36.812, -12}, {36.812, 12}}, textString = "PI", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Line(visible = true, points = {{-7.669, 20}, {18.252, 20}, {23.387, -7.757}, {51.346, -7.757}}, color = {0, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {-9.903, -8}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Text(visible = true, origin = {40, 20}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "1", fontName = "Lato"), Line(visible = true, origin = {-47.217, 12.243}, points = {{-7.669, -20}, {18.252, -20}, {27.217, 7.757}, {51.346, 7.757}}, color = {0, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {-10, 20}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Text(visible = true, origin = {-40, -20}, textColor = {128, 128, 128}, extent = {{-18.921, -12}, {18.921, 12}}, textString = "0", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end PerformanceIndicator; diff --git a/BusinessSimulation/Converters/Lookup/SShapedNegative.mo b/BusinessSimulation/Converters/Lookup/SShapedNegative.mo new file mode 100644 index 0000000..ea48a4f --- /dev/null +++ b/BusinessSimulation/Converters/Lookup/SShapedNegative.mo @@ -0,0 +1,24 @@ +within BusinessSimulation.Converters.Lookup; + +block SShapedNegative "Symmettric S-shaped curve with negative slope around origin (0,0)" + extends Interfaces.PartialConverters.SISO; + parameter Real upperBound(min = 0) = 1 "Upper asymptote (upperBound > 0)"; + parameter Real s(min = 1) = 2 "Slope controls gradient of curve"; +equation + y = -upperBound * (s ^ u - 1) / (s ^ u + 1); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The SShapedNegative
lookup-function is a point symmetric, s-shaped growth function with respect to the origin (0,0) that has a negative slope. The curve has two parameters: An upperBound
(lowerBound = -upperBound
) and a slope s
which is given as a positive number.
The output y is obtained by the following formula:
+ ++ |
This information is part of the Business Simulation Library (BSL).
+The SShapedPositive
lookup-function is a point symmetric, s-shaped growth function with respect to the origin (0,0) that has a positive slope. The curve has two parameters: An upperBound
(lowerBound = -upperBound
) and a slope s
which is given as a positive number.
The output y is obtained by the following formula:
+ ++ |
This information is part of the Business Simulation Library (BSL).
+This converter uses the Modelica CombiTable format to read in a 1-D table function from file. For more explanation regarding the 1-D Modelica CombiTable interpolation see Modelica.Blocks.Tables.CombiTable1Ds.
+The Modelica CombiTable format can be generated by Wolfram Mathematica using Export[]:
Export[ filename, { {\"TableName1\", table1}, {\"TableName2\", table2}, ... }, \"MCTT\" ]
where table1, table2, ...
are 2-dimensional arrays. By default all lookup data are assumed to be included in a single file whose name is given by the global parameter lookupDataFileURI
.
TableFunctionVector, LinearTimeTable
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end TableFunction; diff --git a/BusinessSimulation/Converters/Lookup/TableFunctionVector.mo b/BusinessSimulation/Converters/Lookup/TableFunctionVector.mo new file mode 100644 index 0000000..a017c17 --- /dev/null +++ b/BusinessSimulation/Converters/Lookup/TableFunctionVector.mo @@ -0,0 +1,35 @@ +within BusinessSimulation.Converters.Lookup; + +block TableFunctionVector "Table function for vector input and output using Modelica's CombiTable format" + import Modelica.Blocks.Types.{Extrapolation,Smoothness}; + extends Interfaces.PartialConverters.MIMO_nin; + extends Icons.InterpolationTable; + parameter Boolean tableOnFile = false "= true, if table is defined on file or in function usertab (combiTable1D.tableOnFile)" annotation(Dialog(group = "TableDataDefinition")); + parameter Real table[:, :] = fill(0.0, 0, 2) "Table matrix (grid = first column; e.g., table=[0,2]) (combiTable1D.table)" annotation(Dialog(group = "TableDataDefinition", enable = not tableOnFile)); + parameter String tableName = "NoName" "Name of the table in the file containing the data" annotation(Dialog(group = "TableDataDefinition", enable = tableOnFile)); + parameter String fileNameURI = modelSettings.lookupDataFileURI "URI of the file to read the data from (default = lookupDataFileURI)" annotation(Dialog(group = "TableDataDefinition", enable = tableOnFile)); + parameter Smoothness smoothness = Smoothness.LinearSegments "Smoothness of table interpolation" annotation(Dialog(group = "TableDataInterpretation")); + parameter Integer[nin] columns = fill(2, nin) "Columns of table to be interpolated (length must be equal to length of input and output vectors)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Boolean verboseRead = true "= true, if info message that file is loading is to be printed (combiTable1D.verboseRead)" annotation(Dialog(group = "TableDataDefinition", enable = tableOnFile)); + parameter Extrapolation extrapolation = Extrapolation.LastTwoPoints "Extrapolation of data outside the definition range (combiTable1D.extrapolation)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Boolean verboseExtrapolation = false "= true, if warning messages are to be printed if table input is outside the definition range (combiTable1D.verboseExtrapolation)" annotation(Dialog(group = "TableDataInterpretation")); +protected + outer ModelSettings modelSettings; + parameter String fileName = if tableOnFile then Modelica.Utilities.Files.loadResource(fileNameURI) else "NoName" "Absolute path to the file specified by fileName" annotation(Dialog(group = "Initialization", enable = false)); + Modelica.Blocks.Tables.CombiTable1D combiTable1D(smoothness = smoothness, tableOnFile = tableOnFile, tableName = tableName, fileName = fileName, verboseRead = verboseRead, table = table, columns = columns, extrapolation = extrapolation, verboseExtrapolation = verboseExtrapolation) "Modelica combi table" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(u, combiTable1D.u) annotation(Line(visible = true, origin = {-91, 0}, points = {{-79, 0}, {79, 0}}, color = {1, 37, 163})); + connect(combiTable1D.y, y) annotation(Line(visible = true, origin = {85.5, 0}, points = {{-74.5, 0}, {74.5, 0}}, color = {1, 37, 163})); + // assert statements + assert(size(columns, 1) == nin, "Columns vector does not match length of input vector"); + // assert(min(columns) >= 2 and max(columns) <= size(table, 2), "Columns are out of range"); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This converter uses the Modelica CombiTable format to read in a 1-D table function from file. For more explanation regarding the 1-D Modelica CombiTable interpolation see Modelica.Blocks.Tables.CombiTable1D.
+The Modelica CombiTable format can be generated by Wolfram Mathematica using Export[]:
Export[ filename, { {\"TableName1\", table1}, {\"TableName2\", table2}, ... }, \"MCTT\" ]
where table1, table2, ...
are 2-dimensional arrays. By default all lookup data are assumed to be included in a single file whose name is given by the global parameter lookupDataFileURI
.
TableFunction, LinearTimeTable
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end TableFunctionVector; diff --git a/BusinessSimulation/Converters/Lookup/package.mo b/BusinessSimulation/Converters/Lookup/package.mo new file mode 100644 index 0000000..c321d80 --- /dev/null +++ b/BusinessSimulation/Converters/Lookup/package.mo @@ -0,0 +1,14 @@ +within BusinessSimulation.Converters; + +package Lookup "Table- or Lookup-Functions" + extends Icons.Package; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Table- or Lookup-Functions usually map some variable (usually normalized as a dimensionless input) onto a real number by either providing a parametric funcion or a table of values which is then used for interpolation. Typically lookup functions are nonlinear functions and introduce nonlinearity to dynamic models [3, Ch. 14].
+The parametric lookup functions presented in this package are to a great part inspired by an article written by Khalid Saeed and Arit Irmaridiris [4]. They either directly use the proposed functional form from that article or were slightly modified by the author of the Business Simulation Library using Wolfram Mathematica.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y is the maximum of the inputs u1 and u2.
+This information is part of the Business Simulation Library (BSL).
+The output y is the minimum of the inputs u1 and u2.
+This information is part of the Business Simulation Library (BSL).
+The output y is identical to the input u.
+This component is most often useful as a conditional component: Graphical components and their connections are automatically removed when the component is not active, so the PassThrough component can be used to switch bewtween different structural configurations inside a component (e.g. have an input be modified or unmodified according to some switch as is done in BusinessSimulation.SourcesOrSinks.ExponentialGrowth where the input rate is turned to a force of interest or left unchanged according to a structural parameter).
", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-4.277, 0}, points = {{-80.493, 0}, {80.493, 0}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end PassThrough; diff --git a/BusinessSimulation/Converters/PolynomialFunction.mo b/BusinessSimulation/Converters/PolynomialFunction.mo new file mode 100644 index 0000000..9e957ec --- /dev/null +++ b/BusinessSimulation/Converters/PolynomialFunction.mo @@ -0,0 +1,14 @@ +within BusinessSimulation.Converters; + +block PolynomialFunction "Transform the input according to a polynomial function with given coefficients" + extends Interfaces.PartialConverters.SISO; + parameter Real a[:] = {0, 1} "Vector of coefficients (a_0, a_1, ..., a_n)"; +protected + parameter Integer n(min = 0) = size(a, 1) - 1 "Degree of the polynomial function"; +equation + y = Functions.polynomialFunction(a = a, x = u); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The PolynomialFunction
converter transforms the input signal u according to a polynomial function of degree n:
This information is part of the Business Simulation Library (BSL).
+The output y is the exponentiationen of base u to either a constant power exponent
or a variable power u_exponent.
y = u ^ exponent+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "POWER", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Power; diff --git a/BusinessSimulation/Converters/Product_2.mo b/BusinessSimulation/Converters/Product_2.mo new file mode 100644 index 0000000..5075ca6 --- /dev/null +++ b/BusinessSimulation/Converters/Product_2.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Converters; + +block Product_2 "Inputs are multiplied" + extends Interfaces.PartialConverters.SI2SO; +equation + y = u1 * u2; + annotation(Documentation(info = " +
This information is part of the Business Simulation Library (BSL).
+The output y is the product of inputs u1 and u2.
+This information is part of the Business Simulation Library (BSL).
+The output y is the product of the inputs u1, u2, and u3.
+This information is part of the Business Simulation Library (BSL).
+The output y is derived from converting the input u assumed to be given as a rate in units of timeBaseA
to a rate given in units of timeBaseB
.
The best way to work with time in Modelica is to use the SIunit [s
] for all internal representations and calculations while making use of displayUnit
to convert input and output to and from s
to another unit of time preferred by the modeler. That way models will be compatible with models from other domains.
Nevertheless, there may be use cases where within the model working with other timeBases will be necessary. Thus there may be need to convert from one time base to another which this converter fulfills.
+This information is part of the Business Simulation Library (BSL).
+The input u will be rescaled to run from y_min
to y_max
over the range u_min
to u_max
to obtain the output y.
y = Functions.rescale( x, {u_min,u_max}, {y_min, y_max});+
This information is part of the Business Simulation Library (BSL).
+This component allows to easily set up a model for either gaming = true
(e.g. the user has to provide an input u_User
that is then used in the model) or as a regular model (e.g. the model provides the input u that can be used if gaming = false
).
The input u_User
is conditional upon the global boolean parameter gaming
. If there are to be corresponding user inputs at the top level of a model, then these should be connected to the appropriate u_User
inputs of GameInput
components at deeper levels. These top level inputs should then also be made conditional, so that the model will be balanced for the case gaming = false
as well.
This information is part of the Business Simulation Library (BSL).
+The component will set up the following assert
functions:
assert(u <= maxValue, \"Value out of range (too high)\", level = AssertionLevel.error);+
assert(u >= minValue, \"Value out of range (too low)\", level = AssertionLevel.error);
This information is part of the Business Simulation Library (BSL).
+The component will set up the following assert
functions:
assert(u <= u_max, \"Value out of range (too high)\", level = AssertionLevel.error);+
assert(u >= u_min, \"Value out of range (too low)\", level = AssertionLevel.error);
This information is part of the Business Simulation Library (BSL).
+This package contains converters that are more or less technical.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y is derived from converting the input u assumed to be given in units of timeBaseA
to timeBaseB
.
The best way to work with time in Modelica is to use the SIunit [s
] for all internal representations and calculations while making use of displayUnit
to convert input and output to and from s
to another unit of time preferred by the modeler. That way models will be compatible with models from other domains.
Nevertheless, there may be use cases where within the model working with other timeBases will be necessary. Thus there may be need to convert from one time base to another which this converter fulfills.
+This information is part of the Business Simulation Library (BSL).
+The scalar output y is obtained as a convex combination of the components of the input vector u:
+ +useWeights = false
then all weights are assumed to be one.+arithmeticMean, +GeometricMean +
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "MEAN", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -20}, textColor = {128, 128, 128}, extent = {{-43.883, -9}, {43.883, 9}}, textString = "Arithmetic", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ArithmeticMean; diff --git a/BusinessSimulation/Converters/Vector/Clip.mo b/BusinessSimulation/Converters/Vector/Clip.mo new file mode 100644 index 0000000..b8980d7 --- /dev/null +++ b/BusinessSimulation/Converters/Vector/Clip.mo @@ -0,0 +1,15 @@ +within BusinessSimulation.Converters.Vector; + +block Clip "Clips input vector so that all components remain within a given interval" + import BusinessSimulation.Constants.inf; + extends Interfaces.PartialConverters.MIMO_nin; + parameter Real minValue = -inf "Minimum value (default = - infinity)"; + parameter Real maxValue = inf "Maximum value (default = infinity)"; +algorithm + y := Functions.clip(u, {minValue, maxValue}); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The input vector u will be clipped to make sure that its components remain within the interval [minValue, maxValue]
before it is given as output vector y having the same dimensions.
This information is part of the Business Simulation Library (BSL).
+The vector output y is obtained by adding another element y_comp to the list of inputs so that the total is 1. If the sum of the inputs is larger than one, then the element added to the list of inputs will be zero.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {16.393, 0}, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "= 1", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-22, 6}, textColor = {0, 0, 128}, extent = {{-22.881, -36.024}, {22.881, 36.024}}, textString = "∑", fontName = "Lato", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ComplementFractions; diff --git a/BusinessSimulation/Converters/Vector/ConstantConverter.mo b/BusinessSimulation/Converters/Vector/ConstantConverter.mo new file mode 100644 index 0000000..38b965f --- /dev/null +++ b/BusinessSimulation/Converters/Vector/ConstantConverter.mo @@ -0,0 +1,19 @@ +within BusinessSimulation.Converters.Vector; + +block ConstantConverter "A list of constant values is turned into a constant vector of signals" + extends Icons.ConstantConverter; + extends Interfaces.Basics.OutputTypeChoice; + RealMultiOutput[size(value, 1)] y annotation(Placement(visible = true, transformation(origin = {152.114, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter OutputType[:] value = {0} "List of constant values"; +equation + y = value; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The parameter value
(a vector) is used to set the continous output y making it a vector of constant-valued signals.
displayUnit
for entering vectors. Nevessary conversions have thus to be made before entering a value that needs to reflect the assigned unit
for the chosen OutputType
.ConstantConverter, ConstantConverterRate, ConstantConverterTime, ConstantConverterBoolean
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 60}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value", fontName = "Lato")})); +end ConstantConverter; diff --git a/BusinessSimulation/Converters/Vector/ConstantConverterRate.mo b/BusinessSimulation/Converters/Vector/ConstantConverterRate.mo new file mode 100644 index 0000000..1b6f8b0 --- /dev/null +++ b/BusinessSimulation/Converters/Vector/ConstantConverterRate.mo @@ -0,0 +1,32 @@ +within BusinessSimulation.Converters.Vector; + +block ConstantConverterRate "A list of constant rates is turned into a vector of rate signals" + import BusinessSimulation.Types.TimeBases; + import BusinessSimulation.Units.{Rate,Dimensionless}; + extends Icons.ConstantConverter; + extends Interfaces.Basics.OutputTypeChoice_Rate; + RealMultiOutput[nout] y annotation(Placement(visible = true, transformation(origin = {151.657, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Real[:] value = {0} "Vector of constant rates given in the unit pertaining to OutputType [y.unit * s] per time base"; + parameter String timeBaseString = "second" "Time base of the rates entered (default = per second)" annotation(choices(choice = "second", choice = "minute", choice = "hour", choice = "day", choice = "week", choice = "month", choice = "quarter", choice = "year")); +protected + parameter Integer nout = size(value, 1) "Length of the vector" annotation(Evaluate = true, Dialog(tab = "Initialization", enable = false)); + parameter TimeBases timeBase = Functions.stringToTimeBase(timeBaseString) "Element of the enumeration TimeBases corresponding to the timeBase given as string" annotation(Dialog(tab = "Initialization", enable = false)); + RateConversion[nout] convertRate(each timeBaseA = timeBase, each timeBaseB = TimeBases.seconds) "Convert the rate input to a rate per seconds" annotation(Placement(visible = true, transformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + ConstantConverter ratesInTimeBase(value = value) annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(convertRate.y, y) annotation(Line(visible = true, origin = {119.829, 0}, points = {{-31.829, 0}, {31.829, -0}}, color = {1, 37, 163})); + connect(ratesInTimeBase.y, convertRate.u) annotation(Line(visible = true, origin = {39, 0}, points = {{-33, 0}, {33, 0}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The parameter value
(a vector) is used to set the continous output y making it a vector of constant-valued signals. The output will always give rates per second, but rates can be entered in non-SI-units of time using the parameter timeBaseString
.
OutputType = Rate
the entered rates will be fractional rates (1 per unit of time
).displayUnit
for entering vectors. Nevessary conversions have thus to be made before: Any value entered should have unit = y.unit * s/time base
, so that the converted values will have unit = y.unit
.Given OutputType = Units.VolumeFlowRate, value = {1,2,3}, timeBase = \"minute\"
will result in the output y = {0.0166 [m3/s], 0.0333 [m3/s], 0.05 [m3/s]}
.
+
ConstantConverter, ConstantConverterTime
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 60}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value per %timeBaseString", fontName = "Lato")})); +end ConstantConverterRate; diff --git a/BusinessSimulation/Converters/Vector/ConstantConverterTime.mo b/BusinessSimulation/Converters/Vector/ConstantConverterTime.mo new file mode 100644 index 0000000..03686ab --- /dev/null +++ b/BusinessSimulation/Converters/Vector/ConstantConverterTime.mo @@ -0,0 +1,25 @@ +within BusinessSimulation.Converters.Vector; + +block ConstantConverterTime "A list of constant time values is turned into a vector of constant time signals" + import BusinessSimulation.Units.Time; + import BusinessSimulation.Types.TimeBases; + extends Icons.ConstantConverter; + extends Interfaces.Basics.OutputTypeChoice_Time(redeclare final type OutputType = Time); + RealMultiOutput[nout] y annotation(Placement(visible = true, transformation(origin = {151.87, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Real[:] value = {0} "List of constant time values"; + parameter String unitTime = "s" "Unit of time for the values entered (default = 's')" annotation(choices(choice = "s", choice = "m", choice = "h", choice = "d", choice = "wk", choice = "mo", choice = "qtr", choice = "yr")); +protected + parameter Integer nout = size(value, 1) "Length of vector" annotation(Evaluate = true, Dialog(tab = "Initialization", enable = false)); + parameter TimeBases timeBase = Functions.stringToTimeBase(unitTime) "Element of the enumeration TimeBases corresponding to the unit of time given as string" annotation(Dialog(tab = "Initialization", enable = false)); + ConstantConverter timesInUnitTime(value = value) annotation(Placement(visible = true, transformation(origin = {-0, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + TimeConversion[nout] convertTime(each timeBaseA = timeBase, each timeBaseB = TimeBases.seconds) "Convert the time input to seconds" annotation(Placement(visible = true, transformation(origin = {70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(convertTime.y, y) annotation(Line(visible = true, origin = {114.935, 0}, points = {{-36.935, 0}, {36.935, -0}}, color = {1, 37, 163})); + connect(timesInUnitTime.y, convertTime.u) annotation(Line(visible = true, origin = {34, -0}, points = {{-28, -0}, {28, 0}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The parameter value
(a vector) is used to set the continous output y making it a vector of constant-valued signals. The output will always give times in seconds [s]
, but values can be entered in non-SI-units of time using the parameter unitTime
.
ConstantConverter, ConstantConverterRate
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 60}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value %unitTime", fontName = "Lato")})); +end ConstantConverterTime; diff --git a/BusinessSimulation/Converters/Vector/DotProduct.mo b/BusinessSimulation/Converters/Vector/DotProduct.mo new file mode 100644 index 0000000..e5acc4a --- /dev/null +++ b/BusinessSimulation/Converters/Vector/DotProduct.mo @@ -0,0 +1,20 @@ +within BusinessSimulation.Converters.Vector; + +block DotProduct "Dot product of two vectors of equal length" + extends Interfaces.PartialConverters.SO; + parameter Integer nin(min = 2) = 2 "Elements in the input vectors (length)" annotation(Dialog(group = "Structural Parameters")); + Interfaces.Connectors.RealMultiInput[nin] u1 "Input vector 1" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80.378, 50.378}, extent = {{-10.378, -10.378}, {10.378, 10.378}}, rotation = 0))); + Interfaces.Connectors.RealMultiInput[nin] u2 "Input vector 2" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80.378, -50.378}, extent = {{-10.378, -10.378}, {10.378, 10.378}}, rotation = 0))); + Times times(nin = nin) annotation(Placement(visible = true, transformation(origin = {-27.609, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Total total(nin = nin) annotation(Placement(visible = true, transformation(origin = {27.609, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(u1, times.u1) annotation(Line(visible = true, origin = {-76.412, 22.519}, points = {{-68.588, 17.481}, {16.412, 17.481}, {16.412, -17.481}, {40.841, -17.557}}, color = {0, 0, 127})); + connect(u2, times.u2) annotation(Line(visible = true, origin = {-76.412, -22.519}, points = {{-68.588, -17.481}, {16.412, -17.481}, {16.412, 17.481}, {40.841, 17.481}}, color = {0, 0, 127})); + connect(times.y, total.u) annotation(Line(visible = true, origin = {-0.006, 0}, points = {{-20.24, 0}, {20.24, 0}}, color = {0, 0, 127})); + connect(y, total.y) annotation(Line(visible = true, origin = {97.486, 0}, points = {{62.514, 0}, {-62.514, 0}}, color = {0, 0, 127})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is the dot product of the input vectors u1 and u2 which have the same length nin
.
The dot product is defined as follows:
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "Dot", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end DotProduct; diff --git a/BusinessSimulation/Converters/Vector/GeometricMean.mo b/BusinessSimulation/Converters/Vector/GeometricMean.mo new file mode 100644 index 0000000..8399841 --- /dev/null +++ b/BusinessSimulation/Converters/Vector/GeometricMean.mo @@ -0,0 +1,32 @@ +within BusinessSimulation.Converters.Vector; + +block GeometricMean "(Weighted) geometric mean" + extends Interfaces.PartialConverters.MISO; + parameter Real[nin] weights = ones(nin) "Weights to be used for inputs" annotation(Dialog(enable = useWeights and hasConstantWeights)); + parameter Boolean useWeights = false "= true, if the output is to be a weighted geometric mean" annotation(Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantWeights = true "= true, if the weights are constant" annotation(Dialog(group = "Structural Parameters", enable = useWeights)); + Interfaces.Connectors.RealMultiInput u_weights[nin] if useWeights and not hasConstantWeights "Input of weights" annotation(Placement(visible = true, transformation(origin = {-145, 35}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 80}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); +protected + Interfaces.Connectors.RealMultiInput[nin] constWeights = weights if not useWeights or hasConstantWeights; + Interfaces.Connectors.RealMultiOutput[nin] w; +equation + connect(constWeights, w); + connect(u_weights, w); + y = Functions.geometricMean(u, w); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The scalar output y is obtained as the geometric mean of the components of the input vector u. Optionally weights can be given, either as constants (weights
) or as variable inputs (u_weights
).
useWeights = false
then all weights are assumed to be one.+geometricMean, +ArithmeticMean
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "MEAN", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -20}, textColor = {128, 128, 128}, extent = {{-40.484, -9}, {40.484, 9}}, textString = "Geometric", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end GeometricMean; diff --git a/BusinessSimulation/Converters/Vector/Max.mo b/BusinessSimulation/Converters/Vector/Max.mo new file mode 100644 index 0000000..769fa65 --- /dev/null +++ b/BusinessSimulation/Converters/Vector/Max.mo @@ -0,0 +1,10 @@ +within BusinessSimulation.Converters.Vector; + +block Max "Max function for vectors" + extends Interfaces.PartialConverters.MISO; +equation + y = max(u); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The scalar output y is obtained as the maximum of all components in the input vector u.
", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "MAX", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Max; diff --git a/BusinessSimulation/Converters/Vector/Min.mo b/BusinessSimulation/Converters/Vector/Min.mo new file mode 100644 index 0000000..fa44c8f --- /dev/null +++ b/BusinessSimulation/Converters/Vector/Min.mo @@ -0,0 +1,10 @@ +within BusinessSimulation.Converters.Vector; + +block Min "Min function for vectors" + extends Interfaces.PartialConverters.MISO; +equation + y = min(u); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The scalar output y is obtained as the minimum of all components in the input vector u.
", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-40.484, -12}, {40.484, 12}}, textString = "MIN", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Min; diff --git a/BusinessSimulation/Converters/Vector/Product.mo b/BusinessSimulation/Converters/Vector/Product.mo new file mode 100644 index 0000000..9aae976 --- /dev/null +++ b/BusinessSimulation/Converters/Vector/Product.mo @@ -0,0 +1,14 @@ +within BusinessSimulation.Converters.Vector; + +block Product "Gives the product of all components of the input vector" + extends Interfaces.PartialConverters.MISO; +equation + y = product(u); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is derived as a multiplication of n inputs u given as an vector:
+ +This information is part of the Business Simulation Library (BSL).
+Given a vector u of weights, the converter will give an output vector y of fractions so that:
+ +If the weights do add up to zero equal proportions are assumed:
+ +shiftInputs = true
) or clipped (shiftInputs = false
), so that no weight will be less than zero.This information is part of the Business Simulation Library (BSL).
+The vector output y is obtained by rescaling all components of the input vector u to run from y_min
to y_max
over the range min
to max
.
Care has to be taken if enterInputRange = false
, as then a vector of identical values will cause division by zero.
Rescale, Functions.rescaleVector
", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-53.405, -12}, {53.405, 12}}, textString = "RESCALE", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Rescale; diff --git a/BusinessSimulation/Converters/Vector/ScalarMultiplication.mo b/BusinessSimulation/Converters/Vector/ScalarMultiplication.mo new file mode 100644 index 0000000..05ab6a4 --- /dev/null +++ b/BusinessSimulation/Converters/Vector/ScalarMultiplication.mo @@ -0,0 +1,17 @@ +within BusinessSimulation.Converters.Vector; + +block ScalarMultiplication "Multiplication of a vector with a scalar" + extends Interfaces.Basics.BaseConverter; + parameter Integer nin(min = 2) = 2 "Length of input vector" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + Interfaces.Connectors.RealMultiInput[nin] u1 "Input vector of length nin" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80.378, 49.622}, extent = {{-10.378, -10.378}, {10.378, 10.378}}, rotation = 0))); + Interfaces.Connectors.RealInput u2 "Input of scalar value" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80.378, -49.622}, extent = {{-10.378, -10.378}, {10.378, 10.378}}, rotation = 0))); + RealMultiOutput y[nin] "Output vector" annotation(Placement(visible = true, transformation(origin = {150, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {75, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + y = u1 * u2; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output vector y is obtained by multiplying the input vector u1 with the scalar input u2:
+ +The vectors y and u1 will have the same length nin
.
This information is part of the Business Simulation Library (BSL).
+The output vector y is the sum of the input vectors u1 and u2, which need to have length nin:
This information is part of the Business Simulation Library (BSL).
+The output vector y is obtained by elementwise multiplication of the input vectors u1 and u2, which need to have the same length nin:
+ +"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, points = {{15, 15}, {-15, -15}}, color = {0, 0, 128}, thickness = 4, arrowSize = 0), Line(visible = true, rotation = -270, points = {{15, 15}, {-15, -15}}, color = {0, 0, 128}, thickness = 4, arrowSize = 0)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Times; diff --git a/BusinessSimulation/Converters/Vector/Total.mo b/BusinessSimulation/Converters/Vector/Total.mo new file mode 100644 index 0000000..7c546a6 --- /dev/null +++ b/BusinessSimulation/Converters/Vector/Total.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Converters.Vector; + +block Total "Gives the sum over all components of a vector" + extends Interfaces.PartialConverters.MISO; +equation + y = sum(u); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The scalar output y is obtained by adding all components of the input vector u:
+ +"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {-2, 6}, textColor = {0, 0, 128}, extent = {{-22.881, -36.024}, {22.881, 36.024}}, textString = "∑", fontName = "Lato", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Total; diff --git a/BusinessSimulation/Converters/Vector/package.mo b/BusinessSimulation/Converters/Vector/package.mo new file mode 100644 index 0000000..ff0c7ef --- /dev/null +++ b/BusinessSimulation/Converters/Vector/package.mo @@ -0,0 +1,14 @@ +within BusinessSimulation.Converters; + +package Vector "Converters with vector input and/or vector output" + extends Icons.Package; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package ontains converters where either input or output or both can be vectors of a given dimension.
+There is currently no support in Wolfram SystemModeler for flexible array sizes (\":
\") for connectors used with blocks. Therefore the actual size of array inputs has to be given as a parameter upon instantiating a converter in a model.
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y will be identical with the input u whenever u is greater than or equal to zero. It will be zero in all other cases.
+In the default setting (strict = false
) in the Advanced tab, nonnegativity will be strictly ovserved:
if strict then + y = smooth(0, noEvent(if u < 0 then 0 else u)); + else + y = smooth(0, if u < 0 then 0 else u); + end if;+
This information is part of the Business Simulation Library (BSL).
+This library contains input/output blocks (converters): One or more information inputs are (instantaneously) transformed by some function given one or more outputs.
++Tutorial.ElementaryBuildingBlocks +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Usually in System Dynamics modeling we take the \"high road\" of a macro-level, strategic view on business systems and accordingly we will very often be content with modeling a production line using a →DelayN where production time is distributed around some mean duration. In this example we take a meso-level perspective of modeling a simple assembly line that borders on discrete-event modeling—albeit not yet focussing single entities.
+In modeling an assembly line we here use SimpleConveyor and Oven being dynamical stocks with inherent (hidden) dynamics: The SimpleConveyor is like a conveyor belt, that transports stuff from one stock to another using a fixed, exact amount of time. The Oven represents an idealized batch process, where a processor is loaded, then closes its doors to process the loaded material in a fixed amount of time, to then unload it into the next stage.
+The example is taken from Peter Junglas [18, pp. 247-252].
+")); +end AssemblyLine; diff --git a/BusinessSimulation/Examples/LookupFunctions.mo b/BusinessSimulation/Examples/LookupFunctions.mo new file mode 100644 index 0000000..cd94d0d --- /dev/null +++ b/BusinessSimulation/Examples/LookupFunctions.mo @@ -0,0 +1,62 @@ +within BusinessSimulation.Examples; + +model LookupFunctions "Demonstration of lookup-functions" + extends Icons.Example; + ModelOutput modelOutput "The main model output" annotation(Placement(visible = true, transformation(origin = {120, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80.808, -6.712}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Real slope1To50(min = 1, max = 50) = 2 "Slope parameter (general)"; + parameter Real slope(min = 0) = slope1To50 "Determines the gradient of the curve (Janoschek and S-Shaped)"; + parameter Real slopeUpTo1(min = 0, max = 1) = 0.5 "Slope parameter (0< slope <= 1) (concaveLookupPosisitve)"; + parameter Real interceptUpward(min = 0, max = 1) = 0. "Value of y when input is zero or less (y0) for upward sloping functions"; + parameter Real interceptDownward(min = 1) = 2. "Value of y when input is zero or less (y0) for downward sloping functions"; + parameter Real upperBound = 2 "Upper asymptote for u <= 0 (upperBound > lowerBound) (Janoschek and S-Shaped)"; + parameter Real lowerBound = 0 "Lower asymptote for u -> infinity (Janoschek)"; + parameter Real x_ref(min = 0) = 1 "x-value for point of inflection(>0) (Janoschek)"; + parameter Real y_ref = 1 "y-value for point of inflection(lowerBound < y_ref < upperBound) (Janoschek)"; + parameter Real table[:, :] = {{0, 0}, {2, 4}, {4, 6}, {6, 8}} "Table matrix (grid = first column; e.g., table=[0,2]) (combiTable1D.table) (tableFunction.table)"; + parameter Modelica.Blocks.Types.Smoothness smoothness = Modelica.Blocks.Types.Smoothness.LinearSegments "Smoothness of table interpolation (tableFunction.smoothness)"; + parameter Modelica.Blocks.Types.Extrapolation extrapolation = Modelica.Blocks.Types.Extrapolation.HoldLastPoint "Extrapolation of data outside the definition range (combiTable.extrapolation) (tableFunction.extrapolation)"; + inner ModelSettings modelSettings(modelTimeHorizon = 10) annotation(Placement(visible = true, transformation(origin = {-110, -75}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + InformationSources.RampInput '0..10'(height = 10, duration = 10, offset = 0, startTime = 0) "Ramp from 0 to 10 in 10 units of time" annotation(Placement(visible = true, transformation(origin = {-110, 10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + InformationSources.RampInput '-5..5'(offset = -5, height = 10, duration = 10) "Ramp from -5 to 5 in 10 units of time" annotation(Placement(visible = true, transformation(origin = {10, 10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + expandable connector ModelOutput "Main Output" + extends Icons.DataOutPort; + end ModelOutput; +protected + Converters.Lookup.ConcaveLookupNegative concaveLookupNegative(s = slope1To50, y0 = interceptDownward) annotation(Placement(visible = true, transformation(origin = {-50, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.ConcaveLookupPositive concaveLookupPositive(s = slopeUpTo1, y0 = interceptUpward) annotation(Placement(visible = true, transformation(origin = {-50, 55}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.ConvexLookupNegative convexLookupNegative(y0 = interceptDownward) annotation(Placement(visible = true, transformation(origin = {-50, 25}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.ConvexLookupPositive convexLookupPositive(s = slope1To50, y0 = interceptUpward) annotation(Placement(visible = true, transformation(origin = {-50, -5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.JanoschekNegative janoschek_negative_x_y(growthRate = slope, x_ref = x_ref, y_ref = y_ref, lowerBound = lowerBound, upperBound = upperBound) annotation(Placement(visible = true, transformation(origin = {-50, -35}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.JanoschekPositive janoschek_positive_x_y(lowerBound = lowerBound, upperBound = upperBound, growthRate = slope, x_ref = x_ref, y_ref = y_ref) annotation(Placement(visible = true, transformation(origin = {-50, -65}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.SShapedNegative sShapedNegative_origin(s = slope, upperBound = upperBound) annotation(Placement(visible = true, transformation(origin = {70, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.SShapedPositive sShapedPositive_origin(s = slope, upperBound = upperBound) annotation(Placement(visible = true, transformation(origin = {70, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Lookup.TableFunction tableFunction(table = table, tableOnFile = false, extrapolation = extrapolation, smoothness = smoothness) annotation(Placement(visible = true, transformation(origin = {-50, -90}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect('0..10'.y, concaveLookupPositive.u) annotation(Line(visible = true, origin = {-71.503, 32.5}, points = {{-30.497, -22.5}, {-8.497, -22.5}, {-8.497, 22.5}, {13.503, 22.5}}, color = {0, 0, 127})); + connect('0..10'.y, convexLookupNegative.u) annotation(Line(visible = true, origin = {-71.503, 17.5}, points = {{-30.497, -7.5}, {-8.497, -7.5}, {-8.497, 7.5}, {13.503, 7.5}}, color = {0, 0, 127})); + connect('0..10'.y, janoschek_positive_x_y.u) annotation(Line(visible = true, origin = {-71.503, -27.5}, points = {{-30.497, 37.5}, {-8.497, 37.5}, {-8.497, -37.5}, {13.503, -37.5}}, color = {0, 0, 127})); + connect('0..10'.y, convexLookupPositive.u) annotation(Line(visible = true, origin = {-71.503, 2.5}, points = {{-30.497, 7.5}, {-8.497, 7.5}, {-8.497, -7.5}, {13.503, -7.5}}, color = {0, 0, 127})); + connect('0..10'.y, janoschek_negative_x_y.u) annotation(Line(visible = true, origin = {-71.503, -12.5}, points = {{-30.497, 22.5}, {-8.497, 22.5}, {-8.497, -22.5}, {13.503, -22.5}}, color = {0, 0, 127})); + connect('-5..5'.y, sShapedNegative_origin.u) annotation(Line(visible = true, origin = {29.997, 20}, points = {{-11.997, -10}, {10.003, -10}, {10.003, 10}, {32.003, 10}}, color = {0, 0, 127})); + connect('-5..5'.y, sShapedPositive_origin.u) annotation(Line(visible = true, origin = {39.997, 0}, points = {{-21.997, 10}, {0.003, 10}, {0.003, -10}, {22.003, -10}}, color = {0, 0, 127})); + connect('0..10'.y, tableFunction.u) annotation(Line(visible = true, origin = {-87.117, -40}, points = {{-14.883, 50}, {7.117, 50}, {7.117, -50}, {29.117, -50}}, color = {1, 37, 163})); + connect('0..10'.y, concaveLookupNegative.u) annotation(Line(visible = true, origin = {-80, 45}, points = {{-22, -35}, {0, -35}, {0, 35}, {22, 35}}, color = {1, 37, 163})); + connect(concaveLookupNegative.y, modelOutput.concaveLookupNegative) annotation(Line(visible = true, origin = {9.5, 20}, points = {{-51.5, 60}, {-29.5, 60}, {-29.5, -60}, {110.5, -60}}, color = {192, 192, 192})); + connect(concaveLookupPositive.y, modelOutput.concaveLookupPositive) annotation(Line(visible = true, origin = {9.5, 7.5}, points = {{-51.5, 47.5}, {-29.5, 47.5}, {-29.5, -47.5}, {110.5, -47.5}}, color = {192, 192, 192})); + connect(convexLookupNegative.y, modelOutput.convexLookupNegative) annotation(Line(visible = true, origin = {9.5, -7.5}, points = {{-51.5, 32.5}, {-29.5, 32.5}, {-29.5, -32.5}, {110.5, -32.5}}, color = {192, 192, 192})); + connect(convexLookupPositive.y, modelOutput.convexLookupPositive) annotation(Line(visible = true, origin = {9.5, -22.5}, points = {{-51.5, 17.5}, {-29.5, 17.5}, {-29.5, -17.5}, {110.5, -17.5}}, color = {192, 192, 192})); + connect(janoschek_negative_x_y.y, modelOutput.janoschekNegative) annotation(Line(visible = true, origin = {9.5, -37.5}, points = {{-51.5, 2.5}, {-29.5, 2.5}, {-29.5, -2.5}, {110.5, -2.5}}, color = {192, 192, 192})); + connect(janoschek_positive_x_y.y, modelOutput.janoschekPositive) annotation(Line(visible = true, origin = {9.919, -52.5}, points = {{-51.919, -12.5}, {-29.919, -12.5}, {-29.919, 12.5}, {110.081, 12.5}}, color = {192, 192, 192})); + connect(tableFunction.y, modelOutput.tableFunction) annotation(Line(visible = true, origin = {9.5, -65}, points = {{-51.5, -25}, {-29.5, -25}, {-29.5, 25}, {110.5, 25}}, color = {192, 192, 192})); + connect(sShapedNegative_origin.y, modelOutput.sShapedNegative) annotation(Line(visible = true, origin = {99.5, -5}, points = {{-21.5, 35}, {0.5, 35}, {0.5, -35}, {20.5, -35}}, color = {192, 192, 192})); + connect(sShapedPositive_origin.y, modelOutput.sShapedPositive) annotation(Line(visible = true, origin = {99.5, -25}, points = {{-21.5, 15}, {0.5, 15}, {0.5, -15}, {20.5, -15}}, color = {192, 192, 192})); + annotation(__Wolfram(PlotSet(plots = {Plot(name = "Concave Lookup", identifier = "concave", caption = "Concave lookup with positive and negative slopes.", subPlots = {SubPlot(title = "Negative", identifier = "neg", curves = {Curve(x = time, y = modelOutput.concaveLookupNegative)}), SubPlot(title = "Positive", identifier = "pos", curves = {Curve(x = time, y = modelOutput.concaveLookupPositive)})}), Plot(name = "Convex Lookup", identifier = "convex", caption = "Convex lookups with positive and negative slopes.", subPlots = {SubPlot(title = "Negative", identifier = "neg", curves = {Curve(x = time, y = modelOutput.convexLookupNegative)}), SubPlot(curves = {Curve(x = time, y = modelOutput.convexLookupPositive)})}), Plot(name = "Table Function", identifier = "table", caption = "Classical table function lookup.", subPlots = {SubPlot(curves = {Curve(x = time, y = modelOutput.tableFunction)})}), Plot(name = "Janosckek's Growth Function", identifier = "janoschek", caption = "Janoschek's growth function with positive and negative slopes.", subPlots = {SubPlot(title = "Positive", identifier = "pos", curves = {Curve(x = time, y = modelOutput.janoschekPositive)}), SubPlot(title = "Negative", identifier = "neg", curves = {Curve(x = time, y = modelOutput.janoschekNegative)})}), Plot(name = "S-shaped Lookup", identifier = "sshaped", caption = "S-shaped Lookup with positive and negative slope", subPlots = {SubPlot(title = "Positive", identifier = "pos", curves = {Curve(x = '-5..5'.y, y = modelOutput.sShapedPositive)}), SubPlot(title = "Negative", identifier = "neg", curves = {Curve(x = '-5..5'.y, y = modelOutput.sShapedNegative)})})})), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This example demonstrates the use of parametric and table functions in models and may serve as a little \"sandbox\". While table functions are still frequently used, the advantage of parametric functions is their smoothness—at least in the relevant range—and the better calibration/identification options.
+This information is part of the Business Simulation Library (BSL).
+This model extends the two species model given in the example →LotkaVolterraSystems by introducing a third species: wolves. Wolves predate on both, rabbits and foxes.
+We can immediately extend the model for two species by introducing another material stock for wolves. As predators wolves
will also be connected to a process of exponential decline (e.g. starvation in absence of prey). Since wolves
predate on rabbits
and foxes
, there will be two nonlinear interactions between the stock of wolves
and the other stocks. As before, the predator side (portB
) of the NonlinearInteraction
flow will be connected to the inflow
port for wolves
, while the prey side (portA
) will be connected to the outflow
port of rabbits
and foxes
.
+ |
init = InitializationOptions.SteadyState
in the Advanced tab for modelSettings
allows us to find the equilibrium levels for the three populations.model
to collect global parameters: theta
. Doing so is quite convenient for more complex models (where we will often choose to additionally assign the inner
prefix), as we can set up the model as a component of its own and then simply modify an instance of it to arrive at a scenario run.theta
in the diagram we can then set all parameters in the General
or in the Parameters
tab in SystemModeler.The model presented here comes from Michael Tiller's excellent introduction \"Modelica by Example\" (see Object-Oriented Modeling>Components>Examples>Lotka-Volterra Equations Revisited), which ships with SystemModeler and can also be found online.
+LotkaVolterraSystems, +Tutorial.UnitsInBusinessSimulations
+")); +end LotkaVolterraEquationsRevisited; diff --git a/BusinessSimulation/Examples/LotkaVolterraSystems.mo b/BusinessSimulation/Examples/LotkaVolterraSystems.mo new file mode 100644 index 0000000..4cfced8 --- /dev/null +++ b/BusinessSimulation/Examples/LotkaVolterraSystems.mo @@ -0,0 +1,68 @@ +within BusinessSimulation.Examples; + +model LotkaVolterraSystems "Predator-prey dynamics" + import BusinessSimulation.Units.Rate; + extends Icons.Example; + ModelOutput modelOutput "Main output of the model" annotation(Placement(visible = true, transformation(origin = {130, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {90, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Rate alpha(displayUnit = "1/yr") = 3.17097919837646e-9 "Reproduction rate of prey"; + parameter Rate beta(displayUnit = "1/yr") = 6.34195839675292e-10 "Mortality rate of prey per predator"; + parameter Rate gamma(displayUnit = "1/yr") = 1.26839167935058e-8 "Mortality rate of predator"; + parameter Rate delta(displayUnit = "1/yr") = 6.34195839675292e-10 "Reproduction rate of predators per prey"; + inner ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.years, dt(displayUnit = "yr") = 7884000, modelTimeHorizon(displayUnit = "yr") = 3153600000) annotation(Placement(visible = true, transformation(origin = {-135, -75}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + expandable connector ModelOutput + extends Icons.DataOutPort; + import BusinessSimulation.Units.Population; + Population rabbits(unit = "rabbits") "Rabbit population"; + Population foxes(unit = "foxes") "Fox population"; + Population prey "Prey population"; + Population predators "Predator population"; + end ModelOutput; +protected + Stocks.MaterialStock prey(initialValue = 10, init = BusinessSimulation.Types.InitializationOptions.FixedValue, redeclare replaceable type OutputType = Units.Population) annotation(Placement(visible = true, transformation(origin = {-50, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.MaterialStock predators(initialValue = 10, init = BusinessSimulation.Types.InitializationOptions.FixedValue, redeclare replaceable type OutputType = Units.Population) annotation(Placement(visible = true, transformation(origin = {30, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.MaterialStock rabbits(initialValue = 10, init = BusinessSimulation.Types.InitializationOptions.FixedValue, redeclare replaceable type OutputType = Units.Population(unit = "rabbits")) annotation(Placement(visible = true, transformation(origin = {-50, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.MaterialStock foxes(initialValue = 10, init = BusinessSimulation.Types.InitializationOptions.FixedValue, redeclare replaceable type OutputType = Units.Population(unit = "foxes")) annotation(Placement(visible = true, transformation(origin = {30, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExponentialGrowth reproducing(fractionalRate = alpha, hasConstantRate = true) annotation(Placement(visible = true, transformation(origin = {-90, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExponentialDecline starving(hasConstantRate = true, fractionalRate = gamma) "Foxes mortality in absense of prey" annotation(Placement(visible = true, transformation(origin = {70, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Flows.Interaction.NonlinearInteraction predation(hasConstantFactorA = true, hasConstantFactorB = true, a_AB = -beta, b_AB = delta) "Foxes predating on rabbits" annotation(Placement(visible = true, transformation(origin = {-10, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Interaction.LotkaVolterra predating(hasConstantAlpha = true, hasConstantBeta = true, hasConstantGamma = true, hasConstantDelta = true, alpha = alpha, beta = beta, delta = delta, gamma = gamma, redeclare replaceable type OutputType_A = Rate(unit = "individuals/s"), redeclare replaceable type OutputType_B = Rate(unit = "individuals/s")) annotation(Placement(visible = true, transformation(origin = {-10, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(prey.outflow, predating.portA) annotation(Line(visible = true, origin = {-30, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(predating.portB, predators.inflow) annotation(Line(visible = true, origin = {10, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(reproducing.massPort, rabbits.inflow) annotation(Line(visible = true, origin = {-70, 30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(rabbits.outflow, predation.portA) annotation(Line(visible = true, origin = {-30, 30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(predation.portB, foxes.inflow) annotation(Line(visible = true, origin = {10, 30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(foxes.outflow, starving.massPort) annotation(Line(visible = true, origin = {50, 30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(rabbits.y2, modelOutput.rabbits) annotation(Line(visible = true, origin = {-19.685, -20}, points = {{-40.815, 45}, {-50.315, 45}, {-50.315, -40}, {149.685, -40}}, color = {192, 192, 192})); + connect(prey.y1, modelOutput.prey) annotation(Line(visible = true, origin = {7.625, -47.5}, points = {{-47.125, 12.5}, {-37.625, 12.5}, {-37.625, -12.5}, {122.375, -12.5}}, color = {192, 192, 192})); + connect(predators.y1, modelOutput.predators) annotation(Line(visible = true, origin = {67.625, -47.5}, points = {{-27.125, 12.5}, {-17.625, 12.5}, {-17.625, -12.5}, {62.375, -12.5}}, color = {192, 192, 192})); + connect(foxes.y1, modelOutput.foxes) annotation(Line(visible = true, origin = {70.125, -17.5}, points = {{-29.625, 42.5}, {-15.125, 42.5}, {-15.125, -42.5}, {59.875, -42.5}}, color = {192, 192, 192})); + annotation(experiment(StartTime = 0, StopTime = 3153600000, __Wolfram_DisplayTimeUnit = "yr"), __Wolfram(PlotSet(plots = {Plot(name = "Population Dynamics", identifier = "population-plot", preferred = true, caption = "Population dynamics for rabbits and foxes", subPlots = {SubPlot(curves = {Curve(x = time, y = modelOutput.foxes), Curve(x = time, y = modelOutput.rabbits)}, range = Range(xunit = "yr"))}), Plot(name = "Phase Plot", identifier = "phase-plot", caption = "In the phase plot the oscillatory behavior of the system manifests as an orbit around a focal point.", subPlots = {SubPlot(curves = {Curve(x = modelOutput.rabbits, y = modelOutput.foxes)})})})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {0, 80}, textColor = {76, 112, 136}, extent = {{-140, -6}, {140, 6}}, textString = "Lotka-Volterra Systems", fontName = "Lato Black"), Text(visible = true, origin = {0, 70}, textColor = {76, 112, 136}, extent = {{-140, -3}, {140, 3}}, textString = "Example given by Michael Tiller in 'Modelica by Example'", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {118.123, 11.585}, textColor = {76, 112, 136}, extent = {{-21.877, -6}, {21.877, 6}}, textString = "Explicit", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {118.123, -11.585}, textColor = {76, 112, 136}, extent = {{-21.877, -6}, {21.877, 6}}, textString = "Generic", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {46.667, 0}, points = {{-186.667, 0}, {93.333, 0}, {93.333, 0}}, color = {76, 112, 136}, thickness = 1)}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This is the basic two species model of predation from ecology—the so called Lotka-Volterra-Model [17].
+In the upper model we recognize more explicitly that both populations, rabbits and foxes, have independent processes of exponential growth (the prey population's net rate of growth) and exponential decline (the predator's net rate of negative growth when there is no prey). The predation is modeled using an an →interaction (a special kind of flow element). It introduces nonlinearity, as there is some fractional rate (beta, delta
) that is multiplied with rabbits(t) ⋅ foxes(t). Predation results in an outflow from the rabbit population (increased deaths) and an inflow to the prey population (increased reproduction).
The model below shows the same model structure in a generalized, more compact fashion using the interaction flow component →LotkaVolterra .
++ |
0.1 [1/yr]
using the displayUnit
attribute and conversion tables. All calculations in a simulation will always use SI-units for time so that rates are in unit 1/s
and times in unit s
.modelOutput
) where the variables rabbits, foxes, prey, predators
are explicitly declared with appropriate units.The model presented here comes from Michael Tiller's excellent introduction \"Modelica by Example\" (see Describing Behavior>Basic Equations>Examples>Lotka-Volterra System), which ships with SystemModeler and can also be found online.
+LotkaVolterra, NonlinearInteraction, ExponentialGrowth, ExponentialDecline
+")); +end LotkaVolterraSystems; diff --git a/BusinessSimulation/Examples/LoveHateDynamics.mo b/BusinessSimulation/Examples/LoveHateDynamics.mo new file mode 100644 index 0000000..bb5582d --- /dev/null +++ b/BusinessSimulation/Examples/LoveHateDynamics.mo @@ -0,0 +1,29 @@ +within BusinessSimulation.Examples; + +model LoveHateDynamics "Romeo and Juliet model as introduced by Strogatz" + extends Icons.Example; + Stocks.InformationLevel romeo(initialValue = romeoInitial) annotation(Placement(visible = true, transformation(origin = {-50, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.InformationLevel juliet(initialValue = julietInitial) annotation(Placement(visible = true, transformation(origin = {50, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Interaction.LinearInteraction loving(a_A = romeoIntrinsic, b_B = julietIntrinsic, a_B = romeoExtrinsic, b_A = julietExtrinsic, hasConstantGrowthRates = true, hasConstantFractionalGrowthRates = true, hasConstantCouplingCoefficients = true, a_0 = 0, b_0 = 0) "Interacting forces of love" annotation(Placement(visible = true, transformation(origin = {0.275, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Real romeoInitial = 1 "Initial level (should be different from 0 to find non-trivial steady state solution) (romeo.initialValue)"; + parameter Real julietInitial = 0 "Initial level (should be different from 0 to find non-trivial steady state solution) (juliet.initialValue)"; + parameter Units.Rate romeoIntrinsic = 0 "Gain for Romeo's feelings independent from Juliet"; + parameter Units.Rate julietIntrinsic = 0 "Gain for Juliet's feelings independent from Romeo"; + parameter Units.Rate romeoExtrinsic = -1 "Gain for Romeo's love aroused by Juliet"; + parameter Units.Rate julietExtrinsic = 1 "Gain for Juliet's love aroused by Romeo"; + inner ModelSettings modelSettings annotation(Placement(visible = true, transformation(origin = {-50, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(loving.portA, romeo.outflow) annotation(Line(visible = true, origin = {-24.863, -0}, points = {{15.138, 0}, {-15.137, -0}}, color = {128, 0, 128})); + connect(loving.portB, juliet.inflow) annotation(Line(visible = true, origin = {25.137, 0}, points = {{-14.862, -0}, {14.863, 0}}, color = {128, 0, 128})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Using the →LinearInteraction we can model Steven H. Strogatz' differential equation model for the dynamics in a love affair—conspiciously between Juliet and Romeo [.
+In his example—given in 1988—Strogatz described Romeo as a \"fickle\" lover who is turned off the more Juliet starts to warm up to him. On the other hand, the more Juliet dislikes him, the more he starts to approach Juliet. Juliet in comparison is a rather \"regular\" lover: The more Romeo loves her, the more she will love him and, conversely, the more he hates her, the more she hates him.
+To put this in mathematical form, we use stocks to account for Romeo's (reomeo
) and Juliet's feelings (reomeo
) at any time in the simulation. We define, that 1
is to describe the highest possible degree of love, while -1
is to express the highest possible degree of hate. Initially, Romeo is fully in love with Juliet (i.e.romeoInitial = 1
), while Juliet does not care about him (i.e.julietInitial = 1
).
The relationship's dynamics arise from coupled differential equations, which can be compactly expressed using an → Interaction flow. Using a bit of shorthand notation, the system is described more generally by the following equations:
+ +The change in the states for Romeo (R) and Juliet (J) depends upon coupling coefficients. Both lovers have an intrinsic and and extrinsic coupling coefficient. In our example, there is no intrinsic coupling (i.e. romeoIntrinsic = julietIntrinsic = 0
). The extrinsic coupling factors given according to the above description are: romeoExtrinsic = -1, julietExtrinsic = 1
:
Simulating the example quickly shows, why the technical term for this system is harmonic oscillator.
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {0, 80}, textColor = {76, 112, 136}, extent = {{-140, -6}, {140, 6}}, textString = "Dynamics of Love and Hate", fontName = "Lato Black")}), __Wolfram(PlotSet(plots = {Plot(name = "PhasePlot", identifier = "phaseplot", preferred = true, subPlots = {SubPlot(curves = {Curve(x = romeo.y, y = juliet.y)})}), Plot(name = "LoveDynamics", identifier = "timeseries", subPlots = {SubPlot(curves = {Curve(x = time, y = juliet.y), Curve(x = time, y = romeo.y)})})})), experiment(StartTime = 0, StopTime = 10)); +end LoveHateDynamics; diff --git a/BusinessSimulation/Examples/ManagingEmployment.mo b/BusinessSimulation/Examples/ManagingEmployment.mo new file mode 100644 index 0000000..00c5a89 --- /dev/null +++ b/BusinessSimulation/Examples/ManagingEmployment.mo @@ -0,0 +1,62 @@ +within BusinessSimulation.Examples; + +model ManagingEmployment "Human resource planning" + extends Icons.Example; + ModelOutput modelOutput "The model's main output" annotation(Placement(visible = true, transformation(origin = {120, -35}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {87.542, -1.783}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + inner ModelSettings modelSettings(gaming = true, lookupDataFileURI = "modelica://BusinessSimulation/Resources/SampleTable1D.txt", modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.years, modelTimeHorizon(displayUnit = "yr") = 315360000, dt(displayUnit = "yr") = 7884000) annotation(Placement(visible = true, transformation(origin = {-130, -82.855}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + expandable connector ModelOutput "The model's main output" + extends Icons.DataOutPort; + Units.Labor workforce "The workforce given as FTE"; + Units.Labor desiredWorkforce "The desired workforce"; + Units.Time_years experience "Average workexperience in the workforce"; + end ModelOutput; +protected + SourcesOrSinks.Growth hiring annotation(Placement(visible = true, transformation(origin = {-30, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.DelayN workforce(hasConstantDelayTime = false, hasStockInfoOutput = true, n = 3, redeclare replaceable type OutputType = Units.Labor, initialValue = 750) annotation(Placement(visible = true, transformation(origin = {10, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + MoleculesOfStructure.Policy.FirstOrderStockAdjustment recruitingPolicy(adjTime(displayUnit = "yr") = 15768000) "How many people are needed" annotation(Placement(visible = true, transformation(origin = {-60, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.HinesCoflow expertise(initialValue = 252288000, hasStockInfoOutput = false, redeclare replaceable type OutputType = Units.Time_years) "Average erperience of employees" annotation(Placement(visible = true, transformation(origin = {10, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.Growth gainingExperience(hasConstantRate = false, rate.displayUnit = "1/yr") annotation(Placement(visible = true, transformation(origin = {-30, -50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Converters.ConstantConverterRate gainingExperienceRate(value = 31536000, timeBaseString = "year", redeclare replaceable type ValueType = Units.Time_years) annotation(Placement(visible = true, transformation(origin = {-70, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.OutflowDynamicStock attrition annotation(Placement(visible = true, transformation(origin = {50, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.Cloud cloud1 annotation(Placement(visible = true, transformation(origin = {90, -10}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.ConstantConverterTime employmentPeriod(value = 157680000, redeclare replaceable type OutputType = Units.Time_years) "Average length of employment" annotation(Placement(visible = true, transformation(origin = {40, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.DiscreteDelay.Smooth perceivedAttrition(delayTime(displayUnit = "yr") = 31536000, init = BusinessSimulation.Types.InitializationOptions.SteadyState) "The rate of leaving the company" annotation(Placement(visible = true, transformation(origin = {10, 60}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + InformationSources.RampInput experienceNewEmployees(redeclare replaceable type OutputType = Units.Time_years, offset = 157680000, startTime(displayUnit = "yr") = 31536000, height = -94608000, duration(displayUnit = "yr") = 126144000) "The prior experience of new employees given in years" annotation(Placement(visible = true, transformation(origin = {-117.141, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + InformationSources.RampInput desiredWorkforce(offset = 750, startTime(displayUnit = "yr") = 31536000, height = 450, duration(displayUnit = "yr") = 189216000, redeclare replaceable type OutputType = Units.Labor) "The desired Workforce given in FTE" annotation(Placement(visible = true, transformation(origin = {-118.276, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(hiring.massPort, workforce.inflow) annotation(Line(visible = true, origin = {-10, -10}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(recruitingPolicy.y, hiring.u) annotation(Line(visible = true, origin = {-39.667, 20}, points = {{-9.333, 10}, {4.667, 10}, {4.667, -20}}, color = {1, 37, 163})); + connect(workforce.y_stockInfo, expertise.u_stockInfo) annotation(Line(visible = true, origin = {19.333, -14.933}, points = {{-1.333, 15.333}, {-1.333, 19.933}, {10.667, 19.933}, {10.667, -15.067}, {-9.333, -15.067}, {-9.333, -25.067}}, color = {128, 0, 128})); + connect(gainingExperience.massPort, expertise.inflow) annotation(Line(visible = true, origin = {-10, -50}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(gainingExperienceRate.y, gainingExperience.u) annotation(Line(visible = true, origin = {-44.667, -66.667}, points = {{-19.333, -3.333}, {9.667, -3.333}, {9.667, 6.667}}, color = {1, 37, 163})); + connect(workforce.outflow, attrition.portA) annotation(Line(visible = true, origin = {30, -10}, points = {{-10, 0}, {10, 0}}, color = {255, 0, 0})); + connect(attrition.portB, cloud1.massPort) annotation(Line(visible = true, origin = {70, -10}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(employmentPeriod.y, workforce.u) annotation(Line(visible = true, origin = {14.667, 13.333}, points = {{19.333, 6.667}, {-9.667, 6.667}, {-9.667, -13.333}}, color = {1, 37, 163})); + connect(attrition.y, perceivedAttrition.u) annotation(Line(visible = true, origin = {43.121, 40.133}, points = {{11.879, -39.733}, {11.879, 19.867}, {-23.758, 19.867}}, color = {1, 37, 163})); + connect(perceivedAttrition.y, recruitingPolicy.u_outflow) annotation(Line(visible = true, origin = {-36.667, 53.667}, points = {{36.667, 6.333}, {-18.333, 6.333}, {-18.333, -12.667}}, color = {1, 37, 163})); + connect(workforce.y2, recruitingPolicy.u_current) annotation(Line(visible = true, origin = {-30.1, 22.2}, points = {{29.6, -37.2}, {20.1, -37.2}, {20.1, 27.8}, {-34.9, 27.8}, {-34.9, 18.8}}, color = {1, 37, 163})); + connect(experienceNewEmployees.y, expertise.u) annotation(Line(visible = true, origin = {-33.047, -33.333}, points = {{-76.094, 3.333}, {38.047, 3.333}, {38.047, -6.667}}, color = {1, 37, 163})); + connect(desiredWorkforce.y, recruitingPolicy.u_reference) annotation(Line(visible = true, origin = {-98.138, 30}, points = {{-12.138, 0}, {27.138, 0}}, color = {1, 37, 163})); + connect(workforce.y1, modelOutput.workforce) annotation(Line(visible = true, origin = {47.625, -27.5}, points = {{-27.125, 12.5}, {-22.625, 12.5}, {-22.625, -7.5}, {72.375, -7.5}}, color = {192, 192, 192})); + connect(desiredWorkforce.y, modelOutput.desiredWorkforce) annotation(Line(visible = true, origin = {-37.569, -2.5}, points = {{-72.707, 32.5}, {-42.431, 32.5}, {-42.431, -32.5}, {157.569, -32.5}}, color = {192, 192, 192})); + connect(expertise.y, modelOutput.experience) annotation(Line(visible = true, origin = {50, -36.533}, points = {{-35, -3.067}, {-35, 1.533}, {70, 1.533}}, color = {192, 192, 192})); + annotation(__Wolfram(PlotSet(plots = {Plot(name = "Workforce and Experience", identifier = "workforce-experience", preferred = true, caption = "The workforce closely follows the desired level (Fig1); average workexperience drops significantly over the next years (Fig2).", subPlots = {SubPlot(title = "Workforce", identifier = "Fig1", curves = {Curve(x = time, y = modelOutput.workforce), Curve(x = time, y = modelOutput.desiredWorkforce)}), SubPlot(title = "Experiece", identifier = "Fig2", curves = {Curve(x = time, y = modelOutput.experience)})})})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {0, 80}, textColor = {76, 112, 136}, extent = {{-140, -6}, {140, 6}}, textString = "Managing Employment", fontName = "Lato Black")}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+In this stylized model of human resource management, we are using →FirstOrderStockAdjustment to control the rate of hiring
to keep a company's workforce at the desired level given in full time equivalents (FTE). The workforce in the present case is reduced by attrition as the average employment period is 5 years
—we will model this delay as an exponential delay of 3rd order.
At the start of the simulation we will have the workforce meet its desired level of 750 FTE
. The desired workforce will then ramp up by 450 FTE
starting at the end of the first year over a time of six years.
We would like to keep track of the average experience of the workforce, which we will simply measure in years of relevant work experience. New employees will arrive with an experience of 5 years
, but we assume that this will fall to just 2 years
starting at the end of the first year over four years due to fierce competition for experienced workers. At the start of the simulation, the average experience in our company is around 8 years
.
expertise
of the workforce
).hasStockInfoOutput = true
for workforce
will introduce an additional connector y_stockInfo
which we can then simply connect to the matching connector u_stockInfo
for expertise
. All we need then is an input
providing the current attribute for new entries to workforce
and we are all set.inflow
and outflow
ports for the coflow we can connect processes that directly change the average quality (e.g. gaining experience on the job as done here).This information is part of the Business Simulation Library (BSL).
+The SIR model is a classical approach in mathematical epidemiology to study the spread of infectious diseases. The model goes back to William Ogilvy Kermack and Anderson Gray McKendrick [23] and is also called Kermack-McKendrick-Model.
+The whole population is separated into three stocks(→modelOutput):
+As in the example →SimpleProductionChainIII we are using the →Diffusion component to model social diffusion, e.g. spread by contact. The transmissionRate
(β in the mathematical literature) is also sometimes called the effective contact rate which helps to understand why we have set the adoptionFraction
to 1
in the Diffusion
component.
+ |
inputDiffusion
) at the scope of the model to establish connections for inputs to becoming_infected
in compliance with Modelica specifications. SystemModeler will assist connections with a drop down list making this rather convenient.This information is part of the Business Simulation Library (BSL).
+This introductory example continues the example given in the →Tutorial (please read that section first, if you have not done so already). Here we consider a simple production chain for a company (e.g. ACME) producing a durable good (e.g. intruder alarm systems). Products will be produced at a constant rate of 100 units per month. The finished goods will be collected in a finished-goods inventory from where they will be shipped to customers. The inventory will be empty at the start of the simulation.
+In this introductory example we will assume that there are only first-time purchases and that the rate of purchasing is also the rate of shipment to the customers. Initially the purchase rate will be 10 units per month, but due to some marketing initiative we assume that starting in month six the rate will ramp up to 100 units per month within 18 months after which it will remain at that level.
+Units will remain in use for an average useful life of 5 years. After the useful life has expired, the units will be discarded. In this example, we will not consider replacement purchases.
+The graph below shows different distributions for the useful life given an average life of 5 years. The order of the DelayN component determines the variance for the lifetime distribution. The dashed red lines show the 95th percentil and the red value above indicate the corresponding order <code<n. Since we assume, that 95% of the products will have been discarded after 10 years, it turns out that n = 4
produces a delay distribution matching the assumption.
+ |
In the lower half of the diagram we have included an event-driven process chain (EPC) model typically used in Business Process Modelling (BPM). It offers a nice analogy and allows the transition to a System Dynamics perspective coming from that background: While the process is valid for a single unit, in the continuous time simulation we are aggregating the processes (green) and events (red) over time. An event will thus turn into a stock counting the amount of \"material\" that is in a corresponding state at and given time. A process corresponds to a transition between states at a certain rate given as entities per period.
+EPC always start and end with an event and accordingly we always have to start and end with a stock. In this case the first event is \"hidden\" as a stock with an infinite capacity inside the component of type Growth
. AvailableProducts corresponds to the stock inventory, while \"product received\" pertains to installedBase.
A lot of components will refer to variables contained in modelSettings
. There should always be an instance of that class in the top level scope of any model.
+Tutorial.StrategicBusinessSimulation, +SimpleProductionChainII, SimpleProductionChainIII, DelayN
+"), experiment(StartTime = 0, StopTime = 157680000, __Wolfram_DisplayTimeUnit = "mo"), __Wolfram(PlotSet(plots = {Plot(name = "Stocks", identifier = "stocks", preferred = true, caption = "Inventory levels off when production and shipping rates are identical.", subPlots = {SubPlot(curves = {Curve(x = time, y = modelOutput.installedBase), Curve(x = time, y = modelOutput.inventory)})}), Plot(name = "Flows", identifier = "flows", caption = "Shipping ramps up to the rate of production, while scrapping starts to become notable after about two years.", subPlots = {SubPlot(curves = {Curve(x = time, y = modelOutput.producing), Curve(x = time, y = modelOutput.scrapping), Curve(x = time, y = modelOutput.shipping)}, range = Range(yunit = "1/mo"))})})), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {0, 65}, textColor = {76, 112, 136}, extent = {{-140, -6}, {140, 6}}, textString = "Simple Production Chain", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Bitmap(visible = true, origin = {-11.743, -50.767}, fileName = "", imageSource = "iVBORw0KGgoAAAANSUhEUgAAA2EAAAD0CAYAAAASTy5SAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAD2oSURBVHhe7Z1ddxTXna/P9ckHmLt8hnyQs7JmrXORi7maXIwzXJjkgmTCJA6ZWJkzVmYs40TOmNghcTCxiYwjYmxeBGqpab1AIwkECIElLGELK0bYsoHI1sw++hX9T3Zqthq1urtqV+t51nqWurteulW79K/9066u+l8OAAAAAAAAMoMQBgAAAAAAkCGEMAAAAAAAgAwhhAEAAAAAAGQIIQwAAAAAACBDCGEAAAAAAAAZQggDAAAAAADIEEIYAAAAAABAhhDCAAAAAAAAMoQQBgAAAAAAkCGEMAAAAAAAgAwhhAEAAAAAAGQIIQwAAAAAACBDCGEAAAAAAAAZQggDAIiQ+/fvu6GhIWyB2pYAAAAxQQgDAIiQKxMTbrG317l/+AdswsXnnku2JQAAQEwQwgAAImNpaclNvvNOMFRg404eP55sUwAAgFgghAEARMQXX3zhKqWS++R73wsGCmxcbcuR4eFk2wIAAMQAIQwAICJmr151c7/4RTBM4PbVNr1+6VJtKwMAAOQLIQwAIBI++ugjd/7sWeeeeCIYJLAJN7bp+dOnk20MAACQN4QwAIBIuFAuu49+9KNwiMCm1bbVNgYAAMgbQhgAQATMz86666+/HgwP2Dqvv/KKm5ubq211AACAfCCEAQDkzOrqanIxjs+ffDIYHLB1ahuPDA4m2xwAACAvCGEAADkzOTbmlp57LhgasPUuPfNMss0BAADyghAGAJAjt+fm3HR/fzAsYPu80tfnFhcXa60AAACQLYQwAICcePDggRsaGnL39+wJBgVsn9rm2vZqAwAAgKwhhAEA5MSViQm30NsbDAnYfhf270/aAAAAIGsIYQAAOfDhhx+6iXfeCYYDzM6J48eTtgAAAMgSQhgAQMZ88cUXbmRoyH38/e8HgwFmp9pAbaE2AQAAyApCGABAxsxeverefemlYCjA7FVb3Lh8udY6AAAA7YcQBgCQIXfv3nXnz551//3EE8FAgNmrthg/fTppGwAAgCwghAEAZEj13Dn3x6efDoYBzE+1idoGAAAgCwhhAAAZMT87664fORIMAZi/13/zGzc/P19rLQAAgPZBCAMAyIDV1VVXKZXc2u7dwQCA+au2qQwOJm0FAADQTghhAAAZMDU+7pb27w92/jEeP+juTtoKAACgnRDCAADazO3bt93l/v5gpx/j83JfX9JmAAAA7YIQBgDQRh48eOCGh4bcZ9/+drDDj/GptlKbqe0AAADaASEMAKCNXJ2cdO+98EKws4/xurB/f9J2AAAA7YAQBgDQJj788EM3ceJEsJOP8Xvx+PGkDQEAAFoNIQwAoA2sr6+70eFhd+/73w928DF+1XajQ0NJWwIAALQSQhgAQBuYvXrVvfvyy8HOPRZHteGNy5drrQoAANAaCGEAAC3m7t27buzMGfdf3/hGsGOPxVFtOH76dNKmAAAArYIQBgDQYqqVivtjV1ewU4/FU21ZLZdrrQsAANA8hDAAgBYyPzvrZo4cCXbmO17djFqEphXcmUOH3K1btx79fgAAAE1CCAMAaBGffvqpO1cqubVvfjPYke94x8edW1kJTyu4alO1rdoYAACgWQhhAAAtYmojhLyv0aBAJ35H+P77jwxN6wA/+MlPkjYGAABoFkIYAEALuH37trt87Fiw814YNYrlY6/39z+apoAlZmcfve4HEk2Xei20vvv3//K61uMvW6DgevmNN5K2BgAAaAZCGABAkzx8+NCVh4bcZ9/5TrDjXggVkvxRLAtdeqzQJSx8SQtRFqAsoNnz9Pr03AKaHvvzFki1sdpabQ4AALBdCGEAAE1ydXLSvffznwc77YVQ4cgfqZIKXApieqwwZY9Nze+HMo2WCT1Or09hS2gePRcWyAroe88/n7Q5AADAdiGEAQA0wfLysrt44kSws14Y/VEv0w9e/iiWtFDlj2SlQ1saC2B+WCuwF995J2l7AACA7UAIAwDYJuvr625seNjde+qpYEe9MCo8+aNa0g9ewg9cFqT81zS/BbnQ+kyt08JagVWbq+21DwAAADQKIQwAYJvcnJlxN3/5y2AnvVCmTzfUczudMDRylT69UMsKC216boEsrV7fbFrBVNvfuHz50e8OAADQAIQwAIBtsLIRNMbOnnX/9Y//GOygF04fP5D5pxn6KkgZCl8KbTYyZiHNxwJb+tTGAqu2Hx8YSPYFAACARiCEAQBsg2ql4pZ//ONg5xx3jtoHquVyba8AAADYGoQwAIAGee/mTTfzu98FO+W485x59VX33nvv1fYOAACAx0MIAwBogE8//dSVSyX3p299K9ghx52n9gXtE9o3AAAAtgIhDACgAS6fP+/ef/75YGccd67v//u/u//zzf8XnSOXrtf2XAAAiAlCGABAA1yuVpMOd6gjjjvXWEPYs6++VdtzAQAgJghhAAANwOmImDbG0xFPjV0ihAEARAwhDACgQXRhjmu//W2wQ447T+0L2idighAGABA3hDAAgG3AJeozUvcUC92nLBJjvUQ9IQwAIG4IYQAA20A36NWNejvmZs2tUDdi1k2cQ9O2q9anG0aHpuVszDdrJoQBAMQNIQwAYJvcnJlxN3/5y2AHHVukgp1Gw0LTclZtf+Py5dreEBeEMACAuCGEAQBsk/X1dTc2POzuPfVUsJMejQoxGlGyERsLNRph8tm//y/LaH7DH4nabJn+/kfP9Vjv4y/jT5ONvK/wp0ei2nxsaCjZB2KEEAYAEDeEMACAJlheXnYX33kn2FGPRgs2/oiSXtMok/9chqbpsYJQvWUUmOy7W/7r6ef62cj7+s8jUm2uto8VQhgAQNwQwgAAmuTa5cvuvZhv4KxwZEFHKlAJf4RJYUdBKjTtccvosR+m/EAmhUbD6q3Dpmk+m5ZeTyS+9/Ofu2vV6qPPGymEMACAuCGEAQA0ycOHD115aMh99p3vBDvtuSv8cKMRsTQWpvQzNPpUbxmpZWykTT9tHX6QqrcOfxlTy/nvEYFqY7W12jxmCGEAAHFDCAMAaAG3b992l998M9hxz1UbYfJf84NR2s2m1VtGChvh8t9TWAB83Pv6IczWYcEuEi+/8Ya7PTf36LNFDCEMACBuCGEAAC3iUrXqPvjJT4Kd99wMjTClA096mvCfKxDVWyZ94Q0pNL9/GmS9ddgomT03LNhFoNp2amSk9sHihhAGABA3hDAAgBbx6aefunOlklv75jeDnfhc9L+r5asw5KOAFJq22evCpulneoRL84YC11bfV8EutHxOqk3VtmrjIkAIAwCIG0IYAEALmd8IFdcOHw525LG4qk3VtkWBEAYAEDeEMACAFlOtVNwfu7qCnXksnmrLC0NDtdYtBoQwAIC4IYQBALSYu3fvuvHTp91/feMbwU49Fke1odpSbVokCGEAAHFDCAMAaAOzV6+6d19+Odixx+KoNrwxMVFr1eJACAMAiBtCGABAG1hfX3ejw8Pu3ve/H+zcY/yq7UZLpaQtiwYhDAAgbghhAABt4sMPP3QXjx8PdvAxftV2Hy4s1FqzWBDCAADihhAGANBGrl665BYiutcVbs33XnjBXbV7lxUQQhgAQNwQwgAA2siDBw/c8NCQ++zb3w529jE+1VbljTZT2xUVQhgAQNwQwgAA2szt27fd9JtvBjv8GJ+X+/rc7bm5WusVk50Swj7//HN3584dNzJRdWdHzrmB4SE3tBGgsViq3UqjI+781GTSnmpXgE6HEAYAkAFTFy64D7q7g51+jEe10dTISK3Vikunh7D79++76uVLbnCj8/7Td37vvvrKfveVF3/svvyzp9yXer7t/jcWRrWX2k3tp3b8t2NH3NmhUtK+auedgH7PUDjFxi3SPkMIAwDIgNXVVVcpldza7t3Bzj/mr9pGbaS2KjqdHMKuXp9xZzY66d848vJGB/47wY49Flu169//9sWknW/cuFFr+c5lemLCLfb2BusSbt3Fnh43feFCbavGDyEMACAj5mdn3fXDh4MHD8zf67/5TdJGnUAnhjCdolapnnfdx/vc3zz/z8HOO3aWaueuY68n7d6ppyguLS25ybc2/k4DNQkbd7K/P9mmRYAQBgCQIRfOnXN/fPrp4MED81NtcmF4uNZKxafTQpg64EMjFbe771fBzjp2tk+89ouk/TstiK2trbnK0JD7ZO/eYF3CxtW21DbVto0dQhgAQIbcvXvXjZ8+7f77iSeCBxDMXrWF2kRt0yl0WgjTSMiTBLAdbRLEzo/V9ojOYGZqyt06cCBYl3D7aptq28YOIQwAIGNmr1517770UvDggdmrtpi9eLHWOp1BJ4UwfQes5+03gx1z3Fnq1ETtD53A8vKyq548GaxJ2LzVEyeSbRwzhDAAgIz54osv3Gi57D7+/veDBw/MTrXByOBg0iadwMil64mH3h5OQtiT3S//+bXPHjyszVUcdKUzXZyB74Ch1H4wsLE/FP2qievr625s4xiwsm9fsC5h82rbahtrW8cKIQwAIAc+/PBDN3H8ePDggdmpNvhwYaHWKsXn6//yQhK+Qt65+3FtruKgy5TrKoihDjnuTHXVRO0XRebGtWvu5sGDwZqErVPbWNs6VghhAAA5cWViwi3s3x88eGD7XejtdVfHOus7JgeOng4GsKdf6qvNURx0EQbdB4zL0KOv9oczpVJhL9KxsrLixs6edeu7dgXrErZObePxgYFkm8cIIQwAICcePHjw6OaSe/YEDyDYPrXNte3VBp2ERrtCIUynJxaNO3fuuGePHw12xHFn+8yxI8n+UUSqlYpb7uoK1iVsvdrW1XK5tvXjghAGAJAji4uLbvro0eDBA9vnlb4+d3turtYKnUXolMQinoo4MlF1X31lf7ATjjtb7RfnpyZre0px0H0IZ44cCdYkbJ8z +hw65+fn5WivEAyEMACBnJsfG3NIzzwQPHth6ta2nRkdrW7/zSJ+SqItzFJGzI+fcV178cbATjjtb7Rcnzg3V9pRisLq66iqlklvbvTtYl7B9aptXBgeTNogJQhgAQM7owKAr9H3+5JPBAwi2Tm3jGA/GrURXQvRDmEJZERkYHnJf/tlTwU447my1X5weLtX2lGIwNT7ulp57LliXsP0udXcnbRAThDAAgAjQaSrXX301ePDA1nn9lVeSbd3J6FL0fghTKCsi+s7elwIdcETtF9o/isLi3Jyb7u8P1iTMTp2GvhDR1XAJYQAAkXChXHYf/ehHwYMHNq+27fkCddyaQVdDVAD72nd7Cnl/MKFOdqgDjiiLEsJ0TzN9Vi7AlL92QaZY7jNHCAMAiISPPvrInT992rknnggeQLAJN7aptq228U7g1NilJIQV8dL0BiEM61mUEDY9MeEWe3vDdQkzd7Gnx01fuFBrnXwhhAEARMTs1atu7uc/Dx48cPvO/eIX7vrFi7Wt3PnYKYlFPRVREMKwnkUIYUtLS27yrbeCNQnzc7K/P2mbvCGEAQBExBdffOFGhofdJ9/7XvDggY2rbTlSKiXbdiehS9UX8dL0BiEM6xl7CFtbW3OVjc/4yd69wbqE+ak2UduojfKEEAYAEBnJf0//8IfgwQMbd/L4cbf03nu1rbtzuHSj2L8zIQzrGXsIm5macrcOHAjWJMxftY3aKE8IYQAAEXJF3yPgcsZNq+9iXBkbq23VzkQjfPfu3XM3br7rLk5ddsOVUVcaPudKQ8OP3HhcHhlzFyY2OoW3biXzFgFCGNYz5hC2vLzsqidPBmsSxmP1xImkrfKCEAYAECF2RS1s3liuhNVKLHgpdJ0pDbm+P5xwP3npNbfvp79yu7pecF//wfPu/+75SaIef+uZF90/Pfuy+9f/POSOnzqTbJepS9NRX6hEnzHU+UaU2j9iZH193Y2Vy25l375gxx/jUW2ktlKb5QEhDAAAoEAsffihOzcymgQvhSqFLLsn2FZVOFNge/PtU8lI2Z07d2prjwdCGNYz1hB249o1d/PgwWCnH+NTbaU2ywNCGAAAQAHQyJeFL41shcLVdtTI2dunBpIwFtOpioQwrGeMIWxlZcWNnT3r1nftCnb4MT7VVuMDA0nbZQ0hDAAAIHL0fa+zg6Vk9EqjWKEw1aw6XfH0mcHke2MxQAjDesYYwqqVilvu6gp29jFe1WbVcrnWitlBCAMAAIgUffdLF9R4vf9t93d7nw2Gp1aqgHf4zbfc2Pn8b2ZKCMN6xhbC5mdn3cyRI8FOPsbvzKFDbn5+vtaa2UAIAwAAiJCHDx+6yti4e/7Xv2vb6Ndm/sfLryWnPuZ5bzVCGNYzphC2urrqKqWSW9u9O9jBx/hV21UGB5O2zApCGAAAQGQo/Gg0Slc8DIWkLNRFP8rnKrVPlD2EMKxnTCFsanzcLXFLkcK71N2dtGVWEMIAAAAiQ6cgagQsFI6ytPeV3+V2aiIhDOsZSwhbnJtz0/39wU49Fs8rfX1uYWGh1rrthRAGAAAQEXPz867/nVOZn4K4mfqO2Mz12dqnyw5CGNYzhhBm93O8v2dPsEPf0e7f/2gjhKYVWLVl0qYZ3F+SEAYAABAJukS8rlAYSwCT+iwnTp/J/MbOhDCsZwwhbHpiwi329gY78x2vTtvTZd1D07aq1qGwE5qWo4s9PW76QvvPACCEAQAARMJwZTS5VHwoDOWp7ks2XD5X+5TZQAjDeuYdwpaWltzkW28FO/E7wvfff2Ro2ladnW1+HW1ysr8/aeN2QggDAACIAI006UbMoRAUg29sfLY7d+7UPm37IYRhPfMMYWtra66y8f6f7N0b7MDnrp0qqO+qGX7Y0WP/AhSaX6+nb1hs80t/fs0n9ZqtT4HKn9cf4Uovq9fSp/vZuiJRbas2Vlu3C0IYAABAzuhqiMPnKm5X1wvBABSDX//B8xsd3+HaJ24/hDCsZ54hbGZqyt06cCDYeY9CCz0WeCyMWdiyAGTP7TU/qGlZe27rs/n1uv9cy/ohyh/hCi1r84qIL2qiNlZbtwtCGAAAQM5oFOxIi0bBLlx9t7ZW5w69PRycZ7v+6kh/ZqNhhDCsZ14hbHl52VVPngx22qNRIcgfiVIAEhZ4hB+a9NifX2od/qiVP9JloU6Pbd0WsqSWs/nTAc0MLReh1RMnkjZvB4QwAACAnNEl6XVfrlDwadR7q5/V1urce0t/DM6zXfV9tYuT7fvPsA8hDOuZRwhbX193Y+WyW9m3L9hhj0Y/BEl/JMwPUP78/iiY1HO9HgpLfkALrU/odf99/ekyFPwiVG2tNlfbtxpCGAAAQM6cKQ25v9v7bDD4NOIP/vP1ZH1/vPdJ8lM80fVicN7tqCslDm581iwghGE98whhN65dczcPHgx21qNS4UYByJ4rNFngUfixAGWmQ5u0EaxQkNI0C21+IJNaRuhxKKCZWi4d/CJVba62bzWEMAAAgBz59NNP3fFTZ4Khp1Gn311M1lm6eNV98Md7f34cmne76gIdWVyuPvYQtrh6z71+fTI4LWavfnTHlW/PBacVyaxD2MpG0Bg7e9at79oV7KhHo41cWaiy53ZKoILPZqNe/nMLbba8hTrNJ2x9fgiz0GXL2nNbVj9tOS1TkBCmNh8fGEj2gVZCCAMAAMiR27dvu+d//btg4GnUzx78KVmnRr/eKl9MHmtULDTvdtVpkzdu/uV7Z1vhswcPk++n3bn7ce2VxxN7CBNPj5wMTlPIEaFpefvxnx5s+rm3qtaRdwDdTgjTfrhdqpWKW+7qCnbSo1IhRyHIDwwWfKSNcPnLSB8LVabCkmHrt5ExC2nC1u2HK39Zf72az7B1Razavlou1z5wayCEAQAA5Ii+D9aKe4P99LV3kvVpBMxeW/v8i+Q1naboz9uMumfY+eqjgLdVFL5s+a//ywvuwNHT7tKN92pTw8Qcwv72zZeSzxiaFrP2ufUzNH2rtmIdzbqdEKb97+mX+tybg+MNBbJbN264mSNHgp3z6CzQaX5Fc+bQITc/P1/bK5qHEAYAAJAj5ZGxJNhYSNmuNxYe3VjUP/1QF+YQumKiP28z6jL6Z4Ya+4+wH8LSqlN8auxSbc6/EEsI02mHhgUPjQJpNMhGvIQ/MuSPFGkenQIojc1GouxUwdB76qf/nppXr2tdPprur1PLGJqm57Y+kZ43/XsYeh9N87F15WGjIUyhK7TvKZDVG6FdXV11lVLJre3eHeyYR6dGm0IjXdi02gcqg4PJPtEKCGEAAAA5Uho+l9yDK91BbFQb9fIvxGGnJOqKif68zaiLc4Reb4XqFNtpizGEMAtE9tweWxCywOPPZ+HGwpMFKgs3Ck/+On0t9FhI03wWtiwA2XP/NXsvC2T2XOuz+e1z+etLhyix2bI2b3qb5KUuZPO17/YkI6vmk90vu+/+9NVE7Uvms6++lfwM7XOmlgmdMju1EWiWnnsu2CmPUmHfwcKWu9TdnewTrYAQBgAAkCODQ8NNXxnRwpZ/KqJp4UynK6anbcd2hjDrCL97+04UIUwhJB1UpB+OpB9MLAjZNC1vYc3mDa1TCgtrUu9h6w0tp+f+/FL4o1b+NK3LPovW7f8O/ucOBTQzvVxehvafVqn9UCNki3NzbppAgymv9PW5hYWF5O+lGQhhAAAAOVLaCGHNBhs77VBhbLNpOl0xPW27Nnoq2GanI2okwzq8Cl4+sZyOqDAi/OAhbLRK+uFGPy042eiTjS5Jrcem+6bDm9R89r7+e0ib31+3vZ+mhcKSTdPj9Pr8z+2/b9pQ8MvDUwNnklMMtW+Z2of0XUM5cun6n9XprtrHQvugafui/RPg4cOHyT5494c/DHbEceeqfUL7xn1diKQJCGEAAAA50uzpiDr9UGjEKzTdLtihKyeGpjeqRu00etcIfghTZ1enh6mjXO/iCLGEMOmHG3vsT/eDicKLhRvNnx5R0nM//Jha3kKQKWy9Ws4ClNRjYc+lP4KVDlKaJiy0CX99/udKBzRf4Qe/vGz0HwEKVv5+nA5doX1Rox3TR48GO+K4c9VImEZJm4UQBgAAkCPDldHkYhd+B7ERdSEOoRGv0HRpl64PjZQ1qgKjgmMjqINbr7MbIu8QpgBjIcUCj8KHH3SkhTILJppmwUlBxp9mz21ZX72fP03P7X3S7+G/Zp/Rntt7a3kLdfb5/c8tbFnNJ2xZPbdlpYU5fzvYtLzcTgjTd8Z0ZU6Njm11P0y+E9bdHeyM484z+U7Y6Ght72gOQhgAAECOXL5yze376a+CgWcr2k2Z6wUsu3JivaC2VXU5/fLo+WR97SSGkTAfCywKJBZKpAUTPU6HJQUZzetjy6VVQPLn9QNTOviZFuoM+4zSPovQslqH/7n997L12+f2lxX+ejWf8NeVh42GsO1SuKsjFlmd3hfxd/CSqyNu7AtcHREAAKADmLk+u+0Qpvt/ic1ORTTtlMTHzbcV9VkVHNtNDCGsWRVY/ABTT2EhCB9vViFMzM/OumuHDwc75jtSuzpgK2+ybDd9Dk2LRO0D2hdaBSEMAAAgRz766CP39qmBYOB5nFs5FdG0UxJ1WmBo+lb97e/fTj5zuyl6CLPRpNC0tApqoZEu3NwsQ5ioVipuuasr2DnHFqhgp5Gw0LQIVNtXy43dH/FxEMIAAAByZrA01PRl6rNQV3EcGCy5L754dNn7dlL0ELbZKYQhdVqh/x0sfLxZh7CVlRU3PjDg1nftCnbSo1FBxkaq/FDj8/77f3ndRqAMe73eMrohtEaEdOqg8Jexafbcp977ahl/ekSqzdX22gdaCSEMAAAgZ65cvdrU98Ky8lvPvOhGxi/UPnV7KXoIw/aadQgTN65dczcPHgx21KPQgo0fvuw1BTP/uX6mp+mnglC9ZfRcKIClX/ef2+Otvq//PDLV5mr7VkMIAwAAyBmd3vd6/9vB4BOTWZ2KKAhhWM88Qtj6+robK5fdyr59wc56 +7trIlEKOvaZQ5Y8wWeAJTTPrLeOHKT0XdjENjWZptEiP661Dr9t8pojwohxq67FSKWn7VkMIAwAAiIDScLmp+4W1W11G/0xpKJNTEQUhDOuZRwgTy8vLrnryZLDDnrt+CDI1KpbGponQ6FO9ZTS/P9Kmx7YOYUGq3jr8ZaSFR3sekdUTJ5I2bweEMAAAgAjQCNObx08GA1AMaqRubn6+9mnbDyEM65lXCBMz09Nuvrc32GnPVY0w+d/HkmKzEabNpm32ukx/d8veMx0A661D+CFM6/CDXSTeOnDAzVSrjz5vGyCEAQAARMLwuUryvatQCMpTfSaN1GU1CiYIYVjPPEPY2tqaqwwPu0/27g123nMzPcIkRfo1f5of2ixcic2WUdDyl9FjG/XyT4MUm61D89s69FP4wS4C1bbJ/eE22rpdEMIAAAAi4d69e+7MYCm5CmEoDOWhPsvxU2fcnTt/fdPhdkMIw3rmGcLE0tKSm9xspCcP09/VMhWE0mw2bSvLCP/3tnnTgWur76vwJdPL56za9oNbt2ofsj0QwgAAACJCV0qM6SIdvzrSn9xQOmsIYVjPvEOYmJ6YcIs9PcFOPBbXxd5eNz06Wmvl9kEIAwAAiIyx8xdc7yu/C4aiLP3JS6+54cpopqchGoQwrGcMIez+/fvJ57i/Z0+wM4/FU22ZtKmdYtlGCGEAAACRodBzbmQ013uH6b2z/h6YDyEM6xlDCBMLCwtu+ujRYIcei+eVvj63ODdXa932QggDAACIkIcPHyZB7D9efi0Yktrp87/+3UYAO5d8hrwghGE9YwlhYmp83C11dwc79Vgc1YZTGZyGaBDCAAAAIkWjUDo18fCbbwXDUqvVRTj0HbC8TkH0IYRhPWMKYaurq4+upLd7d7Bzj/GrtlMbqi2zghAGAAAQObowxjsDg+6fnn05GJ5aoW7G/IcTA+7ylWu5BzBBCMN6xhTCxPzsrLt2+HCwg4/xq7ZTG2YJIQwAAKAA6GbO+o6Wbuj89R88HwxS21HhSyNtZ4fKyXvEAiEM6xlbCBPVSsUtd3UFO/kYr2qzarlca8XsIIQBAAAUiNu3b7vBoWH3mzfeSkbGtnNPMS2jGzD/9vdvu9LGuubm56MY/fIhhGE9YwxhKysrbnxgwK3v2hXs7GN8qq3UZmq7rCGEAQAAFBDdPHn0wsWkM6ow9a//eSgJVhrZ+ru9z/45bOmxRs40TVc87H/nlBsYLCXfNdM6YgtfBiEM6xljCBM3rl1zNw8eDHb4MT7VVmqzPCCEAQAAFBydRnjr1i1XHhlzpXIlGSk79MYxN1gaSh7rVMPz1YvJd8vu3bsXbfDyIYRhPWMNYevr626sXHYr+/YFO/0Yj2qjsVIpabM8iD6E2Y3wsHmzuPFcLHz++efJf3hHJqru7Mg5NzAc3iYYt2q30uiIOz81mbSn2nWnQO1rnTup9vk82f2y++xBfpeYbxa1XajzjSi1f8TK8vKyq548Gez4YzxWT5xI2iovog9h0xMTbrG3N7jxcOsu9vS46QsXalu1c1Fnq3r5khvc6Lz/9J3fu6++st995cUfuy//7Cn3pUARx3hVe6nd1H5qx387dsSdHSol7bsTOtXUvta4U2pfmndv30lORzw1dqn2SvEghGE9Yw5hYmZ62s1Tw6P11oEDbqZarbVWPkQdwpaWltzkW28FNx427mR/f7JNO5Wr12fcmY1O+jeOvLzRgf9OsGhjsVW7/v1vX0za+caNG7WW7zyofa2102tfiDcHx5MQ9vRLfbVXigchDOsZewhbW1tzleFh98nevcG6hPmpNknu67bRRnkSbQhLdt6NPzB23taZ7HQb2zTvna7V6BS1SvW86z7e5/7m+X8OFmvsLNXOXcdeT9q9005RpPa13k6tffVQ+FII+9p3e2qvFA9CGNYz9hAmkn+o9fcH6xLm59SxY+6DW7dqrZQf0YawmampZKgwtPFw+ybDrxvbtlNQB3xopOJ29/0qWKSxs33itV8k7d9JQYza1x47rfbVQ98DU/hSCJOXbrxXm1Is1MnmNHIMqf2iCCFMJKeW9/QE6xJmr07znx4drbVOvkQZwvhCY3vN+4uIrUQjIU8SwHa0SRA7P1bbI4oNta+9dlLtq8fIpet/DmDy2Vffqk0pFrowj74XGvq7x52t9ovTw6XanhI3dpGl+3v2BOsSZqfaIGmLSL5XHl0I49Ke7Te5JOfGNs7rkpytQt8B63n7zWCBxp2lTk3U/lBkqH3tt1Nq3+OwUxHNop6SqCvb6sI8ob953NlqvzhdKdf2lPhZWFhw00ePBusSZueVvj63ODdXa5X8iS6EcZO7bMzz5nStQP/F0MUZ+A4YSu0HAxv7Q5Gvmkjty8ai176t8PV/eeGvQpi8c/fj2tTiMDV9ObkyauhvHne22i90C5oiMTU+7pa6u4N1Cduvtv1UJKchGlGFsJWVFTd29qxb37UruAGxdWobjw8MJNu8iOgy5boKYqg4485UV03UflFEqH3ZWfTa9zjs0vRpdbXEoqF7A/YcPxr8e8edrW5Zov2jSKyurj66It/u3cHahO1T21zbXm0QE1GFsGql4pa7uoIbEFuvtnW1XJzhfEMXYdB9wLgMPfpqfzizUWSLeJEOal+2FrX2bYVDbw8HQ9h3f/pqbY7ioL9l3RuQWo++2h+0XxSx1s/Pzrprhw8H6xK2T21zbfvYiCaEaePMHDkS3HjYPmcOHXLz8/O1VigG+u/Xs/x3FAM+U8D/jlL78rGItW8rPNn9cjCESV01sWhcmp5ORrlDf++4M9X+MHTxfG0PKR780y1bY/6nWxQhjCHa/EyGaAcHoxuirYfOA+d7AhhS+8X5qcnanhI/1L78LGLt2wq6HL08cPR0Erx0kQ57rYghTN/z1Pc9+f4vSu0Hp0uDhf7+r06F1inRnH7efmM//TyKEJZ8WfG554IbENtv8mXFjTYoClwxCzdT+8WJc8W4d4yg9uVr0WpfI5wau5SEsKJent5HVz7VzfhDf/O4s+yEK+EKLsSUjbFfiCn3EKZLRU5zN/Hc1WU7dQnVIsC9Y3Azi3TvGGpfHBap9jVCJ4UwoXsB6p6Aob973BnqnqADYyO1PaLYcEuS9pvckqRUivqWJLmGMA0ncwO7OIztBnb10OfU3fJDRRp3ttovtH/EDrUvHotU+xqh00KYLsIwNFIhiO1Qd28EsDPnhgt5MY7N4Ob87bUIN+fPNYRNT0y4xd7e4MbD7F3s6XHTFy7UWide1GEKFWlEWYQQRu2Ly6LUvkbotBAm1AGvVM8np6TxHbGdodpZ7a0RsE4KYMbM9LSb51jQcm8dOOBmqvHfRy63ELa0tOQm39o4OAQ2HubnZH9/0jYxQwjDesYewqh9cVqE2tcInRjCDH0nSBfr0FXyuHx9Z6p2VfueKg26iatXai3feaytrbnK8LD7ZO/eYF3CxtW2TC54tbFtYyeXEJbsdBsdJXa6+Ex23o22iXnnJYRhPWMOYdS+eC1C7WuETg5hQqePjkxeTO4X1fX715Iro+rCPPpeKKerF0u1l9pN7ad21K1GdM9HtW+nnSYcQv/8mTp2LFiXsHG1LT+4dau2deMmlxA2MzWVDBWGNh7mbzKMu9FGsUIIw3rGHMKofXEbe+1rhE4PYYZOUdO9AYeq4+50pZxcmEc1AIulLrilK9vqFjRziwsdeephPZJT1Ht6gnUJt65O858eHa1t1fjJPITxRcRiGPMXGlWwQ51vRKn9I0aofcWwCF/m3go7JYQBdAJ2sSZs3iKNnmYawrgkZ3FMLu250VYxXtpTf2Shzjei1P4RG9S+4hhz7WsEQhgAQNxkGsK4OV2xjPUmd4QwrGeMIYzaVyxjv8HnViCEAQDETWYhbGVlxY2dPevWd+0KHvQwPtVW4wMDSdvFBCEM6xlbCKP2Fc9Ya18jEMIAAOImsxBWrVTccldX8ICH8ao2q5bLtVaMA0IY1jO2EEbtK6Yx1r5GIIQBAMRNJiFsfnbWzRw5EjzQYfzOHDrk5ufna62ZP4QwrGdMIYzaV2xjq32NQAgDAIibtoew1dXVRzdN2707eJDD+FXbVQYHk7aMAUIY1jOWEEbtK76x1b5GIIQBAMRN20PY1Pi4W3ruueABDovjUnd30pYxQAjDesYSwqh9nWFMta8RCGEAAHHT1hC2ODfnpvv7gwc2LJ5X+vrcwsJCrXXzgxCG9YwhhFH7OstYal8jEMIAAOKmbSHMbjx3f8+e4EENi6faMmnTnG+ERwjDeuYdwqh9nWcsta8RCGEAAHHTthA2PTHhFnt7gwe03Hz/fedmZ8PTOlH9rvqdQ9O26WJPj5u+cKHWyvlACNu+5dtz7upHd4LTpPjbN18KTiuKeYewKGtflnZonY2h9jUCIQwAIG7aEsKWlpbc5FsbhT9wIMtV/Rez2VOEhL8O+67A/v1/PV8M6h43+nyhaU04ufH7q43zghC2fRdX77nXr08Gpz09cjLZvqFpRTLPEBZt7cvSVtRZraMNtatZ8659jUAIAwCIm5aHsLW1NVfZ6AR9sndv8CCWmwpJopmwZOsITYtR0WxnKKDaVm2sts4DQtj2FQpboWkKZwppoWlFMq8QFm3ty9JW1FnZinW0wbxrXyMQwgAA4qblIWxmasrdOnAgeACrq53CotEbww7CChJ6XfMIO9VFr/ukT4Hxz9/XND3X66Ewlf7Pq4/m1/I++jyaTz/9903P54cgew/DPk9I+4yGf1qh3sN+H2Hv4W87+xybrc//zMI+l/1ej1FtrLbOg6KEMAUaQ6cBCpv28Z8eJM+FvabTAI10GPLn96fZyJaPvW5Y6LL124iX8Nel0xT9UxXT690svMVmXiFs27UvS+vVWf1UTbHaYTWnnXXWX1bv49dHYeuKyDxrXyMQwgAA4qalIWx5edlVT2508AIHrsdqB2M/UFgnwDoF/sHfDtbWgbCOgj3X+mx56wzYcy2bPrgLW1bYe2m9Fky0vK3DFPaZ +Nc1fb6hDImy68Dskpv0utl5b1p5bB8qe22v2OaWw5+n12XP/sb/sFq2eOJG0edYUIYQp3PgBRyHKnvthR8HIHmseO1VQP+2xUIjTY3tugciw73EZtqze09Zvoco+hx/KbF5bLh0a9dz/fWI2jxDWVO3L0np11mqqX+PaWWfTy9q8qpvbqEdZmlftawRCGABA3LQshK2vr7uxctmt7NsXPGg9VuEHEh2c7UDsPzZ1wE4HGKFOgnUc/Gla3oKV1mcHf+mHknodAH8d0jod+uk/tun+etOdFyn0uj030+8j/d9Xj/3poXX7v2N6fXpsHZ7Qttqiamu1udo+S2IPYTbSZMFI+sFLYSYUaIQftmQ6/PjrTocoKfx1aFl7rp8KejZNCj/s+eHOX6/WY58/drMOYU3XviwVm9VZvy6Y7aqzWjb9XmZ6uQjNq/Y1AiEMACBuWhbCbly75m4ePBg8YD1W/+Bs6mBuB+J0RyAUOiwEaVroIG7T9DgUSqwjovfyp/n665B+RyLUgfE7Kf57SPu8/u/gv+6/jxRaX2i59Lqlv83S+J+zyQ6P2lxtnyWxh7BQ2PFHuaThByYLWMICkMJPGgt3Wp//PhbK/PCn6f66/PfzQ5y9t173P4dRlAAmsw5hTdW+LLW66b/m19l0XbT5/Vrj16dm6qz/vmn92hWxedS+RiCEAQDETUtC2MrGAXXs7Fm3vmtX8GD1WHXAtYOzKfwQ4XcEQp0JzWvhIn2A1zRh6xDWUZBazjoLm3UArPPhv6Zl7H38Dobpd1L00++Q+J/X195ns99Xj9PLad3+e9v8+hlan6+WC/2+W1RtPj4wsLGajfVkROwhTIElNHplYSj9uh+apB/i0uHNV/P54ehxocwPZDa/sMf2mdPrKZpZhrCma1+W6u88XaOE/f2rrvh10a87pl+3tC6rbzZNWK0R/vq0nNVALevXQ1+xWb2KyDxqXyMQwgAA4qYlIaxaqbjlrq7ggWpL6kAu/Od2oA91BCxY2AHenltnwg8ltrwfXIQtawdQvyPidyzssXUw7HXpdyTS09MdEq3X3kNqOf99fIU/r7D30U/73Uy9Zr+fbQvhP/c7Q771pm1RtX21XH60rgwo0kiYBSGh5wo6For8EOSHHj/E6XV/9Mo3PbKlx+nwl/4cfmgTtrxet2n+5yqiWYawpmtflqreCP95um5YvfJfa0ed1XO/jlkttPX4nyNis659jUAIAwCIm6ZD2K0bN9zMkSPBA9SWteBj+AfyUOiw1338IGGdBaF16cBvB3npv5emaR476FsnwPA7A4YFIuG/r3U0DHvdPo+/Ls1r60mrz+RjHRe52XI++kz+NktvK9u+9rvafE04c+iQm5+ff7S+BlFn4dKN92rPHk/sIUz6KAxZOPJDmUgHMuEHMhst87FlhD+yVS+U2UiXNPx59Z6ax5778wk/vMVuoyGs0f3PaEnty9J6ddbqoD+/bFed9ZcV/no1n/DXFbHN1L52QggDAIibpkLY6uqqq5RKbm337uDBacsKP6Bg4dQ+UBkcTPaJRvnuT19NOgvy6Zf6ks7DZw8e1qb+T4oQwjA/Gw1hje5/omW1L0sFdbblNlP72gkhDAAgbpoKYVPj427pueeCB6Ytq/+Ahv4Di4Vzqbs72Scaxe8E+6pDfOjtYffu7Tu1OR9BCMN6NhPCtrL/iZbUviylzrbV7da+dkIIAwCIm22HsMW5OTftn0KyXXW6S+h0QyykV/r6/kdnthV+7bs97sDR08lpY4QwrGdo/2lWf/9rWe3LUups21Xt+49fH032kxjUPxG07xLCAADiZFsh7MGDB0lH+O4Pfxg8GOHOVftEugPbCtUJtlPFTg2cCXa+EWVo/2lW2/+Ol6vJ/kftw7Ttqn3NqkAGAADxse2RsIWFBTd99GjwYIQ7V/03WCMFjbDZ6WBPdr/859PB/O/oMBKG9WzV6Yib7X/UPgyp2verN064NwfHo/LO3Y9rey4AAMRE898J6+4OHpBw55l8L2J0tLZ3bB3rBGu0QY83+x6OQQjDem43hG11/xPUPvTdbu0DAICdS1MhrJBXCMO2mFwhbGNf2M4VwtTp3coV6QxCGNaz0RDW6P4nqH1oNlP7AABg59JUCBPzs7Pu2uHDwYMTbkNRwMtIax/QvpAFhLD6+jdp3ok2GsK2C7XPU1de3MrFSuz+YKFpUvcGUx0JTYvULGsfAAB0Dk2HMFGtVNxyV1fwAFUYdeWwvK8eVtDLSKvtq+VybW9oP4Sw+uomzM3eXNm/0XPRzCqEiY6ofdvRQoceW7Dayj+PdBn3enVW9U/zhKZFaNa1DwAAOoeWhLCVjYPq+MCAW9+1K3igwi2qjk3BLiOtNlfbax/ICkJYfRWeFKJC07aqQlyz68jLLEMYtW/DRv55pJEuGZomRUHOBMij9gEAQOfQkhAmbly75m4ePBg8WEVv+j+5/qkl/n9l1dEw7DXN63cq1CHxp9u6Dc2fnldo3QU8FUdtrrbPkiKHMDtV8PXrk7Xfxv1V2FGA8qf5r/vY61LLGwpPWr/ex5bT+vx5/RGu9LJ6LY2tqyhmGcJE9LXPDwlW2+z1UD2y56pHhh6rRlmN9EestA6ty5bT64bVNZtX8+mxX0ttnen3lz5+nY3APGofAAB0Di0LYevr626sXHYr+/YFD1hRa50CPU53BKxzoQ6AdQLUabDH6Y6M1mXL2Lr0038emmadI3teANXWY6VS0vZZUuQQZqHHAo8FLptu2HOpUOWfXqgQZc9tff40/7nwQ5SW0zJ6HFpW8/7tmy8lr+unTSuSWYewqGufapHVI6k6F6pp6ef6aTVRahl7bv9YsvCkea0GWgCzaVbX7Llhz7Vee0+/dtp76DX/uS2Xs3nVPgAA6BxaFsLE8vKyq548GTxoRa3/n9x0J8LUdJvHV/jBye/IaH4/oOmxdWQ0zeaTkXUytmL1xImkzbOmyCFMIcgfiVLoEQo8Fn780KSQlr7IhsKTrUP4I13+/LZumyZtFE6Phf9eZmi5Ipl1CBNR1j77R49fU/z65Nc9KbSM1SK/rvnz2nptmmqahSU99mueP29ovfostl7/s/mPpdVle56zedU+AADoHFoawsTM9LSb7+0NHriiNR2WdPAX/n+CpWHzhoKT3yFJ469P+J0RLZN+v4i9deCAm6lWH/0eGVPkEOaHIKnHwh6nA5c/6mVakAuFJU2z+dPr80e4/PdN64e8IppHCBPR1T7VqXRN8euTX3P8kBUKPH6N9Of1a2AoZKXXm/48mmZhy/9sepzGXy5H86x9AADQObQ8hK2trbnK8LD7ZO/e4AEsSnXA9zsO/uvW8TDtP7vqcKQ7Ff40v3PiLy9DnRV1RqyzErlq2+QeSRttnQdFDmHCP83PHxlT+EkHLk2z0wdNC3KhICVsfj+QSb1uoSwU+Ewtk37PIplXCIuu9inc+DXF6pPVHatDeizsddU8v67ZfBaQtF6ri1rG5rX1+zVP0yxkaRl7bApbr7BlhX2eiMy79gEAQOfQ8hAmlpaW3GSEB9Cg1sHQT3UG/NAl9Jo6MtY50HNhj60DYusR/vPNtoOwzoc6JiId+CJVbfvBrVuPPnMOFDWE2ciVApD/3E4JDAUuP6TZcwtPtryFOr0ubH1+CLPAZuuy57asnttyWg8hbHtEVfv8MJWuT6bwg5L0a5zNI6wGan6rXXoPC3rpmqfXhc1rz/VY6j3t82kZf5qw5SIy79oHAACdQ1tCmJiemHCLPT3BA1lU6kBvHQFpHQVhocjvwAjrjEgfdSSsQyK1vI//Pv4068jE0nmr42Jvr5seHa198HwoaghTsFEIsrAkLPjI9HP/dcMPZFLPDQtlNs2eC82n9/fDlb+shTWpeQx7rUjmGcJEVLXPJ12fpGqSX5f81w0tZ/NYLbQaqPVZnZT2DyVhtdXmFX7d89/XaqA917JpbFpOxlD7AACgc2hbCLu/cYBVZ+j+nj3BAxoWT7Vl0qZ+By0HihrCFHSKPMJUFPMOYdS+zjOW2gcAAJ1D20KYWFhYcNNHjwYPalg8r/T1ucW5v4yS5EVRQ5hGwEIjXdha8w5hgtrXWcZS+wAAoHNoawgTU+Pjbqm7O3hgw+KoNpyK5FScIoYw/8qEoenYOmMIYYLa1xnGVPsAAKBzaHsIW11dfXQ1qd27gwc4jF+1ndpQbRkDRR0Jw2yMJYRR+4pvbLUPAAA6h7aHMDE/O+uuHT4cPMhh/Krt1IaxQAjDesYSwgS1r9jGVvsAAKBzyCSEiWql4pa7uoIHOoxXtVm1XK61YhwQwrCeMYUwQe0rpjHWPgAA6BwyC2ErKytufGDAre/aFTzgYXyqrdRmaruYIIRhPWMLYdS+4hlr7QMAgM4hsxAmbly75m4ePBg86GF8qq3UZrFBCMN6xhbCBLWvWMZa+wAAoHPINIStr6+7sXLZrezbFzzwYTyqjcZKpaTNYoMQhvWMMYRR+4pjzLUPAAA6h0xDmFheXnbVkyeDBz+Mx+qJE0lbxQghDOsZYwgT1L5iGHPtAwCAziHzECZmpqfdfG9v8ACI+XvrwAE3U63WWis+CGFYz1hDmKD2xW3stQ8AADqHXELY2tqaqwwPu0/27g0eCDE/1SbJvY022ihWCGFYz5hDGLUvXotQ+wAAoHPIJYSJpaUlN9nfHzwYYn5OHTvmPrh1q9ZKcUIIw3rGHMIEtS9Oi1D7AACgc8gthInpiQm32NMTPCBi9i729rrp0dFa68QLIQzrGXsIE9S+uCxK7QMAgM4h1xB2//79pMN0f8+e4IERs1NtkLTFRpvEjj7nlwKdb0TtF0UIYdS+eCxS7QMAgM4h1xAmFhYW3PTRo8GDI2bnlb4+tzg3V2uVuBkYHnJf/tlTwU447my1X5weLtX2lLih9sVhkWofAAB0DrmHMDE1Pu6WuruDB0hsv9r2UwU6FefsyDn3lRd/HOyE485W+8XpSrm2p8QPtS9fi1b7AACgc4gihK2urj66KtXu +3cEDJbZPbXNte7VBUZiavuy++sr+YCccd7baL0YminOJcWpffhax9gEAQOcQRQgT87Oz7trhw8GDJbZPbXNt+yJx584d13P8aLATjjvbfzt2JNk/igS1Lx+LWPsAAKBziCaEiWql4pa7uoIHTGy92tbVcnFO3TI+//xzd3ao5L7U851gRxx3ptoftF9o/yga1L5sLWrtAwCAziGqELaysuLGBwbc+q5dwQMntk5tY21rbfMicml62v39b18MdsZxZ6r9Yeji+doeUiyofdlZ9NoHAACdQVQhTNy4ds3dPHgwePDE1qltrG1dVHQ56YGhkvub5/852CHHnaX2g9OlwUJfZpzal41Fr30AANAZRBfC1tfX3Vi57Fb27QseQLF5tW3HSqVkWxeZq9dnXPfxvmCnHHeWXcdeT/aHIkPta7+dUvsAAKD4RBfCxPLysquePBk8iGLzVk+cSLZxJzB0fsw98dovgh1z3Bk+2fcrNzA2Utsjig21r712Uu0DAIBiE2UIEzPT026+tzd4IMXte+vAATdTLc4lvB+HLsIwNFIhiO1Qd28EsDPnhgt5MY7NoPa1x06rfQAAUGyiDWFra2uuMjzsPtm7N3hAxcbVtkzuSbSxbTsJdcAr1fPJKWl8R2xnqHZWe2sErJMCmKD2td5OrX0AAFBcog1hYmlpyU0dOxY8qGLjalt+cOtWbet2HvpOkC7Woavkcfn6zlTtqvY9VRp0E1ev1Fq+86D2tdZOr30AAFA8og5hYnpiwi329AQPrLh1F3t73fToaG2rdi66Ot7I5MXkflFdv3/NffWV/e4rL/7YfflnT2104MMde4xTtZfaTe2ndnzm2BF3plRK2rfIV0HcKtS+1rhTah8AABSL6EOYOltDQ0PYAndCx9XQKWp37txxQ9Vxd7pSdqeHS8FtgnE7MDzkTpwbciMTVTe3uNBxpx7Wg9rXOndS7QMAgGIQfQgDAAAAAADoJAhhAAAAAAAAGUIIAwAAAAAAyBBCGAAAAAAAQIYQwgAAAAAAADKEEAYAAAAAAJAhhDAAAAAAAIAMIYQBAAAAAABkCCEMAAAAAAAgQwhhAAAAAAAAGUIIAwAAAAAAyBBCGAAAAAAAQIYQwgAAAAAAADKEEAYAAAAAAJAhhDAAAAAAAIDMcO7/AyPAeqvrj91cAAAAAElFTkSuQmCC +", extent = {{-78.257, -39.233}, {78.257, 39.233}}), Line(visible = true, origin = {46.667, -25}, points = {{-186.667, 0}, {93.333, 0}, {93.333, 0}}, color = {76, 112, 136}, thickness = 1), Text(visible = true, origin = {101.715, -30.5}, textColor = {76, 112, 136}, extent = {{-38.285, -10.5}, {38.285, 10.5}}, textString = "Event-driven Process Chain", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-76.8, -75}, textColor = {76, 112, 136}, extent = {{-28.2, -2}, {28.2, 2}}, textString = "Cloud within producing", fontName = "Lato"), Text(visible = true, origin = {-17.6, -75}, textColor = {76, 112, 136}, extent = {{-11.4, -2}, {11.4, 2}}, textString = "inventory", fontName = "Lato"), Text(visible = true, origin = {50.58, -62}, textColor = {76, 112, 136}, extent = {{-12.58, -2}, {12.58, 2}}, textString = "installedBase", fontName = "Lato")})); +end SimpleProductionChain; diff --git a/BusinessSimulation/Examples/SimpleProductionChainII.mo b/BusinessSimulation/Examples/SimpleProductionChainII.mo new file mode 100644 index 0000000..7b81658 --- /dev/null +++ b/BusinessSimulation/Examples/SimpleProductionChainII.mo @@ -0,0 +1,63 @@ +within BusinessSimulation.Examples; + +model SimpleProductionChainII "Extending the first example to include replacement purchases" + extends Icons.Example; + ModelOutput modelOutput "Main output for the model" annotation(Placement(visible = true, transformation(origin = {130, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {90, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + inner ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.months, dt(displayUnit = "mo") = 657000, modelTimeHorizon(displayUnit = "mo") = 157680000) annotation(Placement(visible = true, transformation(origin = {-135, -75}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + expandable connector ModelOutput "Main output for the model" + import BusinessSimulation.Units.{Amount,Rate}; + extends Icons.DataOutPort; + Amount inventory "Finished goods inventory"; + Amount installedBase "Installed base for the product"; + Rate producing "Rate of production"; + Rate shipping "Rate of shipping to customers"; + Rate scrapping "Rate of scrapping at the end of useful life"; + end ModelOutput; +protected + Stocks.MaterialStock inventory(initialValue = 0, redeclare replaceable type OutputType = Units.Amount) "Finished goods inventory" annotation(Placement(visible = true, transformation(origin = {-50, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.Transition shipping(hasConstantRate = false, rate(displayUnit = "1/mo") = 3.80517503805175e-06, redeclare replaceable type OutputType = Units.Rate) "Shippment to the customer at an exogenous rate" annotation(Placement(visible = true, transformation(origin = {-10, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.Growth producing(hasConstantRate = false, rate(displayUnit = "1/mo") = 3.80517503805175e-05) "Production at a constant rate" annotation(Placement(visible = true, transformation(origin = {-90, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.DelayN installedBase(hasConstantDelayTime = false, n = 4, delayTime(displayUnit = "yr") = 157680000, initialValue = 0, redeclare replaceable type OutputType = Units.Amount) "Product stays in use for around 5 years" annotation(Placement(visible = true, transformation(origin = {30, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.OutflowDynamicStock scrapping "After its useful life has expired, products will be discarded" annotation(Placement(visible = true, transformation(origin = {70, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + InformationSources.RampInput firstTimePurchases(redeclare replaceable type OutputType = Units.Rate, offset(displayUnit = "1/mo") = 3.80517503805175e-06, height(displayUnit = "1/mo") = 3.42465753424658e-05, startTime(displayUnit = "mo") = 15768000, duration(displayUnit = "mo") = 47304000) "Ramping up from 10 to 100 units per month starting at 6 mo for 18 mo" annotation(Placement(visible = true, transformation(origin = {-65, 45}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime usefulLife(value(displayUnit = "yr") = 157680000) "Average time a product remains in use" annotation(Placement(visible = true, transformation(origin = {10, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Add_2 shippingRate(redeclare replaceable type OutputType = Units.Rate) "The total rate of material that is being shipped to customers" annotation(Placement(visible = true, transformation(origin = {-15, 22.729}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + MoleculesOfStructure.Policy.FirstOrderStockAdjustment productionRate(adjTime(displayUnit = "mo") = 2628000, hasConstantAdjTime = true) annotation(Placement(visible = true, transformation(origin = {-90, -50}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.ConstantConverter desiredInventory(value = 100) "The constant level of inventory we wich to maintain" annotation(Placement(visible = true, transformation(origin = {-50, -50}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + SourcesOrSinks.Cloud cloud1 annotation(Placement(visible = true, transformation(origin = {110, -10}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); +equation + connect(inventory.outflow, shipping.portA) annotation(Line(visible = true, origin = {-30, -10}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(shipping.portB, installedBase.inflow) annotation(Line(visible = true, origin = {10, -10}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(producing.massPort, inventory.inflow) annotation(Line(visible = true, origin = {-70, -10}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(installedBase.outflow, scrapping.portA) annotation(Line(visible = true, origin = {50, -10}, points = {{-10, 0}, {10, 0}}, color = {255, 0, 0})); + connect(scrapping.portB, cloud1.massPort) annotation(Line(visible = true, origin = {90, -10}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(usefulLife.y, installedBase.u) annotation(Line(visible = true, origin = {22, 13.333}, points = {{-6, 6.667}, {3, 6.667}, {3, -13.333}}, color = {1, 37, 163})); + connect(firstTimePurchases.y, shippingRate.u2) annotation(Line(visible = true, origin = {-32.333, 40.243}, points = {{-24.667, 4.757}, {12.333, 4.757}, {12.333, -9.514}}, color = {1, 37, 163})); + connect(shippingRate.y, shipping.u) annotation(Line(visible = true, origin = {-15, 7.365}, points = {{0, 7.365}, {0, -7.365}}, color = {1, 37, 163})); + connect(scrapping.y, shippingRate.u1) annotation(Line(visible = true, origin = {32.5, 30.282}, points = {{42.5, -29.882}, {42.5, 14.718}, {-42.5, 14.718}, {-42.5, 0.447}}, color = {1, 37, 163})); + connect(desiredInventory.y, productionRate.u_reference) annotation(Line(visible = true, origin = {-67.5, -50}, points = {{11.5, 0}, {-11.5, 0}}, color = {1, 37, 163})); + connect(shipping.y2, productionRate.u_outflow) annotation(Line(visible = true, origin = {-54.1, -25.8}, points = {{33.6, 10.8}, {24.1, 10.8}, {24.1, -4.2}, {-40.9, -4.2}, {-40.9, -13.2}}, color = {1, 37, 163})); + connect(inventory.y2, productionRate.u_current) annotation(Line(visible = true, origin = {-74.1, -27.8}, points = {{13.6, 12.8}, {4.1, 12.8}, {4.1, -7.2}, {-10.9, -7.2}, {-10.9, -11.2}}, color = {1, 37, 163})); + connect(productionRate.y, producing.u) annotation(Line(visible = true, origin = {-106.2, -16}, points = {{5.2, -34}, {-13.8, -34}, {-13.8, 26}, {11.2, 26}, {11.2, 16}}, color = {1, 37, 163})); + connect(producing.y1, modelOutput.producing) annotation(Line(visible = true, origin = {-24.875, -27.5}, points = {{-54.625, 12.5}, {-50.125, 12.5}, {-50.125, -12.5}, {154.875, -12.5}}, color = {192, 192, 192})); + connect(shipping.y1, modelOutput.shipping) annotation(Line(visible = true, origin = {35.125, -27.5}, points = {{-34.625, 12.5}, {-30.125, 12.5}, {-30.125, -12.5}, {94.875, -12.5}}, color = {192, 192, 192})); + connect(inventory.y1, modelOutput.inventory) annotation(Line(visible = true, origin = {5.125, -27.5}, points = {{-44.625, 12.5}, {-40.125, 12.5}, {-40.125, -12.5}, {124.875, -12.5}}, color = {192, 192, 192})); + connect(scrapping.y1, modelOutput.scrapping) annotation(Line(visible = true, origin = {95.125, -27.5}, points = {{-14.625, 12.5}, {-10.125, 12.5}, {-10.125, -12.5}, {34.875, -12.5}}, color = {192, 192, 192})); + connect(installedBase.y1, modelOutput.installedBase) annotation(Line(visible = true, origin = {65.125, -27.5}, points = {{-24.625, 12.5}, {-20.125, 12.5}, {-20.125, -12.5}, {64.875, -12.5}}, color = {192, 192, 192})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+In this model we extend the introductory example →SimpleProductionChain by including the rate of scrapping in determining the rate of shipping. We simply assume, that whatever is scrapped will immediately be replaced by a new product.
+Since this introduces some variation in the rate of shipping, we need to have an adequate policy to determine the production rate. In this case we make use of a policy component called →FirstOrderStockAdjustment that can be found in the package. It simply determines the rate of inflow needed to keep a stock at a desired level, given the current amount in the stock and the (perceived) rate of outflow from the stock.
Here we would like to keep the inventory at a desired level of 100 units.
++Tutorial.StrategicBusinessSimulation, +SimpleProductionChain, SimpleProductionChainIII
+"), experiment(StartTime = 0, StopTime = 157680000, __Wolfram_DisplayTimeUnit = "mo"), __Wolfram(PlotSet(plots = {Plot(name = "Stocks", identifier = "stocks", subPlots = {SubPlot(curves = {Curve(x = time, y = modelOutput.inventory), Curve(x = time, y = modelOutput.installedBase)})}), Plot(name = "Flows", identifier = "flows", preferred = true, caption = "The production rate quickly tracks the shipping rate once inventory is filled to 100 units. Two years into the simulation shipping is \"moulded\" by replacement purchases.", subPlots = {SubPlot(curves = {Curve(x = time, y = modelOutput.producing), Curve(x = time, y = modelOutput.scrapping), Curve(x = time, y = modelOutput.shipping)}, range = Range(yunit = "1/mo"))})})), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {0, 65}, textColor = {76, 112, 136}, extent = {{-140, -6}, {140, 6}}, textString = "Simple Production Chain II", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); +end SimpleProductionChainII; diff --git a/BusinessSimulation/Examples/SimpleProductionChainIII.mo b/BusinessSimulation/Examples/SimpleProductionChainIII.mo new file mode 100644 index 0000000..cfd29d5 --- /dev/null +++ b/BusinessSimulation/Examples/SimpleProductionChainIII.mo @@ -0,0 +1,73 @@ +within BusinessSimulation.Examples; + +model SimpleProductionChainIII "Further extending the first example to explain new product diffusion" + import BusinessSimulation.Units.{Amount,Rate}; + extends Icons.Example; + ModelOutput modelOutput annotation(Placement(visible = true, transformation(origin = {135, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {90, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + inner ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.months, dt(displayUnit = "mo") = 657000, modelTimeHorizon(displayUnit = "mo") = 315360000) annotation(Placement(visible = true, transformation(origin = {-135, -75}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + + expandable connector ModelOutput + extends Icons.DataOutPort; + // stocks + Amount customers "Customers"; + Amount potentialCustomers "Potential customers"; + Amount installedBase "Installed base"; + Amount inventory "Finished goods in stock"; + // rates + Rate producing(displayUnit = "1/mo") "Production rate"; + Rate shipping(displayUnit = "1/mo") "Shipping rate"; + Rate scrapping(displayUnit = "1/mo") "Scrapping rate"; + end ModelOutput; +protected + Stocks.MaterialStock inventory(initialValue = 100, hasStockInfoOutput = false) "Finished goods inventory" annotation(Placement(visible = true, transformation(origin = {-50, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.Transition shipping(hasConstantRate = false, rate = 0, redeclare replaceable type OutputType = Units.Rate) "Shipments to the customers" annotation(Placement(visible = true, transformation(origin = {-10, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.Growth producing(hasConstantRate = false, rate = 100, redeclare replaceable type OutputType = Units.Rate) "Production of a durable good" annotation(Placement(visible = true, transformation(origin = {-90, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.DelayN installedBase(hasConstantDelayTime = true, n = 4, delayTime(displayUnit = "mo") = 157680000) "Products in use" annotation(Placement(visible = true, transformation(origin = {30, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.OutflowDynamicStock scrapping(redeclare replaceable type OutputType = Units.Rate) "Discarding of products (which will be replaced by new ones)" annotation(Placement(visible = true, transformation(origin = {70, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.Cloud cloud1 annotation(Placement(visible = true, transformation(origin = {110, -30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.Add_2 totalOrders(redeclare replaceable type OutputType = Units.Rate) annotation(Placement(visible = true, transformation(origin = {10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -900))); + Stocks.MaterialStock potCustomers(initialValue(displayUnit = "each") = 250000) "Potential customers" annotation(Placement(visible = true, transformation(origin = {-90, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + MoleculesOfStructure.Actuators.Diffusion wordOfMouth(hasConstantOtherAdopters = true, hasConstantOtherPopulation = true, hasConstantContactRate = true, nextStageIsInfluencing = true, hasConstantAdoptionFraction = true, adoptionFraction = 0.02, contactRate(displayUnit = "1/mo") = 3.80517503805175e-06, hasConstantFractionalAdoptionRate = true, fractionalAdoptionRate(unit = "1/mo") = 0) "Bass diffusion model for a word-of-mouth process" annotation(Placement(visible = true, transformation(origin = {-50, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.MaterialStock customers(initialValue = 10) "Initial customers (early adopters)" annotation(Placement(visible = true, transformation(origin = {-10, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + MoleculesOfStructure.Policy.FirstOrderStockAdjustment productionPlanning(hasConstantAdjTime = true, adjTime(displayUnit = "mo") = 2628000) annotation(Placement(visible = true, transformation(origin = {-90, -70}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.ConstantConverter desiredInventory(value = 100) annotation(Placement(visible = true, transformation(origin = {-55, -70}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Interfaces.Connectors.DataBus bus annotation(Placement(visible = true, transformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {73.333, 77.778}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(inventory.outflow, shipping.portA) annotation(Line(visible = true, origin = {-30, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(shipping.portB, installedBase.inflow) annotation(Line(visible = true, origin = {10, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(producing.massPort, inventory.inflow) annotation(Line(visible = true, origin = {-70, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(installedBase.outflow, scrapping.portA) annotation(Line(visible = true, origin = {50, -30}, points = {{-10, 0}, {10, 0}}, color = {255, 0, 0})); + connect(scrapping.portB, cloud1.massPort) annotation(Line(visible = true, origin = {90, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(scrapping.y, totalOrders.u1) annotation(Line(visible = true, origin = {56, -9.867}, points = {{19, -9.733}, {19, 4.867}, {-38, 4.867}}, color = {1, 37, 163})); + connect(totalOrders.y, shipping.u) annotation(Line(visible = true, origin = {-9.333, -6.667}, points = {{11.333, 6.667}, {-5.667, 6.667}, {-5.667, -13.333}}, color = {1, 37, 163})); + connect(wordOfMouth.portB, customers.inflow) annotation(Line(visible = true, origin = {-30, 30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(wordOfMouth.dataOut, bus) annotation(Line(visible = true, origin = {6.667, 46.8}, points = {{-51.667, -6.4}, {-51.667, 3.2}, {103.333, 3.2}}, color = {0, 0, 128})); + connect(bus.totalAdoptionRate, totalOrders.u2) annotation(Line(visible = true, origin = {42.5, 21.318}, points = {{67.5, 28.682}, {-12.5, 28.682}, {-12.5, -16.318}, {-24.5, -16.318}}, color = {0, 0, 128})); + connect(shipping.y2, productionPlanning.u_outflow) annotation(Line(visible = true, origin = {-54.1, -45.75}, points = {{33.6, 10.75}, {24.1, 10.75}, {24.1, -4.25}, {-40.9, -4.25}, {-40.9, -13.25}}, color = {1, 37, 163})); + connect(inventory.y2, productionPlanning.u_current) annotation(Line(visible = true, origin = {-72.1, -47.77}, points = {{11.6, 12.77}, {7.1, 12.77}, {7.1, -7.23}, {-12.9, -7.23}, {-12.9, -11.23}}, color = {1, 37, 163})); + connect(desiredInventory.y, productionPlanning.u_reference) annotation(Line(visible = true, origin = {-69.75, -70}, points = {{8.75, 0}, {-8.75, 0}}, color = {1, 37, 163})); + connect(customers.y1, modelOutput.customers) annotation(Line(visible = true, origin = {83.185, 12.5}, points = {{-82.685, 12.5}, {16.815, 12.5}, {16.815, -12.5}, {51.815, -12.5}}, color = {192, 192, 192})); + connect(potCustomers.y1, modelOutput.potentialCustomers) annotation(Line(visible = true, origin = {18.811, 12.772}, points = {{-98.311, 12.228}, {-88.811, 12.228}, {-88.811, 0.544}, {81.189, 0.544}, {81.189, -12.772}, {116.189, -12.772}}, color = {192, 192, 192})); + connect(inventory.y1, modelOutput.inventory) annotation(Line(visible = true, origin = {37.583, -15}, points = {{-77.083, -20}, {-72.583, -20}, {-72.583, 5}, {62.417, 5}, {62.417, 15}, {97.417, 15}}, color = {192, 192, 192})); + connect(installedBase.y, modelOutput.installedBase) annotation(Line(visible = true, origin = {81, -7.92}, points = {{-46, -11.68}, {-46, -2.08}, {19, -2.08}, {19, 7.92}, {54, 7.92}}, color = {192, 192, 192})); + connect(producing.y1, modelOutput.producing) annotation(Line(visible = true, origin = {24.25, -31.667}, points = {{-103.75, -3.333}, {-99.25, -3.333}, {-99.25, -28.333}, {95.75, -28.333}, {95.75, 31.667}, {110.75, 31.667}}, color = {192, 192, 192})); + connect(shipping.y1, modelOutput.shipping) annotation(Line(visible = true, origin = {64.25, -31.667}, points = {{-63.75, -3.333}, {-59.25, -3.333}, {-59.25, -28.333}, {55.75, -28.333}, {55.75, 31.667}, {70.75, 31.667}}, color = {192, 192, 192})); + connect(scrapping.y1, modelOutput.scrapping) annotation(Line(visible = true, origin = {104.25, -31.667}, points = {{-23.75, -3.333}, {-19.25, -3.333}, {-19.25, -28.333}, {15.75, -28.333}, {15.75, 31.667}, {30.75, 31.667}}, color = {192, 192, 192})); + connect(potCustomers.outflow, wordOfMouth.portA) annotation(Line(visible = true, origin = {-70, 30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(productionPlanning.y, producing.u) annotation(Line(visible = true, origin = {-106.2, -36}, points = {{5.2, -34}, {-13.8, -34}, {-13.8, 26}, {11.2, 26}, {11.2, 16}}, color = {1, 37, 163})); + annotation(experiment(StartTime = 0, StopTime = 315360000, __Wolfram_DisplayTimeUnit = "mo", __Wolfram_NumberOfIntervals = -1), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+In this final extension of the introductory model SimpleProductionChain
we now replace the Ramp
component for the first-time purchases with a model of new product diffusion.
We are assuming that there are 10 initial customers and a stock of 250'000 potential customers that will be turned into customers by \"word-of-mouth\" only—for now we will assume that there is no growth or decline with regard to this potential. There is a constant contactRate
of 10 people per month and the adoptionFraction
is assumed to be 2%.
+Tutorial.StrategicBusinessSimulation, +SimpleProductionChain, SimpleProductionChainII, Diffusion
+"), __Wolfram(PlotSet(plots = {Plot(name = "Stocks and Rates", identifier = "stocks-rates", preferred = true, subPlots = {SubPlot(curves = {Curve(x = time, y = modelOutput.potentialCustomers), Curve(x = time, y = modelOutput.customers)}, range = Range(xunit = "yr", yunit = "thousand")), SubPlot(curves = {Curve(x = time, y = modelOutput.producing), Curve(x = time, y = modelOutput.scrapping)}, range = Range(xunit = "yr"))})})), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {0, 65}, textColor = {76, 112, 136}, extent = {{-140, -6}, {140, 6}}, textString = "Simple Production Chain III", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); +end SimpleProductionChainIII; diff --git a/BusinessSimulation/Examples/package.mo b/BusinessSimulation/Examples/package.mo new file mode 100644 index 0000000..f6f0b26 --- /dev/null +++ b/BusinessSimulation/Examples/package.mo @@ -0,0 +1,16 @@ +within BusinessSimulation; + +package Examples "Example models showing basic and advanced functionality" + extends Icons.ExamplesPackage; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains examples for the use of library elements in simulation models.
++Tutorial +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+ProportionalSwitching models the exchange of \"mass\" (conserved matter or information) between two stocks as a bi-directional flow. The rate of flow will be proportional to the amount in the connected levels times the fractional rate of flow given by the input u:
+input u | +direction of flow (for positive levels) | +
+ rate of flow + |
+
u ≥ 0 | +flow from A to B | +
+
|
+
u <= 0 | +flow from B to A | +
+
|
+
useAbsoluteLevels
the direction of flow may be reversed by negative amounts in the connected stocks, which is possible, if the stocks are information levels (material stocks by definition cannot become negative).useAbsoluteLevels
may be set to false as the amount in the stocks cannot become negative.This information is part of the Business Simulation Library (BSL).
+This is the classical example for an exchange of \"mass\" (conserved matter or information) between two stocks, where the flow may go in either direction.
+Transition, ProportionalSwitching
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {-8.257, -76.886}, textColor = {0, 0, 128}, extent = {{-25.827, -12}, {25.827, 12}}, textString = "rate", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Switching", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {-42.154, -19.63}, rotation = 5.306, points = {{36.522, -45.771}, {43.438, -34.535}, {45.906, -7.964}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {4, -26.925}, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Switching; diff --git a/BusinessSimulation/Flows/Bidirectional/package.mo b/BusinessSimulation/Flows/Bidirectional/package.mo new file mode 100644 index 0000000..fb85a51 --- /dev/null +++ b/BusinessSimulation/Flows/Bidirectional/package.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Flows; + +package Bidirectional "Entities may move from stock A to stock B or from B to A" + extends Icons.Package; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains bidirectional flows of the System Dynamics method. Bidirectional flows represent the most general type of flows.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This is the classical structure for a broken flow from stock A to stock B, where the rate of outflow is given for stock A. A's outflow will flow into a →Cloud and accordingly, there will be an inflow to stock B which is given by:
+rate of inflow to B = rate of outflow from A × factor of proportionality
+Here the factor of proportionality will be given as amount of B per amount of A, so that the resulting inflow to B will have proper units [amount of B per second].
++ |
Jim Hines [6, p. 16] notes, that \"in an aggregated model of a supply chain there will be a change of units and a conceptual break in the transition from raw materials inventory to work in progress.\"
+BrokenTransitionPull, Transition
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {-15.783, -54.866}, textColor = {0, 0, 128}, extent = {{-34.217, -12}, {34.217, 12}}, textString = "factor", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {33.142, 17.162}, rotation = 5.35, points = {{-56.426, 30.508}, {-66.107, 22.749}, {-75.3, 9.902}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Text(visible = true, origin = {-2.331, 50}, textColor = {0, 0, 128}, extent = {{-20, -12}, {20, 12}}, textString = "rate", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Broken Transition", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Polygon(visible = true, origin = {-41.165, 23.17}, rotation = -30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, -9}, {-5, 5}, {5, 5}}), Line(visible = true, origin = {-45.895, -19.209}, rotation = 5.35, points = {{56.426, -30.508}, {66.107, -22.749}, {75.3, -9.902}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {28.979, -23.17}, rotation = -30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BrokenTransition; diff --git a/BusinessSimulation/Flows/Interaction/BrokenTransitionPull.mo b/BusinessSimulation/Flows/Interaction/BrokenTransitionPull.mo new file mode 100644 index 0000000..f967006 --- /dev/null +++ b/BusinessSimulation/Flows/Interaction/BrokenTransitionPull.mo @@ -0,0 +1,58 @@ +within BusinessSimulation.Flows.Interaction; + +model BrokenTransitionPull "The outflow from A is proportional to the inflow to B" + import BusinessSimulation.Units.{Amount,Rate}; + extends Interfaces.Basics.GenericFlow; + extends Interfaces.Basics.Interaction4SO; + extends Icons.Interaction; + Interfaces.Connectors.RealInput u_rate if not hasConstantRate "Rate of inflow to B" annotation(Placement(visible = true, transformation(origin = {-70, 90}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {0, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Interfaces.Connectors.RealInput u_factor if not hasConstantFactor "Factor of proportionality (amount of A per amount of B)" annotation(Placement(visible = true, transformation(origin = {-20, 90}, extent = {{-10, -10}, {10, 10}}, rotation = -450), iconTransformation(origin = {-100, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Rate rate(min = 0) = 0 "Constant rate of inflow to the stock B" annotation(Dialog(enable = hasConstantRate)); + parameter Amount factor = 1 "Constant factor of proportionality to be multiplied with the outflow from A (default = 1 each [per 1 each])" annotation(Dialog(enable = hasConstantFactor)); + parameter Boolean hasConstantFactor = false "= true, if the factor is to be given by the constant parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantRate = false "= true, if the outflow rate for A is to be given by the constant parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); +protected + SourcesOrSinks.Decline flowingOut "Outflow for stock A" annotation(Placement(visible = true, transformation(origin = {-110, -0}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.PassThrough u_InflowRate_B if not hasConstantRate "Input of inflow rate for B" annotation(Placement(visible = true, transformation(origin = {-70, 60}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parInflowRate_B(final value = rate) if hasConstantRate "Constant rate of inflow to B" annotation(Placement(visible = true, transformation(origin = {-95, 60}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.Product_2 outflowRate_A "Rate of outflow from stock A" annotation(Placement(visible = true, transformation(origin = {-50, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + SourcesOrSinks.Growth flowingIn "Inflow to stock B" annotation(Placement(visible = true, transformation(origin = {90, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.PassThrough u_Factor if not hasConstantFactor "Input for factor of proportionality" annotation(Placement(visible = true, transformation(origin = {-20, 60}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverter parFactor(final value = factor) if hasConstantFactor "Constant factor of proportionality" annotation(Placement(visible = true, transformation(origin = {0, 60}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); +equation + connect(portA, flowingOut.massPort) annotation(Line(visible = true, origin = {-140, -0}, points = {{-20, 0}, {20, -0}}, color = {128, 0, 128})); + connect(flowingIn.massPort, portB) annotation(Line(visible = true, origin = {130, -0}, points = {{-30, -0}, {30, 0}}, color = {128, 0, 128})); + connect(flowingOut.y, y1_A) annotation(Line(visible = true, origin = {-23.333, 30.133}, points = {{-91.667, -19.733}, {-91.667, 9.867}, {183.333, 9.867}}, color = {1, 37, 163})); + connect(flowingOut.y, y_A) annotation(Line(visible = true, origin = {-23.333, 56.8}, points = {{-91.667, -46.4}, {-91.667, 23.2}, {183.333, 23.2}}, color = {1, 37, 163})); + connect(u_Factor.y, outflowRate_A.u1) annotation(Line(visible = true, origin = {-27.333, 34}, points = {{7.333, 18}, {7.333, -9}, {-14.667, -9}}, color = {1, 37, 163})); + connect(flowingIn.y1, y_B) annotation(Line(visible = true, origin = {125.125, -22.5}, points = {{-24.625, 17.5}, {-5.125, 17.5}, {-5.125, -17.5}, {34.875, -17.5}}, color = {1, 37, 163})); + connect(flowingIn.y1, y1_B) annotation(Line(visible = true, origin = {125.125, -42.5}, points = {{-24.625, 37.5}, {-5.125, 37.5}, {-5.125, -37.5}, {34.875, -37.5}}, color = {1, 37, 163})); + connect(parFactor.y, outflowRate_A.u1) annotation(Line(visible = true, origin = {-14, 34.667}, points = {{14, 19.333}, {14, -9.667}, {-28, -9.667}}, color = {1, 37, 163})); + connect(u_factor, u_Factor.u) annotation(Line(visible = true, origin = {-20, 79}, points = {{0, 11}, {0, -11}}, color = {1, 37, 163})); + connect(u_rate, u_InflowRate_B.u) annotation(Line(visible = true, origin = {-70, 79}, points = {{0, 11}, {0, -11}}, color = {1, 37, 163})); + connect(parInflowRate_B.y, flowingIn.u) annotation(Line(visible = true, origin = {-5, 31.25}, points = {{-90, 23.75}, {-90, -1.25}, {90, -1.25}, {90, -21.25}}, color = {1, 37, 163})); + connect(u_InflowRate_B.y, flowingIn.u) annotation(Line(visible = true, origin = {7.5, 30.5}, points = {{-77.5, 21.5}, {-77.5, -0.5}, {77.5, -0.5}, {77.5, -20.5}}, color = {1, 37, 163})); + connect(flowingIn.y2, outflowRate_A.u2) annotation(Line(visible = true, origin = {9.375, 5}, points = {{70.125, -10}, {-9.375, -10}, {-9.375, 10}, {-51.375, 10}}, color = {1, 37, 163})); + connect(outflowRate_A.y, flowingOut.u) annotation(Line(visible = true, origin = {-89.333, 16.667}, points = {{31.333, 3.333}, {-15.667, 3.333}, {-15.667, -6.667}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This is a variant of the classical broken flow (→BrokenTransition) structure that allows for a different parameterization: In this component the given value for the rate (rate
or u_rate
) relates to the rate of inflow to stock B, while the factor of proportionality (factor
or u_factor
) determines the outflow from stock A that is necessary for this process.
A typical application would be to have a given rate of production (here the stock B would be the stock of finished goods) which needs and outflow from the stock of materials that is proprotional to the rate of production according to a factor determined by the bill of materials.
+Hence:
+rate of outflow from A = rate of inflow to B × factor of proportionality
+The factor of proportionality will be given as amount of A per amount of B, so that the resulting outflow from A will have proper units[amnount of B per second].
++ |
Unlike the classical broken flow structure, setting the rate for the stock B might not take into account the availability of material in the stock A; so this has to be taken care of by the modeler explicitly.
+This information is part of the Business Simulation Library (BSL).
+The ComplexInteraction component combines linear and nonlinear interaction between two stocks A (portA
) and B (portB
):
Note: Capital letters were chosen to represent the stocks (state variables) connected at portA
and portB
in the formula above. Also dot notation is used for a stock's rate of flow—its first derivative with respect to time.
Coefficient + | +Unit + | +Description + | +
---|---|---|
a_0 |
+
+ amount of A per second + |
+
+ Rate of growth for stock A + |
+
+
|
+
+ amount of B per second + |
+
+ Rate of growth for stock B + |
+
+
|
+
+ 1/s + |
+
+ Fractional rate of growth for stock A |
+
+
|
+
+ 1/s + |
+
+ Fractional rate of growth for stock B |
+
+
|
+
+ amount of A per amount of B per second + |
+
+ Rate of growth for stock A per stock B |
+
+
|
+
+ amount of B per amount of A per second + |
+
+ Rate of growth for stock B per stock A |
+
a_AB |
+1 per second per amount of B | +
+ Factor used to determine the net flow to A |
+
b_AB |
+1 per second per amount of A | +
+ Factor used to determine the net flow to B |
+
The coefficients can be given as parameters or as variables via the expandable connector dataIn
.
The classical Lotka-Volterra-Model of predator-prey-dynamics can be derived from this model using the following parameterization:
+a_0 = 0, a_A = α, a_B = 0, a_AB = -β, b_0 = 0, b_B = -γ, b_A = 0, b_AB = δ
LinearInteraction, ComplexInteraction, LotkaVolterra
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Linear & Nonlinear", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); +end ComplexInteraction; diff --git a/BusinessSimulation/Flows/Interaction/LinearInteraction.mo b/BusinessSimulation/Flows/Interaction/LinearInteraction.mo new file mode 100644 index 0000000..7424b59 --- /dev/null +++ b/BusinessSimulation/Flows/Interaction/LinearInteraction.mo @@ -0,0 +1,179 @@ +within BusinessSimulation.Flows.Interaction; + +model LinearInteraction "Linear model of interaction between two stocks" + import BusinessSimulation.Units.Rate; + extends Interfaces.Basics.GenericFlow; + extends Interfaces.Basics.Interaction4SO; + extends Icons.Interaction; + Input_Connector dataIn if not (hasConstantGrowthRates and hasConstantFractionalGrowthRates and hasConstantCouplingCoefficients) "Continuous inputs for the component" annotation(Placement(visible = true, transformation(origin = {-145, 85}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + parameter Boolean hasConstantGrowthRates = false "= true, if the linear growth rates are given by constant parameters" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantFractionalGrowthRates = false "= true, if the fractional growth rates are given by constant parameters" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantCouplingCoefficients = false "= true, if the induced growth rates are given by constant parameters" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Rate a_0 = 0 "Constant rate of growth for stock A" annotation(Dialog(enable = hasConstantGrowthRates)); + parameter Rate b_0 = 0 "Constant rate of growth for stock B" annotation(Dialog(enable = hasConstantGrowthRates)); + parameter Rate a_A = 0 "Constant fractional rate of growth for stock A (self-coupling)" annotation(Dialog(enable = hasConstantFractionalGrowthRates)); + parameter Rate b_B = 0 "Constant fractional rate of growth for stock B (self-coupling)" annotation(Dialog(enable = hasConstantFractionalGrowthRates)); + parameter Rate a_B = 0 "Constant Rate of growth for stock A per unit of B (coupling B to A)" annotation(Dialog(enable = hasConstantCouplingCoefficients)); + parameter Rate b_A = 0 "Constant cross-fractional rate of growth for stock B per stock A (coupling A to B)" annotation(Dialog(enable = hasConstantCouplingCoefficients)); + + expandable connector Input_Connector "Data bus for inputs" + extends Interfaces.Connectors.DataInPort; + Real a_0 "Rate of growth for stock A (independent growth)"; + Real b_0 "Rate of growth for stock B (independent growth)"; + Real a_A "Fractional rate of growth for stock A (self-coupling)"; + Real b_B "Fractional rate of growth for stock B (sefl-coupling)"; + Real a_B "Rate of growth for stock A per unit of B (coupling of B to A)"; + Real b_A "Rate of growth for stock B per unit of A (coupling of A to B)"; + end Input_Connector; +protected + Converters.ConstantConverterRate parGrowthRateA(value = a_0) if hasConstantGrowthRates "Constant growth rate for A (optional)" annotation(Placement(visible = true, transformation(origin = {-130, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parFractionalRateA(value = a_A) if hasConstantFractionalGrowthRates "Constant fractional growth rate for A (optional)" annotation(Placement(visible = true, transformation(origin = {-80, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parCrossFractionalRateA(value = a_B) if hasConstantCouplingCoefficients "Constant cross-fractional growth rate for A (optional)" annotation(Placement(visible = true, transformation(origin = {-40, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parGrowthRateB(value = b_0) if hasConstantGrowthRates "Constant growth rate for B (optional)" annotation(Placement(visible = true, transformation(origin = {120, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parFractionalRateB(value = b_B) if hasConstantFractionalGrowthRates "Constant fractional growth rate for B (optional)" annotation(Placement(visible = true, transformation(origin = {80, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parCrossFractionalRateB(value = b_A) if hasConstantCouplingCoefficients "Constant cross-fractional growth rate for B (optional)" annotation(Placement(visible = true, transformation(origin = {40, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Interfaces.Connectors.RealOutput u_growthRate_A if not hasConstantGrowthRates annotation(Placement(visible = true, transformation(origin = {-105, 65}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-66.667, 77.778}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_fractionalGrowthRate_A if not hasConstantFractionalGrowthRates annotation(Placement(visible = true, transformation(origin = {-65, 65}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-66.667, 77.778}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_growthRate_A_per_B if not hasConstantCouplingCoefficients annotation(Placement(visible = true, transformation(origin = {-25, 65}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-66.667, 77.778}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_growthRate_B_per_A if not hasConstantCouplingCoefficients annotation(Placement(visible = true, transformation(origin = {20, 65}, extent = {{10, -10}, {-10, 10}}, rotation = 90), iconTransformation(origin = {-66.667, 77.778}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_fractionalGrowthRate_B if not hasConstantFractionalGrowthRates annotation(Placement(visible = true, transformation(origin = {60, 65}, extent = {{10, -10}, {-10, 10}}, rotation = 90), iconTransformation(origin = {-66.667, 77.778}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_growthRate_B if not hasConstantGrowthRates annotation(Placement(visible = true, transformation(origin = {105, 65}, extent = {{10, -10}, {-10, 10}}, rotation = 90), iconTransformation(origin = {-66.667, 77.778}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExogenousChange growingA1 "Linear growth" annotation(Placement(visible = true, transformation(origin = {-110, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + SourcesOrSinks.ExponentialChange growingA2 "Exponential growth for A" annotation(Placement(visible = true, transformation(origin = {-110, -10}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + SourcesOrSinks.ExogenousChange growingA3 "Cross-fractional growth rate for A per B" annotation(Placement(visible = true, transformation(origin = {-110, -50}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Sensors.FlowPortSensor stockB "Amount in stock B" annotation(Placement(visible = true, transformation(origin = {136.619, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Sensors.FlowPortSensor stockA "Amount in stock A" annotation(Placement(visible = true, transformation(origin = {-137.295, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Converters.Product_2 inducedGrowthA "Rate of growth induced by stock B" annotation(Placement(visible = true, transformation(origin = {-70, -30}, extent = {{-10, -10}, {10, 10}}, rotation = -540))); + Converters.Add_3 totalRateA annotation(Placement(visible = true, transformation(origin = {0, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExogenousChange growingB1 "Linear growth" annotation(Placement(visible = true, transformation(origin = {110, 25}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExponentialChange growingB2 "Exponential growth for B" annotation(Placement(visible = true, transformation(origin = {110, -5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExogenousChange growingB3 "Cross-fractional growth rate for B per A" annotation(Placement(visible = true, transformation(origin = {110, -55}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Product_2 inducedGrowthB "Rate of growth induced by stock A" annotation(Placement(visible = true, transformation(origin = {70, -25}, extent = {{10, -10}, {-10, 10}}, rotation = 540))); + Converters.Add_3 totalRateB annotation(Placement(visible = true, transformation(origin = {40, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(growingA1.massPort, portA) annotation(Line(visible = true, origin = {-135, 15}, points = {{15, 15}, {5, 15}, {5, -15}, {-25, -15}}, color = {128, 0, 128})); + connect(parGrowthRateA.y, growingA1.u) annotation(Line(visible = true, origin = {-117.5, 51.25}, points = {{-12.5, 13.75}, {-12.5, -1.25}, {12.5, -1.25}, {12.5, -11.25}}, color = {1, 37, 163})); + connect(growingA2.massPort, portA) annotation(Line(visible = true, origin = {-135, -5}, points = {{15, -5}, {5, -5}, {5, 5}, {-25, 5}}, color = {128, 0, 128})); + connect(parFractionalRateA.y, growingA2.u) annotation(Line(visible = true, origin = {-92.5, 21.25}, points = {{12.5, 43.75}, {12.5, -11.25}, {-12.5, -11.25}, {-12.5, -21.25}}, color = {1, 37, 163})); + connect(growingA3.massPort, portA) annotation(Line(visible = true, origin = {-135, -25}, points = {{15, -25}, {5, -25}, {5, 25}, {-25, 25}}, color = {128, 0, 128})); + connect(stockB.flowPort, portB) annotation(Line(visible = true, origin = {142.542, 0}, points = {{-5.922, 0}, {5.922, -0}}, color = {128, 0, 128})); + connect(stockA.flowPort, portA) annotation(Line(visible = true, origin = {-142.815, 0}, points = {{5.519, 0}, {-5.519, -0}}, color = {128, 0, 128})); + connect(inducedGrowthA.y, growingA3.u) annotation(Line(visible = true, origin = {-95.787, -33.333}, points = {{18.425, 3.333}, {-9.213, 3.333}, {-9.213, -6.667}}, color = {1, 37, 163})); + connect(inducedGrowthA.u1, stockB.stock) annotation(Line(visible = true, origin = {70.445, -27}, points = {{-132.445, -8}, {66.223, -8}, {66.223, 16}}, color = {1, 37, 163})); + connect(parCrossFractionalRateA.y, inducedGrowthA.u2) annotation(Line(visible = true, origin = {-47.333, 5}, points = {{7.333, 60}, {7.333, -30}, {-14.667, -30}}, color = {1, 37, 163})); + connect(growingA1.y2, totalRateA.u1) annotation(Line(visible = true, origin = {-39.833, 25.87}, points = {{-59.667, -0.87}, {29.833, -0.87}, {31.833, -0.87}}, color = {1, 37, 163})); + connect(growingA2.y2, totalRateA.u2) annotation(Line(visible = true, origin = {-34.375, 2.5}, points = {{-65.125, -17.5}, {19.375, -17.5}, {19.375, 17.5}, {26.375, 17.5}}, color = {1, 37, 163})); + connect(growingA3.y2, totalRateA.u3) annotation(Line(visible = true, origin = {-39.375, -20}, points = {{-60.125, -35}, {14.375, -35}, {14.375, 35}, {31.375, 35}}, color = {1, 37, 163})); + connect(totalRateA.y, y_A) annotation(Line(visible = true, origin = {49.341, 50}, points = {{-41.979, -30}, {-34.341, -30}, {-34.341, 30}, {110.659, 30}}, color = {1, 37, 163})); + connect(totalRateA.y, y1_A) annotation(Line(visible = true, origin = {49.341, 30}, points = {{-41.978, -10}, {-34.341, -10}, {-34.341, 10}, {110.659, 10}}, color = {1, 37, 163})); + connect(growingB1.massPort, portB) annotation(Line(visible = true, origin = {135, 15}, points = {{-15, 10}, {-5, 10}, {-5, -15}, {13.464, -15}}, color = {128, 0, 128})); + connect(parGrowthRateB.y, growingB1.u) annotation(Line(visible = true, origin = {112.5, 51.25}, points = {{7.5, 12.75}, {7.5, -1.25}, {-7.5, -1.25}, {-7.5, -16.25}}, color = {1, 37, 163})); + connect(parFractionalRateB.y, growingB2.u) annotation(Line(visible = true, origin = {92.5, 21.25}, points = {{-12.5, 43.75}, {-12.5, -11.25}, {12.5, -11.25}, {12.5, -16.25}}, color = {1, 37, 163})); + connect(growingB2.massPort, portB) annotation(Line(visible = true, origin = {135, -5}, points = {{-15, 0}, {-5, 0}, {-5, 5}, {25, 5}}, color = {128, 0, 128})); + connect(growingB3.massPort, portB) annotation(Line(visible = true, origin = {135, -25}, points = {{-15, -30}, {-5, -30}, {-5, 25}, {25, 25}}, color = {128, 0, 128})); + connect(inducedGrowthB.y, growingB3.u) annotation(Line(visible = true, origin = {95.787, -31.667}, points = {{-18.425, 6.667}, {9.213, 6.667}, {9.213, -13.333}}, color = {1, 37, 163})); + connect(stockA.stock, inducedGrowthB.u1) annotation(Line(visible = true, origin = {-27.58, -40.2}, points = {{-109.667, 29.2}, {-109.667, -29.8}, {67.58, -29.8}, {67.58, 10.2}, {89.58, 10.2}}, color = {1, 37, 163})); + connect(totalRateB.y, y1_B) annotation(Line(visible = true, origin = {79.341, -40}, points = {{-31.978, 40}, {-24.341, 40}, {-24.341, -40}, {80.659, -40}}, color = {1, 37, 163})); + connect(totalRateB.y, y_B) annotation(Line(visible = true, origin = {79.341, -20}, points = {{-31.979, 20}, {-24.341, 20}, {-24.341, -20}, {80.659, -20}}, color = {1, 37, 163})); + connect(growingB3.y2, totalRateB.u3) annotation(Line(visible = true, origin = {45.375, -32.5}, points = {{54.125, -27.5}, {-20.375, -27.5}, {-20.375, 27.5}, {-13.375, 27.5}}, color = {1, 37, 163})); + connect(growingB2.y2, totalRateB.u2) annotation(Line(visible = true, origin = {55.25, -21.667}, points = {{44.25, 11.667}, {34.75, 11.667}, {34.75, -28.333}, {-45.25, -28.333}, {-45.25, 21.667}, {-23.25, 21.667}}, color = {1, 37, 163})); + connect(growingB1.y2, totalRateB.u1) annotation(Line(visible = true, origin = {45.375, 12.5}, points = {{54.125, 7.5}, {-20.375, 7.5}, {-20.375, -7.5}, {-13.375, -7.5}}, color = {1, 37, 163})); + connect(parCrossFractionalRateB.y, inducedGrowthB.u2) annotation(Line(visible = true, origin = {37, 21.7}, points = {{3, 43.3}, {3, 23.3}, {-17, 23.3}, {-17, -41.7}, {25, -41.7}}, color = {1, 37, 163})); + connect(dataIn.a_0, u_growthRate_A) annotation(Line(visible = true, origin = {-123.333, 78.333}, points = {{-21.667, 6.667}, {18.333, 6.667}, {18.333, -13.333}}, color = {0, 0, 128})); + connect(u_growthRate_A, growingA1.u) annotation(Line(visible = true, origin = {-105, 52.5}, points = {{0, 12.5}, {0, -12.5}}, color = {1, 37, 163})); + connect(dataIn.a_A, u_fractionalGrowthRate_A) annotation(Line(visible = true, origin = {-96.667, 78.333}, points = {{-48.333, 6.667}, {31.667, 6.667}, {31.667, -13.333}}, color = {0, 0, 128})); + connect(u_fractionalGrowthRate_A, growingA2.u) annotation(Line(visible = true, origin = {-85.646, 21.921}, points = {{20.646, 43.079}, {20.323, 18.079}, {5.646, 18.079}, {5.646, -11.921}, {-19.354, -11.921}, {-19.354, -21.921}}, color = {1, 37, 163})); + connect(dataIn.a_B, u_growthRate_A_per_B) annotation(Line(visible = true, origin = {-70, 78.333}, points = {{-75, 6.667}, {45, 6.667}, {45, -13.333}}, color = {0, 0, 128})); + connect(u_growthRate_A_per_B, inducedGrowthA.u2) annotation(Line(visible = true, origin = {-38.4, 19}, points = {{13.4, 46}, {13.4, 21}, {-1.6, 21}, {-1.6, -44}, {-23.6, -44}}, color = {1, 37, 163})); + connect(u_growthRate_B_per_A, inducedGrowthB.u2) annotation(Line(visible = true, origin = {34, 8.333}, points = {{-14, 56.667}, {-14, -28.333}, {28, -28.333}}, color = {1, 37, 163})); + connect(dataIn.b_A, u_growthRate_B_per_A) annotation(Line(visible = true, origin = {-40, 78.333}, points = {{-105, 6.667}, {60, 6.667}, {60, -13.333}}, color = {0, 0, 128})); + connect(u_fractionalGrowthRate_B, growingB2.u) annotation(Line(visible = true, origin = {81.667, 30}, points = {{-21.667, 35}, {-21.667, 15}, {-1.667, 15}, {-1.667, -20}, {23.333, -20}, {23.333, -25}}, color = {1, 37, 163})); + connect(dataIn.b_B, u_fractionalGrowthRate_B) annotation(Line(visible = true, origin = {-13.333, 78.333}, points = {{-131.667, 6.667}, {73.333, 6.667}, {73.333, -13.333}}, color = {0, 0, 128})); + connect(u_growthRate_B, growingB1.u) annotation(Line(visible = true, origin = {105, 50}, points = {{0, 15}, {0, -15}}, color = {1, 37, 163})); + connect(dataIn.b_0, u_growthRate_B) annotation(Line(visible = true, origin = {16.667, 78.333}, points = {{-161.667, 6.667}, {88.333, 6.667}, {88.333, -13.333}}, color = {0, 0, 128})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The LinearInteraction component allows to model the interaction between two stocks A (portA
) and A (portB
) as linear equations:
Note: Capital letters were chosen to represent the stocks (state variables) connected at portA
and portB
in the formula above. Also dot notation is used for a stock's rate of flow—its first derivative with respect to time.
Coefficient | +Unit | +Description | +
---|---|---|
a_0 |
+
+ amount of A per second + |
+
+ Rate of growth for stock A + |
+
+
|
+
+ amount of B per second + |
+
+ Rate of growth for stock B + |
+
+
|
+
+ 1/s + |
+
+ Fractional rate of growth for stock A |
+
+
|
+
+ 1/s + |
+
+ Fractional rate of growth for stock B |
+
+
|
+
+ amount of A per amount of B per second + |
+
+ Rate of growth for stock A per stock B |
+
+
|
+
+ amount of B per amount of A per second + |
+
+ Rate of growth for stock B per stock A |
+
The coefficients can be given as parameters or as variables via the expandable connector dataIn
.
A linear harmonic oscillator can be modeled as a special case of linear interactions where the rates for the mutual influences (e.g. fractionalGrowthRate_B_per_A and fractionalGrowthRate_A_per_B) are negative. In that case, positive stock A will decrease stock B and vice versa.
+The Linear Interaction can be used to model Strogatz' famous model for the dynamics of a love affair (conspicuously between \"Romeo\" and \"Juliet\") as shown in →LoveHateDynamics [16].
+NonlinearInteraction, ComplexInteraction
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Linear", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end LinearInteraction; diff --git a/BusinessSimulation/Flows/Interaction/LotkaVolterra.mo b/BusinessSimulation/Flows/Interaction/LotkaVolterra.mo new file mode 100644 index 0000000..2cc5a1b --- /dev/null +++ b/BusinessSimulation/Flows/Interaction/LotkaVolterra.mo @@ -0,0 +1,115 @@ +within BusinessSimulation.Flows.Interaction; + +model LotkaVolterra "The Lotka-Volterra equations to model predator-prey-dynamics" + import BusinessSimulation.Units.Rate; + extends Interfaces.Basics.GenericFlow; + extends Interfaces.Basics.Interaction4SO; + extends Icons.Interaction; + InputConnector dataIn if not (hasConstantAlpha and hasConstantBeta and hasConstantGamma and hasConstantDelta) "Inputs for predator-prey model" annotation(Placement(visible = true, transformation(origin = {-145, 70}, extent = {{-10, -10}, {10, 10}}, rotation = -360), iconTransformation(origin = {0, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + parameter Rate alpha = 0 "Fractional growth rate of prey population (A)" annotation(Dialog(enable = hasConstantAlpha)); + parameter Rate beta = 0 "Fractional rate of decline for prey population (A) per predator" annotation(Dialog(enable = hasConstantBeta)); + parameter Rate gamma = 0 "Fractional rate of decline for predator population (B)" annotation(Dialog(enable = hasConstantGamma)); + parameter Rate delta = 0 "Fractional rate of growth for predator population (B) per prey" annotation(Dialog(enable = hasConstantDelta)); + parameter Boolean hasConstantAlpha = false "= true, if the constant parameter value is to be used instead of the input connector" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantBeta = false "= true, if the constant parameter value is to be used instead of the input connector" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantGamma = false "= true, if the constant parameter value is to be used instead of the input connector" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantDelta = false "= true, if the constant parameter value is to be used instead of the input connector" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + + expandable connector InputConnector "DataBus for inputs" + extends Icons.DataInPort; + Rate alpha "Fractional growth rate of prey population (A)"; + Rate beta "Fractional rate of decline for prey population (A) per predator"; + Rate delta "Fractional rate of growth for predator population (B) per prey"; + Rate gamma "Fractional rate of decline for predator population (B)"; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+alpha, beta, gamma, delta
")); + end InputConnector; +protected + ComplexInteraction complexInteraction annotation(Placement(visible = true, transformation(origin = {0, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterRate zeroRate(value = 0) "Zero rate input" annotation(Placement(visible = true, transformation(origin = {-110, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Gain fractionalGrowthRatePredator(c = -1) "Convert rate of delince to growth rate" annotation(Placement(visible = true, transformation(origin = {21.803, 30}, extent = {{-10, 10}, {10, -10}}, rotation = -540))); + Converters.Gain couplingFactorForPrey(c = -1) "Convert rate of delince to growth rate" annotation(Placement(visible = true, transformation(origin = {-45, 30}, extent = {{-10, 10}, {10, -10}}, rotation = -180))); + Converters.ConstantConverterRate parAlpha(value = alpha) if hasConstantAlpha "Constant alpha (optional)" annotation(Placement(visible = true, transformation(origin = {-110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parBeta(value = beta) if hasConstantBeta "Constant beta (optional)" annotation(Placement(visible = true, transformation(origin = {-50, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parGamma(value = gamma) if hasConstantGamma "Constant gamma (optional)" annotation(Placement(visible = true, transformation(origin = {10, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterRate parDelta(value = delta) if hasConstantDelta "Constant delta (optional)" annotation(Placement(visible = true, transformation(origin = {70, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Interfaces.Connectors.RealOutput u_alpha if not hasConstantAlpha annotation(Placement(visible = true, transformation(origin = {-95, 55}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-50, 66.667}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_beta if not hasConstantBeta annotation(Placement(visible = true, transformation(origin = {-30, 55}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-50, 66.667}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_gamma if not hasConstantGamma annotation(Placement(visible = true, transformation(origin = {30, 55}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-50, 66.667}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput u_delta if not hasConstantDelta annotation(Placement(visible = true, transformation(origin = {90, 55}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-50, 66.667}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.DataBus dataBus annotation(Placement(visible = true, transformation(origin = {-80, 15}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-43.333, 16.667}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(dataIn.alpha, u_alpha) annotation(Line(visible = true, origin = {-116.667, 63.333}, points = {{-28.333, 6.667}, {21.667, 6.667}, {21.667, -8.333}}, color = {0, 0, 128})); + connect(dataIn.beta, u_beta) annotation(Line(visible = true, origin = {-73.333, 65}, points = {{-71.667, 5}, {43.333, 5}, {43.333, -10}}, color = {0, 0, 128})); + connect(dataIn.gamma, u_gamma) annotation(Line(visible = true, origin = {-33.333, 65}, points = {{-111.667, 5}, {63.333, 5}, {63.333, -10}}, color = {0, 0, 128})); + connect(dataIn.delta, u_delta) annotation(Line(visible = true, origin = {6.667, 65}, points = {{-151.667, 5}, {83.333, 5}, {83.333, -10}}, color = {0, 0, 128})); + connect(portA, complexInteraction.portA) annotation(Line(visible = true, origin = {-37.698, -23.214}, points = {{-110.636, 23.214}, {27.698, 23.214}}, color = {128, 0, 128})); + connect(complexInteraction.portB, portB) annotation(Line(visible = true, origin = {79.232, 0}, points = {{-69.232, 0}, {69.232, 0}}, color = {128, 0, 128})); + connect(complexInteraction.y1_B, y1_B) annotation(Line(visible = true, origin = {82.625, -42.5}, points = {{-72.125, 37.5}, {-2.625, 37.5}, {-2.625, -37.5}, {77.375, -37.5}}, color = {1, 37, 163})); + connect(complexInteraction.y1_B, y_B) annotation(Line(visible = true, origin = {82.625, -22.5}, points = {{-72.125, 17.5}, {-2.625, 17.5}, {-2.625, -17.5}, {77.375, -17.5}}, color = {1, 37, 163})); + connect(complexInteraction.y_A, y_A) annotation(Line(visible = true, origin = {50, 56.8}, points = {{-55, -46.4}, {-55, 23.2}, {110, 23.2}}, color = {1, 37, 163})); + connect(complexInteraction.y_A, y1_A) annotation(Line(visible = true, origin = {78, 50.08}, points = {{-83, -39.68}, {-83, 29.92}, {42, 29.92}, {42, -10.08}, {82, -10.08}}, color = {1, 37, 163})); + connect(complexInteraction.dataIn, dataBus) annotation(Line(visible = true, origin = {-26.667, 13.333}, points = {{26.667, -3.333}, {26.667, 1.667}, {-53.333, 1.667}}, color = {0, 0, 128})); + connect(u_beta, couplingFactorForPrey.u) annotation(Line(visible = true, origin = {-32.333, 38.333}, points = {{2.333, 16.667}, {2.333, -8.333}, {-4.667, -8.333}}, color = {1, 37, 163})); + connect(parBeta.y, couplingFactorForPrey.u) annotation(Line(visible = true, origin = {-39.4, 35}, points = {{-10.6, 9}, {-10.6, 5}, {9.4, 5}, {9.4, -5}, {2.4, -5}}, color = {1, 37, 163})); + connect(parGamma.y, fractionalGrowthRatePredator.u) annotation(Line(visible = true, origin = {25.961, 37}, points = {{-15.961, 7}, {-15.961, 3}, {14.039, 3}, {14.039, -7}, {3.842, -7}}, color = {1, 37, 163})); + connect(u_gamma, fractionalGrowthRatePredator.u) annotation(Line(visible = true, origin = {33.961, 39}, points = {{-3.961, 16}, {-3.961, 1}, {6.039, 1}, {6.039, -9}, {-4.158, -9}}, color = {1, 37, 163})); + // feeding the dataBus + connect(u_alpha, dataBus.a_A) annotation(Line(visible = true, origin = {-90, 28.333}, points = {{-5, 26.667}, {-5, -13.333}, {10, -13.333}}, color = {1, 37, 163})); + connect(parAlpha.y, dataBus.a_A) annotation(Line(visible = true, origin = {-100, 25}, points = {{-10, 20}, {-10, -10}, {20, -10}}, color = {1, 37, 163})); + connect(couplingFactorForPrey.y, dataBus.a_AB) annotation(Line(visible = true, origin = {-68.25, 22.5}, points = {{15.25, 7.5}, {-1.75, 7.5}, {-1.75, -7.5}, {-11.75, -7.5}}, color = {1, 37, 163})); + connect(fractionalGrowthRatePredator.y, dataBus.b_B) annotation(Line(visible = true, origin = {-26.549, 22.5}, points = {{40.352, 7.5}, {6.549, 7.5}, {6.549, -7.5}, {-53.451, -7.5}}, color = {1, 37, 163})); + connect(parDelta.y, dataBus.b_AB) annotation(Line(visible = true, origin = {20, 25}, points = {{50, 20}, {50, -10}, {-100, -10}}, color = {1, 37, 163})); + connect(u_delta, dataBus.b_AB) annotation(Line(visible = true, origin = {33.333, 28.333}, points = {{56.667, 26.667}, {56.667, -13.333}, {-113.333, -13.333}}, color = {1, 37, 163})); + // setting parameters a_0,b_0,a_B,b_A to zero + connect(zeroRate.y, dataBus.a_0) annotation(Line(visible = true, origin = {-88.333, -8.333}, points = {{-16.667, -11.667}, {8.333, -11.667}, {8.333, 23.333}}, color = {1, 37, 163})); + connect(zeroRate.y, dataBus.a_B) annotation(Line(visible = true, origin = {-88.333, -8.333}, points = {{-16.667, -11.667}, {8.333, -11.667}, {8.333, 23.333}}, color = {1, 37, 163})); + connect(zeroRate.y, dataBus.b_0) annotation(Line(visible = true, origin = {-88.333, -8.333}, points = {{-16.667, -11.667}, {8.333, -11.667}, {8.333, 23.333}}, color = {1, 37, 163})); + connect(zeroRate.y, dataBus.b_A) annotation(Line(visible = true, origin = {-88.333, -8.333}, points = {{-16.667, -11.667}, {8.333, -11.667}, {8.333, 23.333}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+These are the classical Lotka-Volterra equations describing predator-prey-dynamics in an idealized way [17]. The dynamics for the prey population (portA
) and the predator population (portB
) are given by the following equations:
Note: Capital letters were chosen to represent the stocks (state variables) connected at portA
and portB
in the formula above. Also dot notation is used for a stock's rate of flow—its first derivative with respect to time.
Coefficient | +Unit | +Description | +
---|---|---|
alpha |
+1 per second | +
+ fractional growth rate for prey population + |
+
beta |
+1 per second per amount of B | +
+ fractional rate of decline for prey population per predator + |
+
gamma |
+1 per second | +
+ fractional rate of decline for predator population + |
+
+
|
+1 per second per amount of A | +fractional rate of groth for predator population per prey | +
This information is part of the Business Simulation Library (BSL).
+The NonlinearInteraction can be used by itself or in combination with the →LinearInteraction flow to model more complex interactions. The netflows to the connected stocks A (portA
) and B (portB
) are given by the following equations:
Note: Capital letters were chosen to represent the stocks (state variables) connected at portA
and portB
in the formula above. Also dot notation is used for a stock's rate of flow—its first derivative with respect to time.
Coefficient | +Unit | +Description | +
---|---|---|
a_AB |
+1 per second per amount of B | +
+ Factor used to determine the net flow to A (positive rate = inflow) + |
+
b_AB |
+1 per second per amount of A | +
+ Factor used to determine the net flow to B (positive rate = inflow) + |
+
The coefficients can be given as parameters or as variables via the expandable connector dataIn
.
A nonlinear component is typically found in predator-prey models or models of infectious diseases, where the exponential growth rate for a population depends upon the size of another population (e.g. prey or susceptible population).
+LinearInteraction, ComplexInteraction
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Nonlinear", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end NonlinearInteraction; diff --git a/BusinessSimulation/Flows/Interaction/package.mo b/BusinessSimulation/Flows/Interaction/package.mo new file mode 100644 index 0000000..5a3d388 --- /dev/null +++ b/BusinessSimulation/Flows/Interaction/package.mo @@ -0,0 +1,14 @@ +within BusinessSimulation.Flows; + +package Interaction "Broken flows modeling the interaction of two stocks" + extends Icons.Package; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Interactions model two stocks with a bidirectional flow at each stock and their interdependencies. Such components already allow to represent more complicated structures like the Lotka-Volterra model of predator-prey-dynamics [17]; there is thus a thin boundary between the classes contained in this package and more complex Actuator subsystems contained in the Molecules of Structure package.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The CheckValveInflow is actually a transceiver that simply passes on a connected flow if that flow fills the connected stock (portB
). This will most often be relevant for more complex subsystems where the flows being connected may not be clear in advance and where this element allows to avoid unwanted draining.
This information is part of the Business Simulation Library (BSL).
+The CheckValveOutflow is actually a transceiver that simply passes on a connected flow if that flow drains the connected stock (portA
). This will most often be relevant for more complex subsystems where the flows being connected may not be clear in advance and where this element allows to avoid unwanted filling.
This information is part of the Business Simulation Library (BSL).
+The stock connected to port A (stockA) will be gradually drained at a rate determined by the average time of residence (residenceTime
) in the stock. The rate which drains the stock (draining
) is given by:
draining = stockA.y / residenceTime
The residence time is clipped to never be smaller than the global parameter dt
.
The process of decay is essentially exponential decline, since the outflow is a fraction of the stock. The rate of decay thus also exponentially declines towards zero if there is no inflow to the stock, that is connected to port A.
+If there is no inflow to the stock the level of the stock will be less than α x InitialLevel (0 < α <1) after a time span of - ln(α) × residenceTime.
+So we can note the following multiples for the residenceTime
to calculate the time it takes to drain the stock A to α [%] of its initial level:
α [%] | +Time to drain as multiple of the residenceTime |
+
50 | +
+ 0.69 ⋅ |
+
1/e ≈ 37 | +
+ 1.0 ⋅ |
+
10 | +
+ 2.3 ⋅ |
+
5 | +
+ 3.0 ⋅ |
+
1 | +
+ 4.6 ⋅ |
+
0.1 = 1 ‰ | +
+ 6.9 ⋅ |
+
The time span it takes to drain the stock by half is called its half life. As can be seen from the equation and table above it is about ln(2) ⋅ residenceTime
≈ 69% of the (average) residence time.
ProportionalTransition, ExponentialDecay
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {-1.392, -78.316}, textColor = {0, 0, 128}, extent = {{-81.392, -12}, {81.392, 12}}, textString = "residence time", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Decay", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {-60.264, -14.352}, rotation = 5.306, points = {{-32.722, 10.515}, {-16.1, -26.782}, {20.02, -35.205}, {44.243, -12.981}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Line(visible = true, origin = {-42.154, -19.63}, rotation = 5.306, points = {{36.522, -45.771}, {43.438, -34.535}, {45.906, -7.964}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {4, -26.505}, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}}), Polygon(visible = true, origin = {-15.474, -23.17}, rotation = -35, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {-5, -5}, {5, -5}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Decay; diff --git a/BusinessSimulation/Flows/Unidirectional/OutflowDynamicStock.mo b/BusinessSimulation/Flows/Unidirectional/OutflowDynamicStock.mo new file mode 100644 index 0000000..f3aebce --- /dev/null +++ b/BusinessSimulation/Flows/Unidirectional/OutflowDynamicStock.mo @@ -0,0 +1,36 @@ +within BusinessSimulation.Flows.Unidirectional; + +model OutflowDynamicStock "Outflow from a dynamic stock—the rate is set by the stock" + import BusinessSimulation.Units.Rate; + extends Interfaces.Basics.GenericFlow_Special; + extends Icons.Outflow; + extends Interfaces.Basics.ThreeSO_rate; +equation + portA.rate = portA.data; + portB.rate = -portA.rate; + // report the rate of flow at Port A + y = portA.rate; + y1 = portA.rate; + y2 = portA.rate; + // outflow must never be negative and the stopInflow flag must not be true at portB + assert(portA.rate >= 0, "Rate of outflow must never be negative", AssertionLevel.warning); + assert(not portB.stopInflow, "There must not be capacity restrictions (stopInflow) for the stock at portB"); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+OutflowDynamicStock can be used to model the outflow from a stock with inherent dynamic behavior (e.g. a conveyor or a higher-order delay). In these cases, the stock will set the flow and \"signal\" it via its →StockPort_Special. +
+Since neither negative outflows (after all, this is a unidirectional flow) nor preventing an outflow by \"stock control\" (e.g. the receiving stock at portB
has stopInflow = true
) are compatible with this flow element, the following assert
conditions will have breaches of these conditions cause errors that will stop the simulation:
assert(portA.rate >= 0, \"Rate of outflow must never be negative\");+
assert(not portB.stopInflow, \"There must not be capacity restrictions (stopInflow) for the stock at portB\");
OutflowDynamicStock
flow will not observe the stopInflow
flag of a stock connected to the B-side port. This means that the receiving stock must have sufficient capacity for the mass flowing out and capacity restrictions have to be imposed by an explicit control structure.SplitOutflowDynamicStock
should be used.SplitOutflowDynamicStock
can be used with some fraction of the outflow being directed into a →Cloud.This information is part of the Business Simulation Library (BSL).
+The rate of transition from stock A to stock B will be propotional to the amount in stock A:
rate = fractionalRate ⋅ stockA.y
Since this is a unidirectional flow, the rate of flow will automatically be set to zero (causing an event), if the given rate of transition is a negative value.
+This information is part of the Business Simulation Library (BSL).
+The SplitOutflowDynamicStock is used to model the outflow from a stock with inherent dynamic behavior(e.g. a conveyor or a higher-order delay). In these cases, the stock will set the rate of flow and \"signal\" it via its →StockPort_Special.
+The total outflow is split proportionally according to given weights either given as a vector of parameters or as a vector of inputs u.
+The proportional split is done using fractions derived from the weights as described for the converter →ProportionalSplitFactors.
+This information is part of the Business Simulation Library (BSL).
+This is the prototypical unidirectional flow of mass from stock A to stock B at a given rate. The rate can be either constant (rate
) or given by the continuous input u.
Since this is a unidirectional flow the rate of flow will always be set to zero (causing an event) if the given rate of transition is a negative value.
+See also
+ +"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-42.154, -19.63}, rotation = 5.306, points = {{36.522, -45.771}, {43.438, -34.535}, {45.906, -7.964}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {4, -26.925}, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}}), Text(visible = true, origin = {-5.905, -73.77}, textColor = {0, 0, 128}, extent = {{-34.095, -12}, {34.095, 12}}, textString = "rate", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Transition", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Transition; diff --git a/BusinessSimulation/Flows/Unidirectional/package.mo b/BusinessSimulation/Flows/Unidirectional/package.mo new file mode 100644 index 0000000..c94c6b6 --- /dev/null +++ b/BusinessSimulation/Flows/Unidirectional/package.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Flows; + +package Unidirectional "Transition from one stock to another" + extends Icons.Package annotation(Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains unidirectional flows of the System Dynamics method that can be used to model a transition from one stock to another. A transition can be understood as the continuous movement of some form of mass from one state to another at a specific rate.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This package contains flow elements of the System Dynamics method.
++Tutorial.ElementaryBuildingBlocks +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The function takes a vector of Booleans and will return true, if all of the elements in the input vector is true, and false otherwise.
+Function.allTrueQ(vec);+
Function.allTrueQ({false, false, false}); // false
Function.allTrueQ({true, true, true}); // true+
Function.allTrueQ({false, false, true}); // false+
This information is part of the Business Simulation Library (BSL).
+The output y is the arithmetic mean of the components of the input vector x. As a second argument a vector of positive weights (default = 1 for each weight) can be given to calculate the weighted arithmetic mean.
+Functions.arithmeticMean(x);
+Functions.arithmeticMean(x, weights);
w := BusinessSimulation.Functions.clip(weights, {0, inf}); + y := sum(x[i] * w[i] for i in 1:n) / sum(w);
+Functions.arithmeticMean({ 10, 20}); // 15.0 +Functions.arithmeticMean({-20, 20}); // 0.0 +Functions.arithmeticMean({ 10, 20},{1,10}); // 19.09.. +Functions.arithmeticMean({ 10, 20},{1,-1}); // 10. ++
+ArithmeticMean, +geometricMean +
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end arithmeticMean; diff --git a/BusinessSimulation/Functions/boole.mo b/BusinessSimulation/Functions/boole.mo new file mode 100644 index 0000000..3bbaa38 --- /dev/null +++ b/BusinessSimulation/Functions/boole.mo @@ -0,0 +1,17 @@ +within BusinessSimulation.Functions; + +function boole "Returns 1.0 if input is true, and 0.0 otherwise" + extends BusinessSimulation.Icons.Function; + input Boolean u "Boolean input"; + output Real y "Real output"; +algorithm + y := if noEvent(u == true) then 1. else 0.; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function returns 1.0 if the Boolean input u is true
and 0.0 in all other cases.
Functions.boole(u)
Functions.boole(true); // 1.0+ "), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end boole; diff --git a/BusinessSimulation/Functions/clip.mo b/BusinessSimulation/Functions/clip.mo new file mode 100644 index 0000000..cc60c41 --- /dev/null +++ b/BusinessSimulation/Functions/clip.mo @@ -0,0 +1,25 @@ +within BusinessSimulation.Functions; + +function clip "Clip values so they do not extend beyond a given interval" + extends BusinessSimulation.Icons.Function; + input Real x[:] "List of values to be clipped"; + input Real[2] interval = {-1, 1} "Interval [min,max] given as a list (default = {-1,1})"; + output Real y[size(x, 1)] "Clipped values"; +protected + Integer n = size(x, 1) "Length of the input vector x"; +algorithm + for i in 1:n loop + y[i] := if x[i] < interval[1] then interval[1] elseif x[i] > interval[2] then interval[2] else x[i]; + end for; + annotation(Documentation(info = " +
Functions.notZeroQ(false); // 0.0
This information is part of the Business Simulation Library (BSL).
+The function will clip a list of input values x
so that any component x_i
of x
will be x_i
for min ≤ x_i ≤ max
, min
for x_i < min
, and max
for x_i > max
.
Function.clip(x); // {min, max} = {-1,1}+
Function.clip(x, {min, max});
Function.clip({-3,-2,-1,0,1,2,3}); // {-1,-1,-1,0,1,1,1}+
Function.clip({-3,-2,-1,0,1,2,3},{-2,2}); // {-2,-2,-1,0,1,2,2}
This function is closely modeled to Clip
in the Wolfram Language.
This information is part of the Business Simulation Library (BSL).
+The real output actualRate
is determined by checking whether the real input indicatedRate
is complying with the restrictions signaled by a connected stock in form of the boolean flags stopInflow
and stopOutflow
. If the rate is found to violate either flag 0 is returned, in all other cases the indicated rate
is returned unchanged.
Functions.constrainedRate(indicatedRate, stopInflow, stopOutflow)
Functions.constrainedRate(-5.0, stopInflow = true, stopOutflow = false); // 0.0+
Functions.constrainedRate( 5.0, stopInflow = true, stopOutflow = false); // 5.0
Functions.constrainedRate(-5.0, stopInflow = false, stopOutflow = true); // -5.0
Functions.constrainedRate( 5.0, stopInflow = false, stopOutflow = true); // 0.0
Rates are usually set by flow components and have to observe the flow-restrictions with regard to a connected stock component. By Modelica conventions a negative rate for the flow indicates an inflow with regard to the connected stock, while a positive rate indicates an outflow for the stock.
+Thus, in the first example above the indicated negative rate for a →FlowPort would mean an outflow from the flow component and an inflow with regard to the connected →StockPort. Observing the flow restriction signaled by the stock the acutal rate is set to zero.
+This information is part of the Business Simulation Library (BSL).
+The real output actualRate
is determined by checking whether the real input indicatedRate
is complying with the restrictions signaled by a connected stock in form of the boolean flags stopInflow
and stopOutflow
. If the rate is found to violate either flag false
is returned, in all other cases true
is returned.
Functions.constrainedRateBoolean(indicatedRate, stopInflow, stopOutflow)
Functions.constrainedRateBoolean(-5.0, stopInflow = true, stopOutflow = false); // false+
Functions.constrainedRateBoolean( 5.0, stopInflow = true, stopOutflow = false); // true
Functions.constrainedRateBoolean(-5.0, stopInflow = false, stopOutflow = true); // true
Functions.constrainedRateBoolean( 5.0, stopInflow = false, stopOutflow = true); // false
Rates are usually set by flow components and have to observe the flow-restrictions with regard to a connected stock component. By Modelica conventions a negative rate for the flow indicates an inflow with regard to the connected stock, while a positive rate indicates an outflow for the stock.
+Thus, in the first example above the indicated negative rate for a →FlowPort would mean an outflow from the flow component and an inflow with regard to the connected →StockPort. Observing the flow restriction signaled by the stock false
is returned.
This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using the membership function specified.
+Functions.evalmf(x, mft, a, b, c, d);
+
+Functions.evalmf( 5, mft = MembershipFunctionTypes.trapezoid, a=2, b=4, c=6, d=8); // 1.0 +
+
rampmf, +trapmf, +trimf, +smf, +sigmf, +pimf, +psigmf, +gaussmf, +gbellmf +
")); +end evalmf; diff --git a/BusinessSimulation/Functions/gaussmf.mo b/BusinessSimulation/Functions/gaussmf.mo new file mode 100644 index 0000000..2d8efec --- /dev/null +++ b/BusinessSimulation/Functions/gaussmf.mo @@ -0,0 +1,41 @@ +within BusinessSimulation.Functions; + +function gaussmf "Gaussian membership function" + extends BusinessSimulation.Icons.Function; + input Real x "Input value for which the degree of membership is to be computed"; + input Real a "Half width at half maximum (HWHM)"; + input Real c "Mean value"; + output Real y "Degree of membership"; +protected + // sigma = a/ sqrt(log(4)) + Real sigma = a / 1.177410022515474691; +algorithm + y := exp(-(x - c) ^ 2 / (2 * sigma ^ 2)); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a Gaussian function given the real input x and the parameters half width at half maximum a
and mean c
.
sigma = a / 1.177410022515474691; +y := exp(-(x - c) ^ 2 / (2 * sigma ^ 2));+
Functions.gaussmf(x, a, c);
+
Functions.gaussmf( 5, a=2, c=5); // 1.0 +Functions.gaussmf( 3, a=2, c=5); // 0.5 +Functions.gaussmf( 7, a=2, c=5); // 0.5
+
+evalmf, +rampmf, +trimf, +trapmf, +smf, +sigmf, +pimf, +psigmf, +gbellmf +
")); +end gaussmf; diff --git a/BusinessSimulation/Functions/gbellmf.mo b/BusinessSimulation/Functions/gbellmf.mo new file mode 100644 index 0000000..761212f --- /dev/null +++ b/BusinessSimulation/Functions/gbellmf.mo @@ -0,0 +1,38 @@ +within BusinessSimulation.Functions; + +function gbellmf "Generalized bell-shaped membership function" + extends BusinessSimulation.Icons.Function; + input Real x "Input value for which the degree of membership is to be computed"; + input Real a "Width of core (i.e. the interval for which the function gives 1)"; + input Real b "Shape parameter (larger values → steeper transition"; + input Real c "Center of membership function"; + output Real y "Degree of membership"; +algorithm + y := 1 / (1 + abs((x - c) / a) ^ (2 * b)); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a generalized bell-shaped function given the real input x and the parameters width of core a
, shape parameter b
, and the center value c
.
y := 1 / (1 + abs((x - c) / a) ^ (2 * b));+
Functions.gbellmf(x, a, b, c);
+
Functions.gbellmf( 6, a=2, b=4, c=6); // 1.0 +Functions.gbellmf( 4, a=2, b=4, c=6); // 0.5 +Functions.gbellmf( 8, a=2, b=4, c=6); // 0.5
+
+evalmf, +rampmf, +trimf +trapmf, +smf, +sigmf, +pimf, +psigmf, +gaussmf, +
")); +end gbellmf; diff --git a/BusinessSimulation/Functions/geometricMean.mo b/BusinessSimulation/Functions/geometricMean.mo new file mode 100644 index 0000000..f094db0 --- /dev/null +++ b/BusinessSimulation/Functions/geometricMean.mo @@ -0,0 +1,45 @@ +within BusinessSimulation.Functions; + +function geometricMean "(Weighted) geometric mean" + import BusinessSimulation.Constants.{inf,small}; + extends BusinessSimulation.Icons.Function; + input Real[:] x "Vector input"; + input Real[size(x, 1)] weights = ones(size(x, 1)) "Vector of weights"; + output Real y; +protected + Real[n] w "Normalized and clipped weights"; + constant Integer n = size(x, 1) "Length of the input vector"; +algorithm + // clip weights to eliminate negative values + w := BusinessSimulation.Functions.clip(weights, {0, inf}); + y := if min(x) < small then 0 else exp(sum(log(x[i]) * w[i] for i in 1:n) / sum(w)); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is the geometric mean of the components of the input vector x. As a second argument a vector of positive weights (default = 1 for each weight) can be given to calculate the weighted geometric mean.
+Functions.geometricMean(x);
+Functions.geometricMean(x, weights);
w := BusinessSimulation.Functions.clip(weights, {0, inf}); + y := if min(x) < small then 0 else exp( sum( log(x[i]) * w[i] for i in 1:n ) / sum(w) );
+Functions.geometricMean({10, 20}); // 14.1421.. +Functions.geometricMean({ 0, 20}); // 0.0 +Functions.geometricMean({10, 20},{1,10}); // 18.7786.. +Functions.geometricMean({10, 20},{1,-1}); // 10. ++
+GeometricMean, +arithmeticMean +
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end geometricMean; diff --git a/BusinessSimulation/Functions/janoschek.mo b/BusinessSimulation/Functions/janoschek.mo new file mode 100644 index 0000000..284e65a --- /dev/null +++ b/BusinessSimulation/Functions/janoschek.mo @@ -0,0 +1,26 @@ +within BusinessSimulation.Functions; + +function janoschek "Janoschek's Growth Curve" + extends BusinessSimulation.Icons.Function; + input Real x "x-Value"; + input Real b "Lower asymptote"; + input Real l "Upper asymptote"; + input Real k "Growth rate"; + input Real d "Control of abscissa for the point of inflection"; + output Real y; +algorithm + y := l - (l - b) * exp(-k * x ^ d); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This function models Janoschek's growth curve [19] given the real input x and the specifying real inputs b, l, k, d
. The formula for the real output y is:
y := 1 - (l - b) * exp(-k * x ^ d);
Functions.janoschek(x, b, l, k, d);
BusinessSimulation.Functions.janoschek(2, b = 0, l = 2, k = 2, d = 1); // 1.963369+
JanoschekPositive, JanoschekNegative
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end janoschek; diff --git a/BusinessSimulation/Functions/noneTrueQ.mo b/BusinessSimulation/Functions/noneTrueQ.mo new file mode 100644 index 0000000..bcd887f --- /dev/null +++ b/BusinessSimulation/Functions/noneTrueQ.mo @@ -0,0 +1,29 @@ +within BusinessSimulation.Functions; + +function noneTrueQ "Gives true, if no element in a vector of Booleans is true" + extends BusinessSimulation.Icons.Function; + input Boolean x[:] "Vector of booleans"; + output Boolean y "True, if no element of the input vector is true"; +protected + Integer n = size(x, 1) "Length of the input vector x"; +algorithm + y := true; + for i in 1:n loop + y := y and not x[i]; + end for; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function takes a vector of Booleans and will return true, if none of the elements in the input vector is true, and false otherwise.
+Function.noneTrueQ(vec);+
Function.noneTrueQ({false, false, false}); // true
Function.noneTrueQ({true, false, false}); // false+
Function.noneTrueQ({false, false, true}); // false+
This information is part of the Business Simulation Library (BSL).
+The function returns false
if the real input x is zero and true
in all other cases.
Functions.notZeroQ(x)
import BusinessSimulation.Constants.small;+
Functions.notZeroQ(0.0); // false
Functions.notZeroQ(1.2); // true
Functions.notZeroQ(-5); // true
Functions.notZeroQ(small); // true
This functions is somewhat like an \"inverse\" Boole.
+This information is part of the Business Simulation Library (BSL).
+This pacakge contains functions used in the library.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a Pi-shaped function given the real input x and the parameters foot of the s-shaped part a
, shoulder of the s-shaped part b
, shoulder of the z-shaped part c
, and foot of the z-shaped part d
of the function.
y := if x <= a then 0 + elseif a < x and x <= midpointS then 2 * ((x - a) / (b - a)) ^ 2 + elseif midpointS < x and x <= b then 1 - 2 * ((x - b) / (b - a)) ^ 2 + elseif b < x and x <= c then 1 + elseif c < x and x <= midpointZ then 1 - 2 * ((x - c) / (d - c)) ^ 2 + elseif midpointZ < x and x <= d then 2 * ((x - d) / (d - c)) ^ 2 + else 1;+
Functions.pimf(x, a, b, c, d);
+
Functions.pimf( 5, a=1, b=4, c=5, d=10); // 1.0 +Functions.pimf( 2.5, a=1, b=4, c=5, d=10); // 0.5 +Functions.pimf( 1, a=1, b=4, c=5, d=10); // 0.0 +Functions.pimf( 7.5, a=1, b=4, c=5, d=10); // 0.5 +Functions.pimf( 10, a=1, b=4, c=5, d=10); // 0.0 +
+
+evalmf, +rampmf, +trimf, +trapmf, +smf, +sigmf, +psigmf, +gaussmf, +gbellmf +
")); +end pimf; diff --git a/BusinessSimulation/Functions/polynomialFunction.mo b/BusinessSimulation/Functions/polynomialFunction.mo new file mode 100644 index 0000000..1160e4b --- /dev/null +++ b/BusinessSimulation/Functions/polynomialFunction.mo @@ -0,0 +1,25 @@ +within BusinessSimulation.Functions; + +function polynomialFunction "Polynomial function of degree n" + extends BusinessSimulation.Icons.Function; + input Real x "Independent variable"; + input Real a[:] "Vector of coefficients"; + output Real y "Value of the polynomial equation"; +protected + Integer i; + constant Integer n = size(a, 1); +algorithm + y := 0; + for i in 1:n loop + y := y + a[i] * x ^ (i - 1); + end for; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function returns the value of the n-th degree polynomial given the real input x and the real vector of coefficients a[:] = {a_0, a_1, ..., a_n}
where the degree of the polynomial is n = size(a,1) - 1
.
Functions.polynomialFunction(x,a);
+
Functions.polynomialFunction( 2, { 0,0,1}); // 4.0
Functions.polynomialFunction( 2, {-6,1,1}); // 0.0
This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using the product of two sigmoidal functions given the real input x and the parameters shape parameter for the s-shaped transition area a
, center of the s-shaped transition area b
, shape parameter of the z-shaped transition area c
, and center of the z-shaped transition area d
of the function.
y := sigmf(x, a = a, c = b) * sigmf(x, a = -c, c = d);+
Functions.psigmf(x, a, b, c, d);
+
+Functions.psigmf( 8, a=2, b=3, c=5, d=8); // 0.4999773.. +Functions.psigmf( 6.9, a=2, b=3, c=5, d=8); // 0.9955219.. +Functions.psigmf( 3, a=2, b=3, c=5, d=8); // 0.4999999.. +Functions.psigmf( 10, a=2, b=3, c=5, d=8); // 4.53978e-05 +
+
+evalmf, +rampmf, +trimf, +trapmf, +smf, +sigmf, +gaussmf, +gbellmf +
")); +end psigmf; diff --git a/BusinessSimulation/Functions/rampmf.mo b/BusinessSimulation/Functions/rampmf.mo new file mode 100644 index 0000000..c1c3ea5 --- /dev/null +++ b/BusinessSimulation/Functions/rampmf.mo @@ -0,0 +1,38 @@ +within BusinessSimulation.Functions; + +function rampmf "Bounded ramp membership function" + extends BusinessSimulation.Icons.Function; + input Real x "Input value for which the degree of membership is to be computed"; + input Real a "Lower bound"; + input Real b "Upper bound"; + output Real y "Degree of membership"; +algorithm + y := max(min((x - a) / (b - a), 1), 0); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a bounded ramp function given the real input x and the parameters lower bound a
and upper bound b
.
The ramp will usually ramp up from 0 to 1, but if lower bound and upper bound are switched (i.e. a > b
), then the ramp will be ramp downwards from 1 to 0.
y := max(min((x - a) / (b - a), 1), 0);+
Functions.rampmf(x, a, b);
+
Functions.rampmf( 5, a=2, b=8); // 0.5 +Functions.rampmf( 1, a=2, b=8); // 0.0 +Functions.rampmf( 9, a=2, b=8); // 1.0
+
+evalmf, +trimf, +trapmf, +smf, +sigmf, +pimf, +psigmf, +gaussmf, +gbellmf +
")); +end rampmf; diff --git a/BusinessSimulation/Functions/rescale.mo b/BusinessSimulation/Functions/rescale.mo new file mode 100644 index 0000000..d23490f --- /dev/null +++ b/BusinessSimulation/Functions/rescale.mo @@ -0,0 +1,29 @@ +within BusinessSimulation.Functions; + +function rescale "Rescale values from one range to another" + extends BusinessSimulation.Icons.Function; + input Real x "Value to be transformed"; + input Real x_range[2] "Original range [min,max] given as a list"; + input Real y_range[2] = {0, 1} "Rescaled range [y_min, y_max] given as a list (default = {0,1})"; + output Real y "Rescaled value to run from y_min to y_max over the range min to max"; +protected + Real x_min = x_range[1]; + Real x_max = x_range[2]; + Real y_min = y_range[1]; + Real y_max = y_range[2]; +algorithm + y := y_min + (x - x_min) * (y_max - y_min) / (x_max - x_min) annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function will rescale the input to run from range y_min
to y_max
over the range min
to max
.
Function.rescale(x, {x_min, x_max}); // {y_min, y_max} by default assumed to be {0,1}+
Function.rescale(x, {min, max}, {y_min, y_max});
Function.rescale(5, {0, 10}); // 0.5+
Function.rescale(5, {0, 10}, {10, 20}); // 15.
This function is closely modeled to Rescale
in the Wolfram Language.
This information is part of the Business Simulation Library (BSL).
+The function will rescale the input vector to a vector whose elements run from range y_min
to y_max
over the range min
to max
.
Function.rescale(vec); // {min, max} = {min(vec), max(vec)};{y_min, y_max} = {0,1}+
Function.rescale(vec, {min, max}); // {y_min,y_max} = {0,1}
Function.rescale(vec, {min, max}, {y_min, y_max});
Function.rescale({0,1,2,3,4,5,6,7,8,9,10}); // {0.,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0}+
Function.rescale({4,5,6},{0, 10}); // {0.4, 0.5, 0.6}
Function.rescale({4,5,6},{0,10},{10,20}); // {14.,15.,16.}
This function is closely modeled to Rescale
in the Wolfram Language.
This information is part of the Business Simulation Library (BSL).
+The function will return a list shifted by n
places (n < 0
⇒ shift to the left), where the elements \"pushed\" out of range are added up and reported as carry
. The gaps will be shifted with the real value fill
, which by default is set to 0.
Functions.shiftList( list, n ); // fill by default is set to zero+
Functions.shiftList( list, n, fill ); // explicitly give a real value for fill
shiftList( {1, 2, 3, 4, 5}, 0); // ( {1, 2, 3, 4, 5}, 0. )", revisions = ""), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end shiftList; diff --git a/BusinessSimulation/Functions/sigmf.mo b/BusinessSimulation/Functions/sigmf.mo new file mode 100644 index 0000000..5f25d89 --- /dev/null +++ b/BusinessSimulation/Functions/sigmf.mo @@ -0,0 +1,39 @@ +within BusinessSimulation.Functions; + +function sigmf "Sigmoidal membership function" + extends BusinessSimulation.Icons.Function; + input Real x "Input value for which the degree of membership is to be computed"; + input Real a "Shape parameter controlling the width of s-shaped transition area (higher values → steeper transition)"; + input Real c "Center of the s-shaped transition area"; + output Real y "Degree of membership"; +algorithm + y := 1 / (1 + exp(-a * (x - c))); + annotation(Documentation(info = " +
shiftList( {1, 2, 3, 4, 5}, -2); // ( {3, 4, 5, 0, 0}, 3. )
shiftList( {1, 2, 3, 4, 5}, 2); // ( {0, 0, 1, 2, 3}, 9. )
This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a sigmoid function function given the real input x and the parameters shape parameter to control width of transition area a
and center of transition area c
.
The sigmoid function will increase from 0 to 1 for positive values of a
, while negative values will give rise to a z-shaped transition.
y := 1 / (1 + exp(-a * (x - c)));+
Functions.sigmf(x, a, c);
+
Functions.sigmf( 4, a=2, c=4); // 0.5 +Functions.sigmf( 2, a=2, c=4); // 0.0179862.. +Functions.sigmf( 6, a=2, c=4); // 0.98201379..
+
+evalmf, +rampmf, +trimf, +trapmf, +smf, +sigmf, +pimf, +psigmf, +gaussmf, +gbellmf +
")); +end sigmf; diff --git a/BusinessSimulation/Functions/smf.mo b/BusinessSimulation/Functions/smf.mo new file mode 100644 index 0000000..051fe44 --- /dev/null +++ b/BusinessSimulation/Functions/smf.mo @@ -0,0 +1,43 @@ +within BusinessSimulation.Functions; + +function smf "S-shaped membership function" + extends BusinessSimulation.Icons.Function; + input Real x "Input value for which the degree of membership is to be computed"; + input Real a "Foot of the function (i.e. f(a) = 0)"; + input Real b "Shoulder of the function (i.e. f(b) = 1)"; + output Real y "Degree of membership"; +protected + Real midpoint = (a + b) / 2; +algorithm + y := if x <= a then 0 elseif a < x and x <= midpoint then 2 * ((x - a) / (b - a)) ^ 2 + elseif midpoint < x and x <= b then 1 - 2 * ((x - b) / (b - a)) ^ 2 else 1; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a S-shaped function given the real input x and the parameters foot a
and shoulder b
of the function.
y := if x <= a then 0 + elseif a < x and x <= midpoint then 2 * ( (x-a)/(b-a) )^2 + elseif midpoint < x and x <= b then 1 - 2 * ( (x-b)/(b-a) )^2 + else 1;+
Functions.smf(x, a, b);
+
Functions.smf( 5, a=2, b=8); // 0.5 +Functions.smf( 1, a=2, b=8); // 0.0 +Functions.smf( 9, a=2, b=8); // 1.0
+
+evalmf, +rampmf, +trimf, +trapmf, +sigmf, +pimf, +psigmf, +gaussmf, +gbellmf +
")); +end smf; diff --git a/BusinessSimulation/Functions/stringToTimeBase.mo b/BusinessSimulation/Functions/stringToTimeBase.mo new file mode 100644 index 0000000..cbccfce --- /dev/null +++ b/BusinessSimulation/Functions/stringToTimeBase.mo @@ -0,0 +1,23 @@ +within BusinessSimulation.Functions; + +function stringToTimeBase "Find the corresponding element of the TimeBases enumeration for a given time base string" + extends BusinessSimulation.Icons.Function; + import BusinessSimulation.Types.TimeBases; + import Modelica.Utilities.Strings.isEqual; + input String timeBaseString "String for a time base given in lower case"; + output TimeBases timeBase "Element in the enumeration corresponding to the string given"; +protected + constant Boolean ignoreCase = false "= true, to set caseSensitive flag to true"; +algorithm + timeBase := if isEqual(timeBaseString, "minute", ignoreCase) or isEqual(timeBaseString, "min", ignoreCase) then TimeBases.minutes else if isEqual(timeBaseString, "hour", ignoreCase) or isEqual(timeBaseString, "hours", ignoreCase) or isEqual(timeBaseString, "h", ignoreCase) then TimeBases.hours else if isEqual(timeBaseString, "day", ignoreCase) or isEqual(timeBaseString, "days", ignoreCase) or isEqual(timeBaseString, "d", ignoreCase) then TimeBases.days else if isEqual(timeBaseString, "week", ignoreCase) or isEqual(timeBaseString, "weeks", ignoreCase) or isEqual(timeBaseString, "wk", ignoreCase) then TimeBases.weeks else if isEqual(timeBaseString, "month", ignoreCase) or isEqual(timeBaseString, "months", ignoreCase) or isEqual(timeBaseString, "mo", ignoreCase) then TimeBases.months else if isEqual(timeBaseString, "quarter", ignoreCase) or isEqual(timeBaseString, "quarters", ignoreCase) or isEqual(timeBaseString, "qtr", ignoreCase) then TimeBases.quarters else if isEqual(timeBaseString, "year", ignoreCase) or isEqual(timeBaseString, "years", ignoreCase) or isEqual(timeBaseString, "yr", ignoreCase) then TimeBases.years else TimeBases.seconds; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function will return the element of the enumeration Types.TimeBases
that corresponds to a given unit of time given as a string. The string should be given in lower case letters and should be given either as a word or the unit symbol. If there is no match, the function will default to TimeBases.second
.
Functions.stringToTimeBase( timeBaseString ); // the string is to be given as lower case+
stringToTimeBase( \"month\" ); // TimesBases.months+"), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end stringToTimeBase; diff --git a/BusinessSimulation/Functions/trapmf.mo b/BusinessSimulation/Functions/trapmf.mo new file mode 100644 index 0000000..95f3c1c --- /dev/null +++ b/BusinessSimulation/Functions/trapmf.mo @@ -0,0 +1,40 @@ +within BusinessSimulation.Functions; + +function trapmf "Trapezoidal membership function" + extends BusinessSimulation.Icons.Function; + input Real x "Input value for which the degree of membership is to be computed"; + input Real a "Lower bound for the support (i.e. f(a) = 0)"; + input Real b "Lower bound for the core (i.e. f(b) = 1)"; + input Real c "Upper bound for the core (i.e. f(c) = 1)"; + input Real d "Upper bound for the support(i.e. f(d) = 0)"; + output Real y "Degree of membership"; +algorithm + y := max(min(1, min((x - a) / (b - a), (d - x) / (d - c))), 0); + annotation(Documentation(info = " +
stringToTimeBase( \"yr\" ); // TimeBases.years
This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a trapezoidal function given the real input x and the parameters lower bound of the support a
, the lower bound of the core b
, the upper bound of the core c
, and the upper bound of the support d
.
y := max( min( 1, min( (x - a)/(b - a), (d - x)/(d - c)) ), 0 );+
Functions.trapmf(x, a, b, c, d);
+
Functions.trapmf( 5, a=2, b=4, c=6, d=8); // 1.0 +Functions.trapmf( 2, a=2, b=4, c=6, d=8); // 0.0 +Functions.trapmf( 9, a=2, b=4, c=6, d=8); // 0.0 +Functions.trapmf( 7, a=2, b=4, c=6, d=8); // 0.5
+
+evalmf, +rampmf, +trimf, +smf, +sigmf, +pimf, +psigmf, +gaussmf, +gbellmf +
")); +end trapmf; diff --git a/BusinessSimulation/Functions/trimf.mo b/BusinessSimulation/Functions/trimf.mo new file mode 100644 index 0000000..3899b26 --- /dev/null +++ b/BusinessSimulation/Functions/trimf.mo @@ -0,0 +1,38 @@ +within BusinessSimulation.Functions; + +function trimf "Triangular membership function" + extends BusinessSimulation.Icons.Function; + input Real x "Input value for which the degree of membership is to be computed"; + input Real a "Lower bound (i.e. f(a) = 0)"; + input Real b "Peak (i.e. f(b) = 1)"; + input Real c "Upper bound (i.e. f(c) = 0)"; + output Real y "Degree of membership"; +algorithm + y := max(min((x - a) / (b - a), (c - x) / (c - b)), 0); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The function returns the degree of membership using a triangular function given the real input x and the parameters lower bound of the support a
, the upper bound of the support c
and the peak or core value b
.
y := max(min((x - a) / (b - a), (c - x) / (c - b)), 0);+
Functions.trimf(x, a, b, c);
+
Functions.trimf( 5, a=2, b=5, c=8); // 1.0 +Functions.trimf( 1, a=2, b=5, c=8); // 0.0 +Functions.trimf( 9, a=2, b=5, c=8); // 0.0
+
+evalmf, +rampmf, +trapmf, +smf, +sigmf, +pimf, +psigmf, +gaussmf, +gbellmf +
")); +end trimf; diff --git a/BusinessSimulation/Icons/BasesPackage/package.mo b/BusinessSimulation/Icons/BasesPackage/package.mo new file mode 100644 index 0000000..491cadb --- /dev/null +++ b/BusinessSimulation/Icons/BasesPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package BasesPackage "Base class package icon" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {128, 128, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-30, -30}, {30, 30}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BasesPackage; diff --git a/BusinessSimulation/Icons/BidirectionalFlow.mo b/BusinessSimulation/Icons/BidirectionalFlow.mo new file mode 100644 index 0000000..db3d875 --- /dev/null +++ b/BusinessSimulation/Icons/BidirectionalFlow.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class BidirectionalFlow "Icon for bidirectional flow classes" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-100, -100}, {100, 100}}), Polygon(visible = true, origin = {-72.424, 0}, rotation = 450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{22.295, -7.943}, {-22.191, -7.943}, {-0.104, 15.886}}), Polygon(visible = true, origin = {72.114, -0.25}, rotation = -450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Line(visible = true, origin = {-0.91, -11.973}, points = {{-67.505, 0}, {67.505, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {-0.152, 11.777}, points = {{-67.808, 0}, {67.808, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1), Text(visible = true, origin = {-73.452, 37.479}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "A"), Text(visible = true, origin = {73.452, -43.134}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "B"), Text(visible = true, origin = {2, 0}, textColor = {255, 255, 255}, extent = {{-16.513, -12}, {16.513, 12}}, textString = "X", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {74, 1}, textColor = {255, 255, 255}, extent = {{-13.452, -12}, {13.452, 12}}, textString = "+", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-74.548, 2}, textColor = {255, 255, 255}, extent = {{-13.452, -12}, {13.452, 12}}, textString = "–", fontName = "Lato", textStyle = {TextStyle.Bold}), Ellipse(visible = true, origin = {1.899, 0}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-17, -17}, {17, 17}}), Text(visible = true, origin = {2, 0}, textColor = {255, 255, 255}, extent = {{-16.513, -12}, {16.513, 12}}, textString = "X", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BidirectionalFlow; diff --git a/BusinessSimulation/Icons/CapacityLabel.mo b/BusinessSimulation/Icons/CapacityLabel.mo new file mode 100644 index 0000000..297e210 --- /dev/null +++ b/BusinessSimulation/Icons/CapacityLabel.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class CapacityLabel "Mark stock element as having capacity restrictions" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {61.092, 75}, textColor = {128, 0, 128}, extent = {{-28.908, -20}, {28.908, 20}}, textString = "CPTY", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end CapacityLabel; diff --git a/BusinessSimulation/Icons/Clockface.mo b/BusinessSimulation/Icons/Clockface.mo new file mode 100644 index 0000000..17dcde2 --- /dev/null +++ b/BusinessSimulation/Icons/Clockface.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class Clockface "Face of a clock" + annotation(__Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, lineThickness = 4, extent = {{-100, -100}, {100, 100}}), Ellipse(visible = true, rotation = -30, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, extent = {{45, -45}, {-45, 45}}, startAngle = 60, endAngle = 150), Line(visible = true, origin = {34.536, 20.464}, rotation = 300, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {20.5, 33.33}, rotation = -30, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {0, 39.149}, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {-19.464, 33.464}, rotation = 30, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-34.5, 19.33}, rotation = -300, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-40, 0}, rotation = -270, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-33.464, -20.536}, rotation = 300, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-19.5, -34.67}, rotation = -30, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {0, -39.851}, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {20.536, -33.536}, rotation = 30, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {33.5, -19.67}, rotation = -300, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {39.55, -0.72}, rotation = -270, points = {{0, 5}, {0, -5}}, color = {128, 128, 128}, thickness = 2.5, arrowSize = 0), Ellipse(visible = true, rotation = 30, lineColor = {128, 128, 128}, fillColor = {255, 255, 255}, lineThickness = 2.5, extent = {{-45, -45}, {45, 45}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Clockface; diff --git a/BusinessSimulation/Icons/Clockface_white.mo b/BusinessSimulation/Icons/Clockface_white.mo new file mode 100644 index 0000000..c8f0ea5 --- /dev/null +++ b/BusinessSimulation/Icons/Clockface_white.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class Clockface_white "Face of a clock" + annotation(__Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, lineThickness = 4, extent = {{-100, -100}, {100, 100}}), Line(visible = true, origin = {34.536, 20.464}, rotation = 300, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {20.5, 33.33}, rotation = -30, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {0, 39.149}, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {-19.464, 33.464}, rotation = 30, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-34.5, 19.33}, rotation = -300, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-40, 0}, rotation = -270, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-33.464, -20.536}, rotation = 300, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 1), Line(visible = true, origin = {-19.5, -34.67}, rotation = -30, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {0, -39.851}, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {20.536, -33.536}, rotation = 30, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {33.5, -19.67}, rotation = -300, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {39.55, -0.72}, rotation = -270, points = {{0, 5}, {0, -5}}, color = {255, 255, 255}, thickness = 2.5, arrowSize = 0), Ellipse(visible = true, rotation = 30, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, lineThickness = 2.5, extent = {{-45, -45}, {45, 45}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Clockface_white; diff --git a/BusinessSimulation/Icons/ComponentName.mo b/BusinessSimulation/Icons/ComponentName.mo new file mode 100644 index 0000000..39bf956 --- /dev/null +++ b/BusinessSimulation/Icons/ComponentName.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class ComponentName "Component name for Icon View" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {-0, -125}, textColor = {64, 64, 64}, extent = {{-150, -12}, {150, 12}}, textString = "%name", fontName = "Lato ")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ComponentName; diff --git a/BusinessSimulation/Icons/ConnectorsPackage/package.mo b/BusinessSimulation/Icons/ConnectorsPackage/package.mo new file mode 100644 index 0000000..0cbafd1 --- /dev/null +++ b/BusinessSimulation/Icons/ConnectorsPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package ConnectorsPackage "Icon for a connector package" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, origin = {-40, -40}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}}), Rectangle(visible = true, origin = {-40, 40}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-22.954, -21.871}, {22.954, 21.871}}), Polygon(visible = true, origin = {121.766, -37.967}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {-51.766, 78.102}, {-100, 55.933}, {-100, 100}}), Polygon(visible = true, origin = {45, -42.5}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 3, points = {{-20, 12.5}, {20, 12.5}, {25, 7.5}, {20, -10}, {15, -12.5}, {-15, -12.5}, {-20, -10}, {-25, 7.5}}, smooth = Smooth.Bezier)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConnectorsPackage; diff --git a/BusinessSimulation/Icons/ConstantConverter.mo b/BusinessSimulation/Icons/ConstantConverter.mo new file mode 100644 index 0000000..2e68482 --- /dev/null +++ b/BusinessSimulation/Icons/ConstantConverter.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial block ConstantConverter "Icon for constant converter elements" + extends ConstantConverterName; + annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-28.253, -28.253}, {28.253, 28.253}}), Line(visible = true, rotation = -270, points = {{0, 40}, {0, -40}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0)})); +end ConstantConverter; diff --git a/BusinessSimulation/Icons/ConstantConverterName.mo b/BusinessSimulation/Icons/ConstantConverterName.mo new file mode 100644 index 0000000..bab0128 --- /dev/null +++ b/BusinessSimulation/Icons/ConstantConverterName.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class ConstantConverterName "Icon for converter elements" + annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -55}, textColor = {64, 64, 64}, extent = {{-150, -12}, {150, 12}}, textString = "%name", fontName = "Lato")})); +end ConstantConverterName; diff --git a/BusinessSimulation/Icons/ConstantsPackage/package.mo b/BusinessSimulation/Icons/ConstantsPackage/package.mo new file mode 100644 index 0000000..9ab233d --- /dev/null +++ b/BusinessSimulation/Icons/ConstantsPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package ConstantsPackage "Icon for a constants package" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {14.3, 18.868}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-80, -6.372}, {-80, -6.372}, {-76.12, -6.372}, {-76.12, -6.372}, {-60.75, 16.378}, {-9.64, 16.378}, {43.88, 16.378}, {43.88, 16.378}, {43.88, 32.798}, {43.88, 32.798}, {-11.12, 32.798}, {-66.12, 32.798}}, smooth = Smooth.Bezier), Polygon(visible = true, origin = {14.3, 18.868}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{16.84, 26.921}, {16.84, -51.493}, {33.13, -53.079}, {41.24, -38.779}, {41.24, -38.779}, {45.7, -38.779}, {45.7, -38.779}, {33.13, -75.549}, {6.87, -75.549}, {0, -43.079}, {5.157, 26.921}, {5.157, 26.921}, {16.84, 26.921}}, smooth = Smooth.Bezier), Polygon(visible = true, origin = {14.3, 18.868}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-38.493, 26.921}, {-44.229, -29.502}, {-70, -66.269}, {-52.476, -76.921}, {-33.577, -66.269}, {-28.493, 26.921}, {-28.493, 26.921}, {-38.493, 26.921}}, smooth = Smooth.Bezier)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ConstantsPackage; diff --git a/BusinessSimulation/Icons/Converter.mo b/BusinessSimulation/Icons/Converter.mo new file mode 100644 index 0000000..100ef67 --- /dev/null +++ b/BusinessSimulation/Icons/Converter.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial block Converter "Icon for converter elements" + extends ConverterName; + annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-60, -60}, {60, 60}})})); +end Converter; diff --git a/BusinessSimulation/Icons/ConverterName.mo b/BusinessSimulation/Icons/ConverterName.mo new file mode 100644 index 0000000..321ac25 --- /dev/null +++ b/BusinessSimulation/Icons/ConverterName.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class ConverterName "Icon for converter elements" + annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -95}, textColor = {64, 64, 64}, extent = {{-150, -12}, {150, 12}}, textString = "%name", fontName = "Lato")})); +end ConverterName; diff --git a/BusinessSimulation/Icons/Conveyor.mo b/BusinessSimulation/Icons/Conveyor.mo new file mode 100644 index 0000000..d956e3f --- /dev/null +++ b/BusinessSimulation/Icons/Conveyor.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Conveyor "Icon for conveyor stocks" + extends MaterialStock; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-50.416, -31.706}, points = {{0, 131.706}, {0, -68.294}}, color = {255, 0, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {49.584, -30.259}, points = {{0, 130.747}, {0, -69.741}}, color = {255, 0, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {0, 21.356}, points = {{0, 78.644}, {0, -78.644}}, color = {255, 0, 0}, thickness = 4, arrowSize = 1)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Conveyor; diff --git a/BusinessSimulation/Icons/DataBus.mo b/BusinessSimulation/Icons/DataBus.mo new file mode 100644 index 0000000..8d3521e --- /dev/null +++ b/BusinessSimulation/Icons/DataBus.mo @@ -0,0 +1,7 @@ +within BusinessSimulation.Icons; + +partial class DataBus "Icon for information input and output busses" + annotation(Icon(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {0, 0, 128}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, lineThickness = 3, points = {{-80, 50}, {80, 50}, {100, 30}, {80, -40}, {60, -50}, {-60, -50}, {-80, -40}, {-100, 30}}, smooth = Smooth.Bezier), Ellipse(visible = true, origin = {-50, 11.841}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Ellipse(visible = true, origin = {0, 11.571}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Ellipse(visible = true, origin = {48.125, 10}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Ellipse(visible = true, origin = {-22, -16.159}, lineColor = {76, 112, 136}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Ellipse(visible = true, origin = {28, -16.429}, lineColor = {76, 112, 136}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}})}), Diagram(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.2, grid = {5, 5}), graphics = {Text(visible = true, origin = {-0, 55}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold}), Polygon(visible = true, lineColor = {0, 0, 128}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, lineThickness = 3, points = {{-40, 25}, {40, 25}, {50, 15}, {40, -20}, {30, -25}, {-30, -25}, {-40, -20}, {-50, 15}}, smooth = Smooth.Bezier), Ellipse(visible = true, origin = {-25, 10}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}}), Ellipse(visible = true, origin = {0, 10}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}}), Ellipse(visible = true, origin = {25, 10}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}}), Ellipse(visible = true, origin = {-13.006, -10}, lineColor = {76, 112, 136}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}}), Ellipse(visible = true, origin = {12.531, -10}, lineColor = {76, 112, 136}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}})}), Documentation(info = " +This icon is designed for a signal bus connector. +")); +end DataBus; diff --git a/BusinessSimulation/Icons/DataInPort.mo b/BusinessSimulation/Icons/DataInPort.mo new file mode 100644 index 0000000..c8794fc --- /dev/null +++ b/BusinessSimulation/Icons/DataInPort.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class DataInPort "Icon for an expandable connector for information input" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}, {-100, 100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 170, 0}, fillColor = {255, 170, 0}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-100, 0}, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 50}, {100, 0}, {0, -50}, {0, 50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation); +end DataInPort; diff --git a/BusinessSimulation/Icons/DataOutPort.mo b/BusinessSimulation/Icons/DataOutPort.mo new file mode 100644 index 0000000..8af99c3 --- /dev/null +++ b/BusinessSimulation/Icons/DataOutPort.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class DataOutPort "Icon for an expandable connector for information output" + annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 170, 0}, fillColor = {255, 170, 0}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {100, 0}, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation); +end DataOutPort; diff --git a/BusinessSimulation/Icons/DelayN.mo b/BusinessSimulation/Icons/DelayN.mo new file mode 100644 index 0000000..42aef16 --- /dev/null +++ b/BusinessSimulation/Icons/DelayN.mo @@ -0,0 +1,7 @@ +within BusinessSimulation.Icons; + +partial class DelayN "Icon for DelayN" + extends MaterialStock; + extends Clockface; + annotation(__Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end DelayN; diff --git a/BusinessSimulation/Icons/DiscreteSmoothLabel.mo b/BusinessSimulation/Icons/DiscreteSmoothLabel.mo new file mode 100644 index 0000000..fc7d5e5 --- /dev/null +++ b/BusinessSimulation/Icons/DiscreteSmoothLabel.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class DiscreteSmoothLabel "Mark converters as discrete" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {53.863, 38}, textColor = {0, 0, 128}, extent = {{-16.137, -20}, {16.137, 20}}, textString = "···", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end DiscreteSmoothLabel; diff --git a/BusinessSimulation/Icons/DiscreteStockLabel.mo b/BusinessSimulation/Icons/DiscreteStockLabel.mo new file mode 100644 index 0000000..e1af492 --- /dev/null +++ b/BusinessSimulation/Icons/DiscreteStockLabel.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class DiscreteStockLabel "Mark stock element as discrete" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {73.863, 81}, textColor = {128, 0, 128}, extent = {{-16.137, -20}, {16.137, 20}}, textString = "···", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end DiscreteStockLabel; diff --git a/BusinessSimulation/Icons/Enumeration.mo b/BusinessSimulation/Icons/Enumeration.mo new file mode 100644 index 0000000..a4b3a23 --- /dev/null +++ b/BusinessSimulation/Icons/Enumeration.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class Enumeration "Icon for type enumeration" + annotation(Icon(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-100, -100}, {100, 100}}), Text(visible = true, textColor = {76, 112, 136}, extent = {{-90, -50}, {90, 50}}, textString = "1..n", fontName = "Lato", textStyle = {TextStyle.Bold})})); +end Enumeration; diff --git a/BusinessSimulation/Icons/Example.mo b/BusinessSimulation/Icons/Example.mo new file mode 100644 index 0000000..793eaf9 --- /dev/null +++ b/BusinessSimulation/Icons/Example.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial model Example "Icon for an example" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-100, -100}, {100, 100}}), Polygon(visible = true, lineColor = {76, 112, 136}, fillColor = {76, 112, 136}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-36, 60}, {64, 0}, {-36, -60}, {-36, 60}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Example; diff --git a/BusinessSimulation/Icons/ExamplesPackage/package.mo b/BusinessSimulation/Icons/ExamplesPackage/package.mo new file mode 100644 index 0000000..3f6ae36 --- /dev/null +++ b/BusinessSimulation/Icons/ExamplesPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package ExamplesPackage "Icon for packages containing examples" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {8, 14}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-58, 46}, {42, -14}, {-58, -74}, {-58, 46}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ExamplesPackage; diff --git a/BusinessSimulation/Icons/ExpandableFlowPort.mo b/BusinessSimulation/Icons/ExpandableFlowPort.mo new file mode 100644 index 0000000..5bfb918 --- /dev/null +++ b/BusinessSimulation/Icons/ExpandableFlowPort.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class ExpandableFlowPort "Icon for expandable flow ports" + annotation(Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {-5, 5}, lineColor = {128, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-55, -55}, {55, 55}}), Text(visible = true, origin = {0, 90}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation, Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-100, -100}, {100, 100}}), Rectangle(visible = true, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-80, -80}, {80, 80}}), Ellipse(visible = true, lineColor = {255, 170, 0}, fillColor = {255, 170, 0}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})})); +end ExpandableFlowPort; diff --git a/BusinessSimulation/Icons/ExpandableStockPort.mo b/BusinessSimulation/Icons/ExpandableStockPort.mo new file mode 100644 index 0000000..65a442b --- /dev/null +++ b/BusinessSimulation/Icons/ExpandableStockPort.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class ExpandableStockPort "Icon for expandable stock ports" + annotation(Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {-5, 5}, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-55, -55}, {55, 55}}), Text(visible = true, origin = {-0, 90}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation, Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {128, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-100, -100}, {100, 100}}), Rectangle(visible = true, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-80, -80}, {80, 80}}), Ellipse(visible = true, lineColor = {255, 170, 0}, fillColor = {255, 170, 0}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})})); +end ExpandableStockPort; diff --git a/BusinessSimulation/Icons/FlowIndicators.mo b/BusinessSimulation/Icons/FlowIndicators.mo new file mode 100644 index 0000000..8a6c333 --- /dev/null +++ b/BusinessSimulation/Icons/FlowIndicators.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class FlowIndicators "Arrows indicating flow" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-80.87, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {-70.87, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {70.439, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {80.439, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end FlowIndicators; diff --git a/BusinessSimulation/Icons/Function.mo b/BusinessSimulation/Icons/Function.mo new file mode 100644 index 0000000..30be781 --- /dev/null +++ b/BusinessSimulation/Icons/Function.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial function Function "Icon for functions" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-87.608, -87.608}, {87.608, 87.608}}), Text(visible = true, origin = {-10, 0}, textColor = {0, 0, 128}, extent = {{-90, -90}, {90, 90}}, textString = "f", textStyle = {TextStyle.Italic}), Text(visible = true, origin = {0, 112}, textColor = {64, 64, 64}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato ")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Function; diff --git a/BusinessSimulation/Icons/FunctionLetter.mo b/BusinessSimulation/Icons/FunctionLetter.mo new file mode 100644 index 0000000..83b617f --- /dev/null +++ b/BusinessSimulation/Icons/FunctionLetter.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class FunctionLetter "FunctionLetter typically added for general function converters" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {-2.676, 5.698}, textColor = {0, 0, 128}, extent = {{-40.145, -40.145}, {40.145, 40.145}}, textString = "f", fontName = "Lato", textStyle = {TextStyle.Italic})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end FunctionLetter; diff --git a/BusinessSimulation/Icons/FunctionsPackage/package.mo b/BusinessSimulation/Icons/FunctionsPackage/package.mo new file mode 100644 index 0000000..da847ab --- /dev/null +++ b/BusinessSimulation/Icons/FunctionsPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package FunctionsPackage "Functions package icon" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {15.113, -2.4}, textColor = {255, 255, 255}, extent = {{-40.266, -40.266}, {40.266, 40.266}}, textString = "(•)", fontName = "Lato"), Text(visible = true, origin = {-55, 5}, textColor = {255, 255, 255}, extent = {{-75, -75}, {75, 75}}, textString = "f", textStyle = {TextStyle.Italic})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end FunctionsPackage; diff --git a/BusinessSimulation/Icons/IconsPackage/package.mo b/BusinessSimulation/Icons/IconsPackage/package.mo new file mode 100644 index 0000000..8ebaa18 --- /dev/null +++ b/BusinessSimulation/Icons/IconsPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package IconsPackage "Icon for an icons package" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-8.167, -17}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-15.833, 20}, {-15.833, 30}, {14.167, 40}, {24.167, 20}, {4.167, -30}, {14.167, -30}, {24.167, -30}, {24.167, -40}, {-5.833, -50}, {-15.833, -30}, {4.167, 20}, {-5.833, 20}}, smooth = Smooth.Bezier), Ellipse(visible = true, origin = {-0.5, 56.5}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, extent = {{-12.5, -12.5}, {12.5, 12.5}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end IconsPackage; diff --git a/BusinessSimulation/Icons/Info.mo b/BusinessSimulation/Icons/Info.mo new file mode 100644 index 0000000..cdebd93 --- /dev/null +++ b/BusinessSimulation/Icons/Info.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class Info "Icon for information pages (UsersGuide)" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {255, 170, 0}, fillColor = {255, 170, 0}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-95, -95}, {95, 95}}), Polygon(visible = true, origin = {-4.167, -15}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-15.833, 20}, {-15.833, 30}, {14.167, 40}, {24.167, 20}, {4.167, -30}, {14.167, -30}, {24.167, -30}, {24.167, -40}, {-5.833, -50}, {-15.833, -30}, {4.167, 20}, {-5.833, 20}}, smooth = Smooth.Bezier), Ellipse(visible = true, origin = {7.5, 56.5}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, extent = {{-12.5, -12.5}, {12.5, 12.5}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Info; diff --git a/BusinessSimulation/Icons/InformationProcessing.mo b/BusinessSimulation/Icons/InformationProcessing.mo new file mode 100644 index 0000000..f766e60 --- /dev/null +++ b/BusinessSimulation/Icons/InformationProcessing.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial block InformationProcessing "Icon for information processing molecules" + extends ComponentName; + annotation(__Wolfram(itemFlippingEnabled = true), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-90, -90}, {90, 90}}), Rectangle(visible = true, origin = {0, 52.225}, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, lineThickness = 1, extent = {{-15.899, -19.317}, {15.899, 19.317}}, radius = 10), Text(visible = true, origin = {0.5, 52.448}, textColor = {0, 0, 128}, extent = {{-15.5, -20}, {15.5, 20}}, textString = "i", fontName = "Consolas")})); +end InformationProcessing; diff --git a/BusinessSimulation/Icons/InformationSourceIndicator.mo b/BusinessSimulation/Icons/InformationSourceIndicator.mo new file mode 100644 index 0000000..8ac858f --- /dev/null +++ b/BusinessSimulation/Icons/InformationSourceIndicator.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial block InformationSourceIndicator "Icon used to indicate external information" + annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {76, 112, 136}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-60, -60}, {60, 60}})})); +end InformationSourceIndicator; diff --git a/BusinessSimulation/Icons/InformationSources/package.mo b/BusinessSimulation/Icons/InformationSources/package.mo new file mode 100644 index 0000000..6712b44 --- /dev/null +++ b/BusinessSimulation/Icons/InformationSources/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package InformationSources "Package Icon for Information Sources" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {128, 128, 128}, extent = {{-100, -100}, {100, 100}}, radius = 25), Polygon(visible = true, origin = {23.333, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-23.333, 30}, {46.667, 0}, {-23.333, -30}}), Rectangle(visible = true, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, extent = {{-70, -4.5}, {0, 4.5}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end InformationSources; diff --git a/BusinessSimulation/Icons/Interaction.mo b/BusinessSimulation/Icons/Interaction.mo new file mode 100644 index 0000000..6e85fc9 --- /dev/null +++ b/BusinessSimulation/Icons/Interaction.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Interaction "Icon for interactional flow classes" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-100, -100}, {100, 100}}), Polygon(visible = true, origin = {72.114, -0.25}, rotation = -450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Text(visible = true, origin = {-73.452, 37.479}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "A"), Text(visible = true, origin = {73.452, -43.134}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "B"), Polygon(visible = true, origin = {-72.424, 0}, rotation = 450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{22.295, -7.943}, {-22.191, -7.943}, {-0.104, 15.886}}), Rectangle(visible = true, origin = {40.723, -0.123}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, extent = {{-26.573, -11.955}, {26.573, 11.955}}), Line(visible = true, origin = {-0, -11.973}, points = {{-66.898, 0}, {66.898, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {-0, 11.777}, points = {{-66.291, 0}, {66.291, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1), Ellipse(visible = true, origin = {1.899, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-17, -17}, {17, 17}}), Ellipse(visible = true, origin = {1.899, 0}, lineColor = {255, 255, 255}, fillColor = {0, 128, 0}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-14, -14}, {14, 14}}), Text(visible = true, origin = {-74, 1}, textColor = {255, 255, 255}, extent = {{-13.452, -12}, {13.452, 12}}, textString = "+", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {74, 1}, textColor = {255, 255, 255}, extent = {{-13.452, -12}, {13.452, 12}}, textString = "+", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {2, 0}, textColor = {255, 255, 255}, extent = {{-16.513, -12}, {16.513, 12}}, textString = "X", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}))); +end Interaction; diff --git a/BusinessSimulation/Icons/InterfacesPackage/package.mo b/BusinessSimulation/Icons/InterfacesPackage/package.mo new file mode 100644 index 0000000..aefe15c --- /dev/null +++ b/BusinessSimulation/Icons/InterfacesPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package InterfacesPackage "Icon for an interfaces package" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {20, 0}, lineColor = {64, 64, 64}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-10, 70}, {10, 70}, {40, 20}, {80, 20}, {80, -20}, {40, -20}, {10, -70}, {-10, -70}}), Polygon(visible = true, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{-100, 20}, {-60, 20}, {-30, 70}, {-10, 70}, {-10, -70}, {-30, -70}, {-60, -20}, {-100, -20}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end InterfacesPackage; diff --git a/BusinessSimulation/Icons/InterpolationTable.mo b/BusinessSimulation/Icons/InterpolationTable.mo new file mode 100644 index 0000000..0a4628b --- /dev/null +++ b/BusinessSimulation/Icons/InterpolationTable.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class InterpolationTable "Icon for table functions" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {17.96, 28.906}, lineColor = {255, 255, 255}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Rectangle(visible = true, origin = {-17.96, 28.906}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Rectangle(visible = true, origin = {-17.96, 9.906}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Rectangle(visible = true, origin = {17.96, 9.906}, lineColor = {255, 255, 255}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Rectangle(visible = true, origin = {-17.96, -9.094}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Rectangle(visible = true, origin = {17.96, -9.094}, lineColor = {255, 255, 255}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Rectangle(visible = true, origin = {-17.96, -28.297}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Rectangle(visible = true, origin = {17.96, -28.297}, lineColor = {255, 255, 255}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, extent = {{-17.96, -8.906}, {17.96, 8.906}}), Ellipse(visible = true, origin = {16.097, 0}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Ellipse(visible = true, origin = {-18.903, 10}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Ellipse(visible = true, origin = {-18.903, -10}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Ellipse(visible = true, origin = {16.097, -11}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Ellipse(visible = true, origin = {16.097, 10}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Ellipse(visible = true, origin = {-18.903, 0}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end InterpolationTable; diff --git a/BusinessSimulation/Icons/MaterialStock.mo b/BusinessSimulation/Icons/MaterialStock.mo new file mode 100644 index 0000000..1b3d0f5 --- /dev/null +++ b/BusinessSimulation/Icons/MaterialStock.mo @@ -0,0 +1,7 @@ +within BusinessSimulation.Icons; + +partial class MaterialStock "General Icon for material stocks" + extends Stock; + extends MaterialStockIndicator; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end MaterialStock; diff --git a/BusinessSimulation/Icons/MaterialStockIndicator.mo b/BusinessSimulation/Icons/MaterialStockIndicator.mo new file mode 100644 index 0000000..5e978c0 --- /dev/null +++ b/BusinessSimulation/Icons/MaterialStockIndicator.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class MaterialStockIndicator "General Icon for stocks" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {-81.678, 80}, textColor = {128, 0, 128}, extent = {{-16.137, -20}, {16.137, 20}}, textString = "+", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end MaterialStockIndicator; diff --git a/BusinessSimulation/Icons/MultiInput.mo b/BusinessSimulation/Icons/MultiInput.mo new file mode 100644 index 0000000..d653695 --- /dev/null +++ b/BusinessSimulation/Icons/MultiInput.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class MultiInput "Icon for multiple inputs" + annotation(defaultComponentName = "u", Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {5, 5, 125}, fillColor = {5, 5, 125}, fillPattern = FillPattern.Solid, points = {{0, 50}, {100, 0}, {0, -50}, {0, 50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}, {-100, 100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Documentation(info = "")); +end MultiInput; diff --git a/BusinessSimulation/Icons/MultiOutput.mo b/BusinessSimulation/Icons/MultiOutput.mo new file mode 100644 index 0000000..50ab819 --- /dev/null +++ b/BusinessSimulation/Icons/MultiOutput.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial class MultiOutput "Icon for multiple outputs" + annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation); +end MultiOutput; diff --git a/BusinessSimulation/Icons/MultiPort.mo b/BusinessSimulation/Icons/MultiPort.mo new file mode 100644 index 0000000..a776708 --- /dev/null +++ b/BusinessSimulation/Icons/MultiPort.mo @@ -0,0 +1,7 @@ +within BusinessSimulation.Icons; + +partial class MultiPort "Icon for mass transport pipelines" + annotation(Icon(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.2, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {128, 0, 128}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, lineThickness = 3, points = {{-80, 50}, {80, 50}, {100, 30}, {80, -40}, {60, -50}, {-60, -50}, {-80, -40}, {-100, 30}}, smooth = Smooth.Bezier), Rectangle(visible = true, origin = {-40, 0}, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-30, -30}, {30, 30}}), Rectangle(visible = true, origin = {-40, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-25, -25}, {25, 25}}), Ellipse(visible = true, origin = {-40, 0}, lineColor = {255, 255, 255}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Rectangle(visible = true, origin = {40, 0}, lineColor = {128, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-30, -30}, {30, 30}}), Rectangle(visible = true, origin = {40, 0}, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-25, -25}, {25, 25}}), Ellipse(visible = true, origin = {40, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}})}), Diagram(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {5, 5}), graphics = {Polygon(visible = true, lineColor = {128, 0, 128}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, lineThickness = 3, points = {{-40, 25}, {40, 25}, {50, 15}, {40, -20}, {30, -25}, {-30, -25}, {-40, -20}, {-50, 15}}, smooth = Smooth.Bezier), Text(visible = true, origin = {-0, 55}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This icon is designed for a signal bus connector. +")); +end MultiPort; diff --git a/BusinessSimulation/Icons/OmniBus.mo b/BusinessSimulation/Icons/OmniBus.mo new file mode 100644 index 0000000..18d1488 --- /dev/null +++ b/BusinessSimulation/Icons/OmniBus.mo @@ -0,0 +1,7 @@ +within BusinessSimulation.Icons; + +partial class OmniBus "Icon for combined mass and information transport pipelines" + annotation(Icon(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.2, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {76, 112, 136}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, lineThickness = 3, points = {{-80, 50}, {80, 50}, {100, 30}, {80, -40}, {60, -50}, {-60, -50}, {-80, -40}, {-100, 30}}, smooth = Smooth.Bezier), Rectangle(visible = true, origin = {-33.091, -6.909}, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-23.091, -23.091}, {23.091, 23.091}}), Rectangle(visible = true, origin = {-32.5, -7.5}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-17.5, -17.5}, {17.5, 17.5}}), Ellipse(visible = true, origin = {-32.394, -7.606}, lineColor = {255, 255, 255}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-7.606, -7.606}, {7.606, 7.606}}), Rectangle(visible = true, origin = {33.223, -6.777}, lineColor = {128, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-23.223, -23.223}, {23.223, 23.223}}), Rectangle(visible = true, origin = {33.644, -6.614}, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-17.356, -17.356}, {17.356, 17.356}}), Ellipse(visible = true, origin = {34.394, -6.606}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-7.606, -7.606}, {7.606, 7.606}}), Ellipse(visible = true, origin = {-40, 33.069}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}}), Ellipse(visible = true, origin = {-22.337, 32.861}, lineColor = {76, 112, 136}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}}), Ellipse(visible = true, origin = {25, 32.213}, lineColor = {76, 112, 136}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}}), Ellipse(visible = true, origin = {42.663, 32.005}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-5, -5}, {5, 5}})}), Diagram(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.2, grid = {5, 5}), graphics = {Polygon(visible = true, lineColor = {76, 112, 136}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, lineThickness = 3, points = {{-40, 25}, {40, 25}, {50, 15}, {40, -20}, {30, -25}, {-30, -25}, {-40, -20}, {-50, 15}}, smooth = Smooth.Bezier), Text(visible = true, origin = {-0, 55}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This icon is designed for a signal bus connector. +")); +end OmniBus; diff --git a/BusinessSimulation/Icons/Outflow.mo b/BusinessSimulation/Icons/Outflow.mo new file mode 100644 index 0000000..bd12046 --- /dev/null +++ b/BusinessSimulation/Icons/Outflow.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial model Outflow "Icon for outflow classes" + extends ComponentName; + annotation(__Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{100, 100}, {-100, -100}}), Polygon(visible = true, origin = {72.114, -0.25}, rotation = -450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Text(visible = true, origin = {-73.452, 37.479}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "A"), Text(visible = true, origin = {73.452, -43.134}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "B"), Line(visible = true, origin = {-3.902, 11.777}, points = {{-70.951, 0}, {70.951, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {-4.227, -11.973}, points = {{-70.669, 0}, {70.669, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Outflow; diff --git a/BusinessSimulation/Icons/Oven.mo b/BusinessSimulation/Icons/Oven.mo new file mode 100644 index 0000000..95ea40b --- /dev/null +++ b/BusinessSimulation/Icons/Oven.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Oven "Icon for ovens" + extends DelayN; + annotation(__Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {255, 0, 0}, fillColor = {255, 255, 255}, lineThickness = 4, extent = {{-60, -60}, {60, 60}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Oven; diff --git a/BusinessSimulation/Icons/Package/package.mo b/BusinessSimulation/Icons/Package/package.mo new file mode 100644 index 0000000..ef5ba29 --- /dev/null +++ b/BusinessSimulation/Icons/Package/package.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Icons; + +partial package Package "Basic package icon" + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {76, 112, 136}, fillColor = {113, 166, 201}, pattern = LinePattern.None, fillPattern = FillPattern.HorizontalCylinder, lineThickness = 4, extent = {{-100, -100}, {100, 100}}, radius = 25)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Package; diff --git a/BusinessSimulation/Icons/Policy.mo b/BusinessSimulation/Icons/Policy.mo new file mode 100644 index 0000000..b9f829d --- /dev/null +++ b/BusinessSimulation/Icons/Policy.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial block Policy "Policy Block (Controller)" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-90, -90}, {90, 90}}), Line(visible = true, origin = {0.067, 70}, rotation = -90, points = {{0, 55.552}, {0, -55.552}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0), Line(visible = true, origin = {0.335, -70}, rotation = -90, points = {{0, 55.955}, {0, -55.955}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Policy; diff --git a/BusinessSimulation/Icons/Queue.mo b/BusinessSimulation/Icons/Queue.mo new file mode 100644 index 0000000..e40a0d5 --- /dev/null +++ b/BusinessSimulation/Icons/Queue.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Queue "Icon for queues" + extends MaterialStock; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {0, 21.356}, points = {{0, 78.644}, {0, -78.644}}, color = {255, 0, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {-50, -22.696}, points = {{0, 77.304}, {0, -77.304}}, color = {255, 0, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {50, -22.696}, points = {{0, 77.304}, {0, -77.304}}, color = {255, 0, 0}, thickness = 4, arrowSize = 1)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Queue; diff --git a/BusinessSimulation/Icons/Record.mo b/BusinessSimulation/Icons/Record.mo new file mode 100644 index 0000000..1faa62e --- /dev/null +++ b/BusinessSimulation/Icons/Record.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Record "Icon for records" + extends Icons.ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {0, -25}, lineColor = {64, 64, 64}, fillColor = {255, 215, 136}, fillPattern = FillPattern.Solid, extent = {{-100, -75}, {100, 75}}, radius = 25), Rectangle(visible = true, origin = {0, -25}, lineColor = {255, 255, 255}, fillColor = {76, 112, 136}, fillPattern = FillPattern.Solid, extent = {{-100, -75}, {100, 75}}, radius = 25), Line(visible = true, points = {{-100, 0}, {100, 0}}, color = {255, 255, 255}), Line(visible = true, origin = {0, -50}, points = {{-100, 0}, {100, 0}}, color = {255, 255, 255}), Line(visible = true, origin = {0, -25}, points = {{0, 75}, {0, -75}}, color = {255, 255, 255})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Record; diff --git a/BusinessSimulation/Icons/SimulationModel.mo b/BusinessSimulation/Icons/SimulationModel.mo new file mode 100644 index 0000000..9eb2cf0 --- /dev/null +++ b/BusinessSimulation/Icons/SimulationModel.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial model SimulationModel "Icon for Base Model" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {-51.766, 60}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Rectangle(visible = true, origin = {0, 25.188}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Rectangle(visible = true, origin = {41.891, 60}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Rectangle(visible = true, origin = {40, -17.73}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Rectangle(visible = true, origin = {-51.947, 1.702}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Line(visible = true, origin = {-3.23, 60}, points = {{-41.28, 0}, {41.28, 0}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-52.032, 30.442}, points = {{0, 27.078}, {0, -27.078}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {40, 21.017}, points = {{0, 31.017}, {0, -31.017}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-32.173, 14.201}, points = {{24.74, 10.755}, {5.98, 10.755}, {5.98, -12.961}, {-12.072, -12.961}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-24.173, 6.201}, points = {{55.852, -24.074}, {24.173, -24.074}, {24.173, 10.789}}, color = {255, 255, 255}, thickness = 1), Rectangle(visible = true, origin = {0, -62.812}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-10, -10}, {10, 10}}), Line(visible = true, origin = {-6.173, -0.119}, points = {{6.173, -55.896}, {6.173, 16.134}}, color = {255, 255, 255}, thickness = 1)}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SimulationModel; diff --git a/BusinessSimulation/Icons/Sink.mo b/BusinessSimulation/Icons/Sink.mo new file mode 100644 index 0000000..4b29a77 --- /dev/null +++ b/BusinessSimulation/Icons/Sink.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Sink "General icon for sinks" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-100, -100}, {100, 100}}), Rectangle(visible = true, origin = {-59.838, 0}, lineColor = {255, 0, 0}, fillColor = {255, 255, 255}, lineThickness = 2.5, extent = {{-32.838, -32.117}, {32.838, 32.117}}), Polygon(visible = true, origin = {-9.461, 0.052}, rotation = -990, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Line(visible = true, origin = {40.959, 10}, points = {{45.054, 0}, {-45.054, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 0), Line(visible = true, origin = {41.034, -10}, points = {{44.979, 0}, {-44.979, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 0), Ellipse(visible = true, origin = {41.899, 0}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-17, -17}, {17, 17}}), Line(visible = true, origin = {-59.639, -1.461}, points = {{-19.013, -1.251}, {-19.013, 5.61}, {-13.146, 10.097}, {-4.518, 6.3}, {3.107, -1.637}, {9.976, -6.855}, {16.533, -6.855}, {19.639, -3.018}, {19.639, 4.92}, {13.107, 11.132}, {6.525, 8.716}, {3.107, 3.145}, {-4.173, -6.855}, {-14.872, -8.539}, {-19.013, -1.251}, {-19.013, -1.251}}, color = {255, 0, 0}, thickness = 2.5, smooth = Smooth.Bezier), Text(visible = true, origin = {42, 0}, textColor = {255, 255, 255}, extent = {{-16.513, -12}, {16.513, 12}}, textString = "X", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Sink; diff --git a/BusinessSimulation/Icons/Smooth.mo b/BusinessSimulation/Icons/Smooth.mo new file mode 100644 index 0000000..3a01538 --- /dev/null +++ b/BusinessSimulation/Icons/Smooth.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial block Smooth "Icon to be used for converters that contain stocks" + extends ConverterName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-80, -50}, {80, 50}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Smooth; diff --git a/BusinessSimulation/Icons/Source.mo b/BusinessSimulation/Icons/Source.mo new file mode 100644 index 0000000..351a4ca --- /dev/null +++ b/BusinessSimulation/Icons/Source.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Source "General icon for sources" + extends ComponentName; + annotation(__Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-100, -100}, {100, 100}}), Line(visible = true, origin = {19.916, -10}, points = {{-46.748, 0}, {46.748, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 0), Line(visible = true, origin = {19.213, 8.274}, points = {{-46.013, 0}, {46.013, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 0), Rectangle(visible = true, origin = {-59.838, 0}, lineColor = {255, 0, 0}, fillColor = {255, 255, 255}, lineThickness = 2.5, extent = {{-32.838, -32.117}, {32.838, 32.117}}), Polygon(visible = true, origin = {72.114, -0.25}, rotation = -450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Ellipse(visible = true, origin = {21.899, 0}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-15.107, -15.107}, {15.107, 15.107}}), Line(visible = true, origin = {-59.639, -1.461}, points = {{-19.013, -1.251}, {-19.013, 5.61}, {-13.146, 10.097}, {-4.518, 6.3}, {3.107, -1.637}, {9.976, -6.855}, {16.533, -6.855}, {19.639, -3.018}, {19.639, 4.92}, {13.107, 11.132}, {6.525, 8.716}, {3.107, 3.145}, {-4.173, -6.855}, {-14.872, -8.539}, {-19.013, -1.251}, {-19.013, -1.251}}, color = {255, 0, 0}, thickness = 2.5, smooth = Smooth.Bezier), Text(visible = true, origin = {22, 0}, textColor = {255, 255, 255}, extent = {{-16.513, -12}, {16.513, 12}}, textString = "X", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Source; diff --git a/BusinessSimulation/Icons/SourceOrSink.mo b/BusinessSimulation/Icons/SourceOrSink.mo new file mode 100644 index 0000000..cf3ad34 --- /dev/null +++ b/BusinessSimulation/Icons/SourceOrSink.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class SourceOrSink "General icon for sources or sinks" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-100, -100}, {100, 100}}), Polygon(visible = true, origin = {72.114, -0.25}, rotation = -450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Rectangle(visible = true, origin = {-59.838, 0}, lineColor = {255, 0, 0}, fillColor = {255, 255, 255}, lineThickness = 2.5, extent = {{-32.838, -32.117}, {32.838, 32.117}}), Polygon(visible = true, origin = {-9.461, 0.052}, rotation = -990, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Line(visible = true, origin = {-59.639, -1.461}, points = {{-19.013, -1.251}, {-19.013, 5.61}, {-13.146, 10.097}, {-4.518, 6.3}, {3.107, -1.637}, {9.976, -6.855}, {16.533, -6.855}, {19.639, -3.018}, {19.639, 4.92}, {13.107, 11.132}, {6.525, 8.716}, {3.107, 3.145}, {-4.173, -6.855}, {-14.872, -8.539}, {-19.013, -1.251}, {-19.013, -1.251}}, color = {255, 0, 0}, thickness = 2.5, smooth = Smooth.Bezier), Line(visible = true, origin = {31.043, -10}, points = {{-34.814, 0}, {34.814, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 0), Line(visible = true, origin = {31.312, 10}, points = {{-35.083, 0}, {35.083, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 0), Text(visible = true, origin = {74, 1}, textColor = {255, 255, 255}, extent = {{-13.452, -12}, {13.452, 12}}, textString = "+", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-12, 2}, textColor = {255, 255, 255}, extent = {{-13.452, -12}, {13.452, 12}}, textString = "–", fontName = "Lato", textStyle = {TextStyle.Bold}), Ellipse(visible = true, origin = {31.899, 0}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-17, -17}, {17, 17}}), Text(visible = true, origin = {32, 0}, textColor = {255, 255, 255}, extent = {{-16.513, -12}, {16.513, 12}}, textString = "X", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SourceOrSink; diff --git a/BusinessSimulation/Icons/Stock.mo b/BusinessSimulation/Icons/Stock.mo new file mode 100644 index 0000000..cfc165d --- /dev/null +++ b/BusinessSimulation/Icons/Stock.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Stock "General Icon for stocks" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {255, 0, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-100, -100}, {100, 100}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Stock; diff --git a/BusinessSimulation/Icons/SubsystemActuator.mo b/BusinessSimulation/Icons/SubsystemActuator.mo new file mode 100644 index 0000000..14315b9 --- /dev/null +++ b/BusinessSimulation/Icons/SubsystemActuator.mo @@ -0,0 +1,7 @@ +within BusinessSimulation.Icons; + +partial class SubsystemActuator "Icon for subsystems with flow ports" + // extends ComponentName; + extends Icons.SubsystemTransceiver; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SubsystemActuator; diff --git a/BusinessSimulation/Icons/SubsystemBlock.mo b/BusinessSimulation/Icons/SubsystemBlock.mo new file mode 100644 index 0000000..f1af324 --- /dev/null +++ b/BusinessSimulation/Icons/SubsystemBlock.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class SubsystemBlock "Icon for subsystems with flow ports" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-100, -100}, {100, 100}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SubsystemBlock; diff --git a/BusinessSimulation/Icons/SubsystemIncubator.mo b/BusinessSimulation/Icons/SubsystemIncubator.mo new file mode 100644 index 0000000..c554760 --- /dev/null +++ b/BusinessSimulation/Icons/SubsystemIncubator.mo @@ -0,0 +1,7 @@ +within BusinessSimulation.Icons; + +partial class SubsystemIncubator "General Icon for stocks" + // extends Icons.Stock; + extends Icons.SubsystemTransceiver; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SubsystemIncubator; diff --git a/BusinessSimulation/Icons/SubsystemTransceiver.mo b/BusinessSimulation/Icons/SubsystemTransceiver.mo new file mode 100644 index 0000000..76cc667 --- /dev/null +++ b/BusinessSimulation/Icons/SubsystemTransceiver.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class SubsystemTransceiver "Icon for subsystems with mixed ports" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 4, extent = {{-100, -100}, {100, 100}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SubsystemTransceiver; diff --git a/BusinessSimulation/Icons/Theta.mo b/BusinessSimulation/Icons/Theta.mo new file mode 100644 index 0000000..655c16e --- /dev/null +++ b/BusinessSimulation/Icons/Theta.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class Theta "Icon for a class providing global parameters" + extends ConverterName; + annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {192, 192, 192}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-50, -50}, {50, 50}}), Text(visible = true, textColor = {0, 0, 128}, extent = {{-100, -24}, {100, 24}}, textString = "θ", fontName = "Lato", textStyle = {TextStyle.Bold, TextStyle.Italic})})); +end Theta; diff --git a/BusinessSimulation/Icons/TypesPackage/package.mo b/BusinessSimulation/Icons/TypesPackage/package.mo new file mode 100644 index 0000000..100fe62 --- /dev/null +++ b/BusinessSimulation/Icons/TypesPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package TypesPackage "Icon for a types package" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-12.167, -23}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{12.167, 65}, {14.167, 93}, {36.167, 89}, {24.167, 20}, {4.167, -30}, {14.167, -30}, {24.167, -30}, {24.167, -40}, {-5.833, -50}, {-15.833, -30}, {4.167, 20}, {12.167, 65}}, smooth = Smooth.Bezier), Polygon(visible = true, origin = {2.74, 1.667}, fillColor = {255, 255, 255}, pattern = LinePattern.None, fillPattern = FillPattern.Solid, points = {{49.26, 22.333}, {31.26, 24.333}, {7.26, 18.333}, {-26.74, 10.333}, {-46.74, 14.333}, {-48.74, 6.333}, {-32.74, 0.333}, {-6.74, 4.333}, {33.26, 14.333}, {49.26, 14.333}, {49.26, 22.333}}, smooth = Smooth.Bezier)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end TypesPackage; diff --git a/BusinessSimulation/Icons/UnidirectionalFlow.mo b/BusinessSimulation/Icons/UnidirectionalFlow.mo new file mode 100644 index 0000000..7ab89fd --- /dev/null +++ b/BusinessSimulation/Icons/UnidirectionalFlow.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class UnidirectionalFlow "Icon for unidirectional flow classes" + extends ComponentName; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-100, -100}, {100, 100}}), Rectangle(visible = true, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-100, -100}, {100, 100}}), Line(visible = true, origin = {-4.075, -11.973}, points = {{-70.821, 0}, {70.821, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1), Line(visible = true, origin = {-4.357, 11.777}, points = {{-70.496, 0}, {70.496, 0}}, color = {0, 128, 0}, thickness = 4, arrowSize = 1), Polygon(visible = true, origin = {72.114, -0.25}, rotation = -450, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Text(visible = true, origin = {-73.452, 37.479}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "A"), Text(visible = true, origin = {73.452, -43.134}, textColor = {0, 128, 0}, extent = {{-13.452, -20}, {13.452, 20}}, textString = "B"), Ellipse(visible = true, origin = {1.899, 0}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, lineThickness = 1, extent = {{-17, -17}, {17, 17}}), Text(visible = true, origin = {2, 0}, textColor = {255, 255, 255}, extent = {{-16.513, -12}, {16.513, 12}}, textString = "X", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end UnidirectionalFlow; diff --git a/BusinessSimulation/Icons/UnitsPackage/package.mo b/BusinessSimulation/Icons/UnitsPackage/package.mo new file mode 100644 index 0000000..ccf44c5 --- /dev/null +++ b/BusinessSimulation/Icons/UnitsPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package UnitsPackage "Units package icon" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {255, 255, 255}, extent = {{-53.838, -67.501}, {53.838, 67.501}}, textString = "kg", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end UnitsPackage; diff --git a/BusinessSimulation/Icons/UtilitiesPackage/package.mo b/BusinessSimulation/Icons/UtilitiesPackage/package.mo new file mode 100644 index 0000000..c07e0f5 --- /dev/null +++ b/BusinessSimulation/Icons/UtilitiesPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package UtilitiesPackage "Package icon for utilities" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {1.383, -4.142}, rotation = 45, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-15, 93.333}, {-15, 68.333}, {0, 58.333}, {15, 68.333}, {15, 93.333}, {20, 93.333}, {25, 83.333}, {25, 58.333}, {10, 43.333}, {10, -41.667}, {25, -56.667}, {25, -76.667}, {10, -91.667}, {0, -91.667}, {0, -81.667}, {5, -81.667}, {15, -71.667}, {15, -61.667}, {5, -51.667}, {-5, -51.667}, {-15, -61.667}, {-15, -71.667}, {-5, -81.667}, {0, -81.667}, {0, -91.667}, {-10, -91.667}, {-25, -76.667}, {-25, -56.667}, {-10, -41.667}, {-10, 43.333}, {-25, 58.333}, {-25, 83.333}, {-20, 93.333}}), Polygon(visible = true, origin = {10.102, 5.218}, rotation = -45, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-15, 87.273}, {15, 87.273}, {20, 82.273}, {20, 27.273}, {10, 17.273}, {10, 7.273}, {20, 2.273}, {20, -2.727}, {5, -2.727}, {5, -77.727}, {10, -87.727}, {5, -112.727}, {-5, -112.727}, {-10, -87.727}, {-5, -77.727}, {-5, -2.727}, {-20, -2.727}, {-20, 2.273}, {-10, 7.273}, {-10, 17.273}, {-20, 27.273}, {-20, 82.273}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end UtilitiesPackage; diff --git a/BusinessSimulation/Icons/VariantsPackage/package.mo b/BusinessSimulation/Icons/VariantsPackage/package.mo new file mode 100644 index 0000000..7687e77 --- /dev/null +++ b/BusinessSimulation/Icons/VariantsPackage/package.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial package VariantsPackage "Variants class package icon" + extends Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Ellipse(visible = true, origin = {-40, 40}, lineColor = {128, 128, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-30, -30}, {30, 30}}), Ellipse(visible = true, origin = {40, 40}, lineColor = {128, 128, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-30, -30}, {30, 30}}), Ellipse(visible = true, origin = {-40, -40}, lineColor = {128, 128, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-30, -30}, {30, 30}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end VariantsPackage; diff --git a/BusinessSimulation/Icons/World.mo b/BusinessSimulation/Icons/World.mo new file mode 100644 index 0000000..75c20d2 --- /dev/null +++ b/BusinessSimulation/Icons/World.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Icons; + +partial class World "Icon to represent the world or the environment" + extends ComponentName; + annotation(Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Bitmap(visible = true, origin = {0, -5.282}, fileName = "modelica://BusinessSimulation/Resources/Images/Icons/World/World.png", imageSource = "", extent = {{-97.75, -57.683}, {97.75, 57.683}})})); +end World; diff --git a/BusinessSimulation/Icons/package.mo b/BusinessSimulation/Icons/package.mo new file mode 100644 index 0000000..0a800ce --- /dev/null +++ b/BusinessSimulation/Icons/package.mo @@ -0,0 +1,11 @@ +within BusinessSimulation; + +package Icons "Partial classes for icons" + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains partial classes for icons used in the library.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The real output y is obtained by converting the constant parameter value
into a continuous time signal.
This component is included for the sake of completeness; traditionally in System Dynamics an exogenous constant signal is modeled using a converter (→ConstantConverter).
+ConstantInputRate, ConstantInputTime, Converters.ConstantConverter, Converters.Vector.ConstantConverter
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, points = {{-50, 0}, {50, 0}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0), Text(visible = true, origin = {0, 90}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value", fontName = "Lato")})); +end ConstantInput; diff --git a/BusinessSimulation/InformationSources/ConstantInputRate.mo b/BusinessSimulation/InformationSources/ConstantInputRate.mo new file mode 100644 index 0000000..792672d --- /dev/null +++ b/BusinessSimulation/InformationSources/ConstantInputRate.mo @@ -0,0 +1,27 @@ +within BusinessSimulation.InformationSources; + +block ConstantInputRate "Input signal with constant rate information" + import BusinessSimulation.Units.Rate; + import BusinessSimulation.Types.TimeBases; + extends Icons.Converter; + extends Icons.InformationSourceIndicator; + extends Interfaces.Basics.OutputTypeChoice(redeclare replaceable type OutputType = Rate); + parameter Real value = 1 "Value of constant rate per time base given"; + parameter String timeBaseString = "second" "Time base of the rate entered (default = second)" annotation(choices(choice = "second", choice = "minute", choice = "hour", choice = "day", choice = "week", choice = "month", choice = "quarter", choice = "year")); + RealOutput y annotation(Placement(visible = true, transformation(origin = {161.717, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +protected + final parameter TimeBases timeBase = Functions.stringToTimeBase(timeBaseString) "Element of the enumeration TimeBases corresponding to the timeBase given as string" annotation(Dialog(tab = "Initialization", enable = false)); + Converters.RateConversion convertRate(timeBaseA = timeBase, timeBaseB = TimeBases.seconds) "Convert the rate input to a rate per seconds" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + convertRate.u = value; + // connect equations + connect(convertRate.y, y) annotation(Line(visible = true, origin = {87.259, -2.118}, points = {{-79.259, 2.118}, {74.457, 2.118}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The real output y is obtained by converting the constant rate value
into a continuous signal. The output will always give rates per second [1/s]
, but rates can be entered using non-SI-units of time.
This component is included for the sake of completeness; traditionally in System Dynamics an exogenous constant signal is modeled using a converter (→ConstantConverterRate).
+ConstantInput, ConstantInputTime, Converters.ConstantConverterRate, Converters.Vector.ConstantConverterRate
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, points = {{-50, 0}, {50, 0}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0), Text(visible = true, origin = {0, 90}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value per %timeBaseString", fontName = "Lato")})); +end ConstantInputRate; diff --git a/BusinessSimulation/InformationSources/ConstantInputTime.mo b/BusinessSimulation/InformationSources/ConstantInputTime.mo new file mode 100644 index 0000000..0ccb980 --- /dev/null +++ b/BusinessSimulation/InformationSources/ConstantInputTime.mo @@ -0,0 +1,21 @@ +within BusinessSimulation.InformationSources; + +block ConstantInputTime "Input signal with constant time information" + import BusinessSimulation.Units.Time; + import BusinessSimulation.Types.TimeBases; + extends Icons.Converter; + extends Icons.InformationSourceIndicator; + extends Interfaces.Basics.OutputTypeChoice(redeclare replaceable type OutputType = Time); + RealOutput y annotation(Placement(visible = true, transformation(origin = {161.74, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Time value "Constant value of time"; +equation + y = value; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The real output y is obtained by converting the time parameter value
into a continuous time signal. The output will always be given in seconds [s]
, but values can be entered using non-SI-units of time.
This component is included for the sake of completeness; traditionally in System Dynamics an exogenous constant signal is modeled using a converter (→ConstantConverterTime).
+ConstantInput, ConstantInputRate, Converters.ConstantConverterTime, Converters.Vector.ConstantConverterTime
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, points = {{-50, 0}, {50, 0}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0), Text(visible = true, origin = {0, 90}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%value", fontName = "Lato")})); +end ConstantInputTime; diff --git a/BusinessSimulation/InformationSources/ExogenousData.mo b/BusinessSimulation/InformationSources/ExogenousData.mo new file mode 100644 index 0000000..aa8129b --- /dev/null +++ b/BusinessSimulation/InformationSources/ExogenousData.mo @@ -0,0 +1,38 @@ +within BusinessSimulation.InformationSources; + +block ExogenousData "Reading external data from a file using Modelica's CombiTimeTable format (MCTT)" + import BusinessSimulation.Units.Time; + import Modelica.Blocks.Types.{Smoothness,Extrapolation,TimeEvents}; + extends Interfaces.Basics.BaseConverter; + extends Icons.InformationSourceIndicator; + RealOutput y if combiTimeTable.nout == 1 "Single Output" annotation(Placement(visible = true, transformation(origin = {160, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -1440))); + RealMultiOutput[combiTimeTable.nout] y_nout if combiTimeTable.nout > 1 "Output vector" annotation(Placement(visible = true, transformation(origin = {150, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + // RealMultiOutput y_nout[combiTimeTable.nout] if combiTimeTable.nout > 1 "Output vector" annotation(Placement(visible = true, transformation(origin = {150, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -1440))); + parameter Boolean tableOnFile = true "= true, if table is defined on file or in function usertab (combiTimeTable.tableOnFile)" annotation(Dialog(group = "TableDataDefinition")); + parameter Real table[:, :] = fill(0.0, 0, 2) "Table matrix (time = first column; e.g., table=[0, 0; 1, 1; 2, 4]) (combiTimeTable.table)" annotation(Dialog(group = "TableDataDefinition", enable = not tableOnFile)); + parameter String tableName = "NoName" "Table name on file or in function usertab (see docu) (combiTimeTable.tableName)" annotation(Dialog(group = "TableDataDefinition", enable = tableOnFile)); + parameter String fileNameURI = modelSettings.exogenousDataFileURI "URI for the exogenous data file" annotation(Evaluate = true, Dialog(group = "TableDataDefinition", enable = tableOnFile)); + parameter Boolean verboseRead = true "= true, if info message that file is loading is to be printed (combiTimeTable.verboseRead)" annotation(Dialog(group = "TableDataDefinition", enable = tableOnFile)); + parameter Integer columns[:] = 2:size(table, 2) "Columns of table to be interpolated (combiTimeTable.columns)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Smoothness smoothness = Smoothness.LinearSegments "Smoothness of table interpolation (combiTimeTable.smoothness)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Extrapolation extrapolation = Extrapolation.LastTwoPoints "Extrapolation of data outside the definition range (combiTimeTable.extrapolation)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Time timeScale(min = Modelica.Constants.eps) = 1 "Time scale of first table column (combiTimeTable.timeScale)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Real offset[:] = {0} "Offsets of output signals (combiTimeTable.offset)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Time startTime = 0 "Output = offset for time < startTime (combiTimeTable.startTime)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Time shiftTime = startTime "Shift time of first table column (combiTimeTable.shiftTime)" annotation(Dialog(group = "TableDataInterpretation")); + parameter TimeEvents timeEvents = TimeEvents.Always "Time event handling of table interpolation (combiTimeTable.timeEvents)" annotation(Dialog(group = "TableDataInterpretation")); + parameter Boolean verboseExtrapolation = false "= true, if warning messages are to be printed if time is outside the table definition range (combiTimeTable.verboseExtrapolation)" annotation(Dialog(group = "TableDataInterpretation")); + outer ModelSettings modelSettings; +protected + parameter String fileName = if tableOnFile then Modelica.Utilities.Files.loadResource(fileNameURI) else "NoName" annotation(Dialog(group = "Initialization", enable = false)); + Modelica.Blocks.Sources.CombiTimeTable combiTimeTable(tableOnFile = tableOnFile, table = table, tableName = tableName, fileName = fileName, verboseRead = verboseRead, columns = columns, smoothness = smoothness, extrapolation = extrapolation, timeScale = timeScale, offset = offset, startTime = startTime, shiftTime = shiftTime, timeEvents = timeEvents, verboseExtrapolation = verboseExtrapolation) annotation(Placement(visible = true, transformation(origin = {50, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(combiTimeTable.y[1], y) annotation(Line(visible = true, origin = {110.5, 0}, points = {{-49.5, 0}, {49.5, 0}}, color = {1, 37, 163})); + connect(combiTimeTable.y, y_nout) annotation(Line(visible = true, origin = {91.912, -10}, points = {{-30.912, 10}, {-11.912, 10}, {-11.912, -10}, {58.088, -10}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This block generates an output signal y_nout[:]
(or y
in case of a single output) by constant, linear or cubic Hermite spline interpolation in a table. The time points and function values are stored in a matrix table[i,j]
, where the first column table[:,1]
contains the time points and the other columns contain the data to be interpolated. For more information → Modelica.Blocks.Sources.CombiTimeTable.
This information is part of the Business Simulation Library (BSL).
+The Real output y is found by linear interpolation in a time table → Modelica.Blocks.Sources.TimeTable.
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end LinearTimeTable; diff --git a/BusinessSimulation/InformationSources/PulseInput.mo b/BusinessSimulation/InformationSources/PulseInput.mo new file mode 100644 index 0000000..25d1541 --- /dev/null +++ b/BusinessSimulation/InformationSources/PulseInput.mo @@ -0,0 +1,22 @@ +within BusinessSimulation.InformationSources; + +model PulseInput "Generate pulse or pulse-train signal of real input" + import BusinessSimulation.Units.Time; + extends Interfaces.PartialConverters.InformationSource_SO; + parameter OutputType offset = 0 "Offset of output signal y"; + parameter Time startTime = 0 "Output y = offset for time < startTime"; + parameter OutputType amplitude = 1 "Amplitude of pulse (with regard to offset)"; + parameter Real width(final min = Modelica.Constants.small, final max = 100) = 50 "Width of pulse in % of period"; + parameter Time period(final min = Modelica.Constants.small, start = 1) "Timespan for one period"; + parameter Integer nperiod = -1 "Number of periods (< 0 means infinite number of periods)"; +protected + Modelica.Blocks.Sources.Pulse pulse(offset = offset, startTime = startTime, amplitude = amplitude, width = width, period = period, nperiod = nperiod) annotation(Placement(visible = true, transformation(origin = {0.863, 0}, extent = {{-55.863, -55.863}, {55.863, 55.863}}, rotation = 0))); +equation + connect(pulse.y, y) annotation(Line(visible = true, origin = {111.156, 0}, points = {{-48.844, 0}, {48.844, 0}}, color = {0, 0, 127})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Real output y is a pulse signal → Modelica.Blocks.Sources.Pulse.
+ConstantInput, StepInput, RampInput, SineInput
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-17.67, 4.296}, points = {{-30, -24.296}, {0, -24.296}, {0, 24.296}, {30, 24.296}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0), Line(visible = true, origin = {16.467, 4.296}, points = {{30, -24.296}, {0, -24.296}, {0, 24.296}, {-30, 24.296}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end PulseInput; diff --git a/BusinessSimulation/InformationSources/RampInput.mo b/BusinessSimulation/InformationSources/RampInput.mo new file mode 100644 index 0000000..acbb96e --- /dev/null +++ b/BusinessSimulation/InformationSources/RampInput.mo @@ -0,0 +1,22 @@ +within BusinessSimulation.InformationSources; + +block RampInput "Generate ramp signal of real input" + import BusinessSimulation.Units.Time; + extends Interfaces.PartialConverters.InformationSource_SO; + parameter OutputType offset = 0 "Offset of output signal y"; + parameter Time startTime = 0 "Output y = offset for time < startTime"; + parameter OutputType height = 1 "Height of ramp"; + parameter Time duration = 1 "Duration of ramp (0 gives step)"; +protected + Modelica.Blocks.Sources.Ramp ramp(final offset = offset, final startTime = startTime, final height = height, final duration = duration) annotation(Placement(visible = true, transformation(origin = {1.356, 0}, extent = {{-48.644, -48.644}, {48.644, 48.644}}, rotation = 0))); +equation + connect(ramp.y, y) annotation(Line(visible = true, origin = {107.432, -0}, points = {{-52.568, -0}, {52.568, 0}}, color = {0, 0, 127})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Real output y is a ramp signal → Modelica.Blocks.Sources.Ramp.
+If parameter duration is set to zero, the output will be a step signal.
+ConstantInput, StepInput, PulseInput, SineInput
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-1.364, 0}, points = {{-38.636, -24.296}, {-8.636, -24.296}, {9.463, 24.296}, {37.808, 24.296}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end RampInput; diff --git a/BusinessSimulation/InformationSources/SineInput.mo b/BusinessSimulation/InformationSources/SineInput.mo new file mode 100644 index 0000000..02f85f3 --- /dev/null +++ b/BusinessSimulation/InformationSources/SineInput.mo @@ -0,0 +1,25 @@ +within BusinessSimulation.InformationSources; + +block SineInput "Generate sine wave as input signal" + import BusinessSimulation.Units.Time; + import Modelica.SIunits.{Frequency,Angle}; + extends Interfaces.PartialConverters.InformationSource_SO; + parameter OutputType offset = 0 "Offset of output signal y"; + parameter Time startTime = 0 "Output y = offset for time < startTime"; + parameter OutputType amplitude = 1 "Amplitude of sine wave (with regard to offset)"; + parameter Time period(min = 0.001) = 1 "Period of sine wave (= 1/freqHz)"; + parameter Angle phase = 0 "Phase of sine wave"; +protected + final Modelica.Blocks.Sources.Sine sine(offset = offset, startTime = startTime, amplitude = amplitude, freqHz = 1 / period, phase = phase) annotation(Placement(visible = true, transformation(origin = {1.413, -0}, extent = {{-46.413, -46.413}, {46.413, 46.413}}, rotation = 0))); +equation + assert(period > 0., "Period must be greater than zero"); + connect(sine.y, y) annotation(Line(visible = true, origin = {106.234, 0}, points = {{-53.766, 0}, {53.766, 0}}, color = {0, 0, 127})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Real output y is a sine signal → Modelica.Blocks.Sources.Sine.
+A cosine input signal can be simply achieved by using a SineInput with a phase of 90°.
+ConstantInput, StepInput, RampInput, PulseInput
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-3.666, -2.761}, points = {{-38.911, 1.472}, {-28.911, 27.793}, {-14.004, 36.075}, {-2.224, 22.761}, {4.77, -23.743}, {20.599, -31.106}, {33.666, -17.239}, {38.269, 3.313}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0, smooth = Smooth.Bezier)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SineInput; diff --git a/BusinessSimulation/InformationSources/StepInput.mo b/BusinessSimulation/InformationSources/StepInput.mo new file mode 100644 index 0000000..fb496d9 --- /dev/null +++ b/BusinessSimulation/InformationSources/StepInput.mo @@ -0,0 +1,19 @@ +within BusinessSimulation.InformationSources; + +model StepInput "Generate a step signal of real input" + import BusinessSimulation.Units.Time; + extends Interfaces.PartialConverters.InformationSource_SO; + parameter OutputType offset = 0 "Offset of output signal y"; + parameter Time startTime = 0 "Output y = offset for time < startTime"; + parameter OutputType height = 1 "Height of step"; +protected + Modelica.Blocks.Sources.Step step(final offset = offset, final startTime = startTime, final height = height) annotation(Placement(visible = true, transformation(origin = {1.316, -0}, extent = {{-58.684, -58.684}, {58.684, 58.684}}, rotation = 0))); +equation + connect(step.y, y) annotation(Line(visible = true, origin = {112.934, 0}, points = {{-47.066, 0}, {47.066, 0}}, color = {0, 0, 127})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Real output y is a step signal. For more information → Modelica.Blocks.Sources.Step.
+ConstantInput, RampInput, PulseInput, SineInput
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {0, 1.104}, points = {{-30, -24.296}, {0, -24.296}, {0, 24.296}, {30, 24.296}}, color = {255, 255, 255}, thickness = 4, arrowSize = 0)}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end StepInput; diff --git a/BusinessSimulation/InformationSources/TimeInput.mo b/BusinessSimulation/InformationSources/TimeInput.mo new file mode 100644 index 0000000..d5a7aa1 --- /dev/null +++ b/BusinessSimulation/InformationSources/TimeInput.mo @@ -0,0 +1,22 @@ +within BusinessSimulation.InformationSources; + +block TimeInput "Clock to provide time-signal" + import BusinessSimulation.Units.Time; + extends Interfaces.PartialConverters.InformationSource_SO(redeclare final type OutputType = Time); + extends Icons.Clockface_white; + parameter Time offset = modelSettings.modelStartTime "Offset of output signal y (default = modelStartTime)"; + parameter OutputType startTime = modelSettings.modelStartTime "Output y = offset for time <= startTime (default = modelStartTime)"; + outer ModelSettings modelSettings; +protected + final Modelica.Blocks.Sources.Clock clock(offset = offset, startTime = startTime) annotation(Placement(visible = true, transformation(origin = {10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(clock.y, y) annotation(Line(visible = true, origin = {90.5, 0}, points = {{-69.5, 0}, {69.5, 0}}, color = {1, 37, 163})); + annotation(__Wolfram(itemFlippingEnabled = true), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The output y is a time signal (e.g. a clock) → Modelica.Blocks.Sources.Clock.
+Time will always be given in the SIunit s
so that models are compatible with those from other domains. To provide a time signal in non SIunits (e.g. min, h, d, wk
etc.) TimeInputConverted should be used.
This information is part of the Business Simulation Library (BSL).
+The output y is a time signal (e.g. a clock) → Modelica.Blocks.Sources.Clock. The units for the output will here be a non-SIunit (e.g. min, h, d, wk
etc.).
To make models compatible internally time will always be in the SIunit s
while displayUnit
is used to enter and present values in a different unit of time.
This information is part of the Business Simulation Library (BSL).
+This package contains sources that provide continuous information (signals). Next to a ConstantInput
there are typical test inputs (StepInput, RampInput, PulseInput, SineInput
), inputs of time (TimeInput, ConvertedTimeInput
), and interpolation tables (LinearTimeTable, ExogenousData
).
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Partial block extending from Icons.Converter and →OutputTypeChoice. This is the base class for Converter components.
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BaseConverter; diff --git a/BusinessSimulation/Interfaces/Basics/BaseInformationProcessing.mo b/BusinessSimulation/Interfaces/Basics/BaseInformationProcessing.mo new file mode 100644 index 0000000..7a5b02c --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/BaseInformationProcessing.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Interfaces.Basics; + +partial block BaseInformationProcessing "Basic information processing class" + extends Icons.InformationProcessing; + extends OutputTypeChoice; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from Icons.InformationProcessing and →OutputTypeChoice. This is the base class for InformationProcessing-related components.
+MoleculesOfStructure.InformationProcessing
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BaseInformationProcessing; diff --git a/BusinessSimulation/Interfaces/Basics/BaseInformationProcessing_MO.mo b/BusinessSimulation/Interfaces/Basics/BaseInformationProcessing_MO.mo new file mode 100644 index 0000000..5a71aff --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/BaseInformationProcessing_MO.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Interfaces.Basics; + +partial block BaseInformationProcessing_MO "Basic information processing class with multiple outputs" + extends Icons.InformationProcessing; + extends OutputTypeChoice; + parameter Integer nout(min = 1) = 2 "Number of outputs" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from Icons.InformationProcessing and →OutputTypeChoice. This is the base class for InformationProcessing-related components with multiple outputs.
+MoleculesOfStructure.InformationProcessing
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BaseInformationProcessing_MO; diff --git a/BusinessSimulation/Interfaces/Basics/BasePolicy.mo b/BusinessSimulation/Interfaces/Basics/BasePolicy.mo new file mode 100644 index 0000000..39dbdaa --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/BasePolicy.mo @@ -0,0 +1,11 @@ +within BusinessSimulation.Interfaces.Basics; + +partial block BasePolicy "Basic policy class" + extends Icons.Policy; + extends OutputTypeChoice; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from Icons.Policy and →OutputTypeChoice. This is the base class for Policy-related components.
+This information is part of the Business Simulation Library (BSL).
+Partial block extending from Icons.Policy and →OutputTypeChoice_MO. This is the base class for Policy-related components with multiple outputs.
+This information is part of the Business Simulation Library (BSL).
+Partial model class with two →FlowPort connectors.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end GenericFlow; diff --git a/BusinessSimulation/Interfaces/Basics/GenericFlow_Special.mo b/BusinessSimulation/Interfaces/Basics/GenericFlow_Special.mo new file mode 100644 index 0000000..1bb0cbf --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/GenericFlow_Special.mo @@ -0,0 +1,9 @@ +within BusinessSimulation.Interfaces.Basics; + +partial model GenericFlow_Special "Flow Template with a FlowPort_Special (portA)" + Connectors.FlowPort_Special portA "Flow from/to Stock A (stock signals the rate)" annotation(Placement(visible = true, transformation(origin = {-148.205, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-100, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Connectors.FlowPort portB "Flow to/from Stock B" annotation(Placement(visible = true, transformation(origin = {148.205, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {100, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial model class with a →FlowPort_Special (portA
) and a regular →FlowPort (portB
).
This information is part of the Business Simulation Library (BSL).
+Partial model with a →StockInfoInput connector and five Real output connectors. The class is extended by sensor components that \"measure\" stock-related information.
+This information is part of the Business Simulation Library (BSL).
+Partial block extending from Icons.Smooth and →OutputTypeChoice. This is the base class for Smooth-like Converters.
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end GenericSmooth; diff --git a/BusinessSimulation/Interfaces/Basics/GenericSourceOrSink.mo b/BusinessSimulation/Interfaces/Basics/GenericSourceOrSink.mo new file mode 100644 index 0000000..7eba31c --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/GenericSourceOrSink.mo @@ -0,0 +1,10 @@ +within BusinessSimulation.Interfaces.Basics; + +partial model GenericSourceOrSink "SinkOrSource template with one flow port" + extends ThreeSO_rate; + Connectors.FlowPort massPort "Inflow to or outflow from connected stock" annotation(Placement(visible = true, transformation(origin = {148.334, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {100, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial model with three Real output connectors and a single →FlowPort connector. This is the base class for SourcesOrSinks components.
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end GenericSourceOrSink; diff --git a/BusinessSimulation/Interfaces/Basics/GenericStock.mo b/BusinessSimulation/Interfaces/Basics/GenericStock.mo new file mode 100644 index 0000000..3273b85 --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/GenericStock.mo @@ -0,0 +1,19 @@ +within BusinessSimulation.Interfaces.Basics; + +partial model GenericStock "Generic Stock to collect material or information" + import BusinessSimulation.Interfaces.Connectors.StockPort; + import BusinessSimulation.Interfaces.Basics.ThreeSO; + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Interfaces.Connectors.StockInfoOutput; + import BusinessSimulation.Icons.FlowIndicators; + extends ThreeSO; + extends FlowIndicators; + StockPort inflow "Inflow port of the stock" annotation(Placement(visible = true, transformation(origin = {-148.205, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-100, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + StockPort outflow "Outflow port of the stock" annotation(Placement(visible = true, transformation(origin = {148.464, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {100, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter InitializationOptions init = InitializationOptions.FixedValue "Provide InitializationOptions (Free, FixedValue, SteadyState)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + parameter Boolean hasStockInfoOutput = false "= true, if a StockInfoOutput should be added to the stock" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + StockInfoOutput y_stockInfo if hasStockInfoOutput "Optional StockInfoOutput" annotation(Placement(visible = true, transformation(origin = {150, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 104}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial model with three Real output connectors, two →StockPorts, and an optional →StockInfoOutput. This is the base class for stock components.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end GenericStock; diff --git a/BusinessSimulation/Interfaces/Basics/GenericStockInfo.mo b/BusinessSimulation/Interfaces/Basics/GenericStockInfo.mo new file mode 100644 index 0000000..0bd223b --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/GenericStockInfo.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Interfaces.Basics; + +partial model GenericStockInfo + Connectors.StockPort inPort "Connect to inflow of stock" annotation(Placement(visible = true, transformation(origin = {-148.318, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Connectors.StockPort outPort "Connect to outflow of stock" annotation(Placement(visible = true, transformation(origin = {147.895, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Connectors.StockInfoOutput y_stockInfo "StockInformation output" annotation(Placement(visible = true, transformation(origin = {150, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 60}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); + Connectors.RealInput levelInfo "Connect to level output of stock" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, -60}, extent = {{10, -10}, {-10, 10}}, rotation = -90))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial model with two →StockPorts, a Real information input (levelInfo
), and a →StockInfoOutput connector. This is the base class for a →StockInfo sensor.
This information is part of the Business Simulation Library (BSL).
+Partial model with a →StockPort connector on the inflow side, a →StockPort_Special connector on the outflow side, a Real information input (levelInfo
), and a →StockInfoOutput connector. This is the base class for a →DynamicStockInfo sensor.
This information is part of the Business Simulation Library (BSL).
+Partial model with three Real output connectors, a →StockPort connector on the inflow side, a →StockPort_Special connector on the outflow side, and an optional →StockInfoOutput. This is the base class for dynamic stock components that will usually signal the rate of outflow to a connected flow component.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end GenericStock_Special; diff --git a/BusinessSimulation/Interfaces/Basics/Interaction4SO.mo b/BusinessSimulation/Interfaces/Basics/Interaction4SO.mo new file mode 100644 index 0000000..d0600cb --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/Interaction4SO.mo @@ -0,0 +1,20 @@ +within BusinessSimulation.Interfaces.Basics; + +partial class Interaction4SO "Output connectors for interaction elements reporting rates" + replaceable type OutputType_A = Units.Rate constrainedby Units.Rate "Type selection for the flow to/from A"; + replaceable type OutputType_B = Units.Rate constrainedby Units.Rate "Type selection for the flow to/from B"; + RealOutput_B y_B "Rate for flow to and from B (positive value indicates inflow)" annotation(Placement(visible = true, transformation(origin = {160, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {50, 104}, extent = {{-10, -10}, {10, 10}}, rotation = -1350))); + RealOutput_B y1_B "Rate for flow to and from B (positive value indicates inflow)" annotation(Placement(visible = true, transformation(origin = {160, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {105, -50}, extent = {{-10, -10}, {10, 10}}, rotation = -360))); + RealOutput_A y1_A "Rate for flow to and from A (positive value indicates inflow)" annotation(Placement(visible = true, transformation(origin = {160, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-105, -50}, extent = {{-10, 10}, {10, -10}}, rotation = -180))); + RealOutput_A y_A "Rate for flow to and from A (positive value indicates inflow)" annotation(Placement(visible = true, transformation(origin = {160, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 104}, extent = {{-10, -10}, {10, 10}}, rotation = -1350))); + connector RealOutput_A = output OutputType_A "Output signal for A" annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Real output connector.
")); + connector RealOutput_B = output OutputType_B "Output signal for B" annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Real output connector.
")); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial model that has four Real output connectors (unit = \"1/s\"
). It is typically used by interaction flow components to report the current rates of flow for the two flow ports (two output connectors per port).
This information is part of the Business Simulation Library (BSL).
+A Real output connector.
")); + connector RealMultiOutput = output OutputType "Output signal" annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {100, 0}, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Real output connector to indicate vector or list output.
")); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial class that enables the redeclaration of type OutputType
which by default is set to Types.Reals
. This class is only used for extensions.
This information is part of the Business Simulation Library (BSL).
+A Real output connector.
")); + connector RealMultiOutput = output OutputType "Output signal" annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {100, 0}, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Real output connector to indicate vector or list output.
")); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial class that enables the redeclaration of type OutputType
which by default is set to Units.Rate
. This class is only used for extensions.
This information is part of the Business Simulation Library (BSL).
+A Real output connector.
")); + connector RealMultiOutput = output OutputType "Output signal" annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 255, 255}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {100, 0}, lineColor = {1, 37, 163}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Real output connector to indicate vector or list output.
")); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial class that enables the redeclaration of type OutputType
which by default is set to Units.Time
. This class is only used for extensions.
This information is part of the Business Simulation Library (BSL).
+Partial model with a single Real input connector u
. This class is typically used by Stock, Flow or SourcesOrSinks components to allow for an unnamed input connector in a standard position.
This information is part of the Business Simulation Library (BSL).
+Partial model that extends →OutputTypeChoice and has three Real output connectors. It is typically used by Stock components to report the amount inside (e.g. its state).
++ThreeSO_rate +
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ThreeSO; diff --git a/BusinessSimulation/Interfaces/Basics/ThreeSO_rate.mo b/BusinessSimulation/Interfaces/Basics/ThreeSO_rate.mo new file mode 100644 index 0000000..d0e4203 --- /dev/null +++ b/BusinessSimulation/Interfaces/Basics/ThreeSO_rate.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Interfaces.Basics; + +partial class ThreeSO_rate "Generic information output for flow elements" + extends OutputTypeChoice_Rate; + RealOutput y "Rate information" annotation(Placement(visible = true, transformation(origin = {160, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {50, 104}, extent = {{-10, -10}, {10, 10}}, rotation = -1350))); + RealOutput y1 "Rate information" annotation(Placement(visible = true, transformation(origin = {160, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {105, -50}, extent = {{-10, -10}, {10, 10}}, rotation = -360))); + RealOutput y2 "Rate information" annotation(Placement(visible = true, transformation(origin = {160, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-105, -50}, extent = {{-10, 10}, {10, -10}}, rotation = -180))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial model that has three Real output connectors (unit = \"1/s\"
). It is typically used by flow components to report the current rate of flow.
This information is part of the Business Simulation Library (BSL).
+This package contains partial classes at a very basic level (e.g. mostly just connectors and/or rudimentory functionality).
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+A Boolean input connector.
+")); diff --git a/BusinessSimulation/Interfaces/Connectors/BooleanMultiInput.mo b/BusinessSimulation/Interfaces/Connectors/BooleanMultiInput.mo new file mode 100644 index 0000000..3b3f63c --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/BooleanMultiInput.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Interfaces.Connectors; + +connector BooleanMultiInput = input Boolean "Input of a vector of Booleans" annotation(defaultComponentName = "u", Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-100, 0}, lineColor = {190, 52, 178}, fillColor = {190, 52, 178}, fillPattern = FillPattern.Solid, points = {{0, 50}, {100, 0}, {0, -50}, {0, 50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {190, 52, 178}, fillColor = {190, 52, 178}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}, {-100, 100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Boolean vector input connector.
+")); diff --git a/BusinessSimulation/Interfaces/Connectors/BooleanOutput.mo b/BusinessSimulation/Interfaces/Connectors/BooleanOutput.mo new file mode 100644 index 0000000..70d8da2 --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/BooleanOutput.mo @@ -0,0 +1,6 @@ +within BusinessSimulation.Interfaces.Connectors; + +connector BooleanOutput = output Boolean "Output flag" annotation(defaultComponentName = "y", Icon(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {190, 52, 178}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}})}), Diagram(coordinateSystem(preserveAspectRatio = true, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {100, 0}, lineColor = {190, 52, 178}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Boolean output connector.
+")); diff --git a/BusinessSimulation/Interfaces/Connectors/DataBus.mo b/BusinessSimulation/Interfaces/Connectors/DataBus.mo new file mode 100644 index 0000000..7112a93 --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/DataBus.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Interfaces.Connectors; + +expandable connector DataBus "Expandable connector for multiple data signals (input/output)" + extends Icons.DataBus; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A DataBus is an expandable connector for information inputs and outputs.
+All expandable connectors can be connected to each other and will propagate variables and connectors contained within. Nevertheless, it is good practice in System Dynamics modeling, to keep information and \"material\" networks separated from each other for clarity. Elements within a MultiPort should only be connected to elements in other MultiPorts, FlowPorts or StockPorts.
+FlowPort, StockPort, MultiPort, OmniBus
+")); +end DataBus; diff --git a/BusinessSimulation/Interfaces/Connectors/DataInPort.mo b/BusinessSimulation/Interfaces/Connectors/DataInPort.mo new file mode 100644 index 0000000..9149c8b --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/DataInPort.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Interfaces.Connectors; + +expandable connector DataInPort "Expandable connector for multiple inputs" + extends Icons.DataInPort; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A DataBus is an expandable connector for information inputs and outputs.
+All expandable connectors can be connected to each other and will propagate variables and connectors contained within. Nevertheless, it is good practice in System Dynamics modeling, to keep information and \"material\" networks separated from each other for clarity. Elements within a MultiPort should only be connected to elements in other MultiPorts, FlowPorts or StockPorts.
+FlowPort, StockPort, MultiPort, OmniBus
+", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}))); +end DataInPort; diff --git a/BusinessSimulation/Interfaces/Connectors/DataOutPort.mo b/BusinessSimulation/Interfaces/Connectors/DataOutPort.mo new file mode 100644 index 0000000..7399a1b --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/DataOutPort.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Interfaces.Connectors; + +expandable connector DataOutPort "Expandable connector for multiple outputs" + extends Icons.DataOutPort; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A DataBus is an expandable connector for information inputs and outputs.
+All expandable connectors can be connected to each other and will propagate variables and connectors contained within. Nevertheless, it is good practice in System Dynamics modeling, to keep information and \"material\" networks separated from each other for clarity. Elements within a MultiPort should only be connected to elements in other MultiPorts, FlowPorts or StockPorts.
+FlowPort, StockPort, MultiPort, OmniBus
+", revisions = ""), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}))); +end DataOutPort; diff --git a/BusinessSimulation/Interfaces/Connectors/ExpandableFlowPort.mo b/BusinessSimulation/Interfaces/Connectors/ExpandableFlowPort.mo new file mode 100644 index 0000000..ea31d82 --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/ExpandableFlowPort.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Interfaces.Connectors; + +expandable connector ExpandableFlowPort "Expandable connector for flow ports" + extends Icons.ExpandableFlowPort; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Expandable connector to accomodate multiple flow ports.
+While the FlowMultiPort component is typically used to visually show the presence of an array of FlowPort
, this component is an expandable connector that is much more flexible.
This information is part of the Business Simulation Library (BSL).
+Expandable connector to accomodate multiple stock ports.
+While the StockMultiPort component is typically used to visually show the presence of an array of StockPort
, this component is an expandable connector that is much more flexible.
This information is part of the Business Simulation Library (BSL).
+The FlowPort is the counter part to the StockPort and contains an acausal connector with the Real potential variable stock
indicating the stored amount in a connected reservoir and the Real flow variable rate
indicating the rate of flow into the connected stock (rate < 0
) or out of the connected stock (rate > 0
).
There are also two Boolean input variables, which indicate whether draining the connected reservoir (stopOutflow
) or filling it (stopInflow
) is prohibited. These signals originate with the connected stock.
This information is part of the Business Simulation Library (BSL).
+The FlowPort is the counter part to the StockPort and contains an acausal connector with the Real potential variable stock
indicating the stored amount in a connected reservoir and the Real flow variable rate
indicating the rate of flow into the connected stock (rate < 0
) or out of the connected stock (rate > 0
).
There are also two Boolean input variables, which indicate whether draining the connected reservoir (stopOutflow
) or filling it (stopInflow
) is prohibited. These signals originate with the connected stock.
This information is part of the Business Simulation Library (BSL).
+The FlowPort_Special is the corresponding connector to the StockPort_Special and will only connect to these. While usually the rate of flow is determined by a flow component, in the case of dynamic stocks (e.g. higher order delays) the rate of outflow will be determined by the stock component and transmitted to the connected flow using the variable data
.
It has the following connectors:
+CONNECTOR | TYPE | DESCRIPTION |
---|---|---|
data | +Real | +
+ Rate of flow to be observed by connected flow element + |
+
rate (flow) | +Real | +
+ Flow that affects the stock + |
+
The FlowPort_Special
connector class is used as MassPortF
by Peter Junglas for his approach to SystemDynamics modeling [18, Chapter 12] (see here for a System Dynamics Modelica library published by Peter Junglas) and has been simplified for the Business Simulation library.
This information is part of the Business Simulation Library (BSL).
+Like a DataBus for information inputs and outputs, the FlowMultiPort is an expandable connector that should only contain named FlowPort and/or StockPort connectors.
+All expandable connectors can be connected to each other and will propagate variables and connectors contained within. Nevertheless, it is good practice in System Dynamics modeling, to keep information and \"material\" networks separated from each other for clarity. Elements within a MultiPort should only be connected to elements in other MultiPorts, FlowPorts or StockPorts.
+FlowPort, StockPort, DataBus, OmniBus
+")); +end MultiPort; diff --git a/BusinessSimulation/Interfaces/Connectors/OmniBus.mo b/BusinessSimulation/Interfaces/Connectors/OmniBus.mo new file mode 100644 index 0000000..13a0ef1 --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/OmniBus.mo @@ -0,0 +1,13 @@ +within BusinessSimulation.Interfaces.Connectors; + +expandable connector OmniBus "Expandable connector for combined mass and information transport pipelines" + extends Icons.OmniBus; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The OmniBus is an expandable connector that can contain input and output-connnectors (data) as well as Stock- and Flow-Ports.
+All expandable connectors can be connected to each other and will propagate variables and connectors contained within.
+FlowPort, StockPort, DataBus, MultiPort
+", revisions = "")); +end OmniBus; diff --git a/BusinessSimulation/Interfaces/Connectors/RealInput.mo b/BusinessSimulation/Interfaces/Connectors/RealInput.mo new file mode 100644 index 0000000..26334df --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/RealInput.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Interfaces.Connectors; + +connector RealInput = input Real "Input signal" annotation(defaultComponentName = "u", Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-100, 0}, lineColor = {5, 5, 125}, fillColor = {5, 5, 125}, fillPattern = FillPattern.Solid, points = {{0, 50}, {100, 0}, {0, -50}, {0, 50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}, {-100, 100}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Real input connector.
")); diff --git a/BusinessSimulation/Interfaces/Connectors/RealMultiInput.mo b/BusinessSimulation/Interfaces/Connectors/RealMultiInput.mo new file mode 100644 index 0000000..45aab9f --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/RealMultiInput.mo @@ -0,0 +1,8 @@ +within BusinessSimulation.Interfaces.Connectors; + +connector RealMultiInput = input RealInput "Multiple input signals" annotation(defaultComponentName = "u", Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-100, 0}, lineColor = {5, 5, 125}, fillColor = {5, 5, 125}, fillPattern = FillPattern.Solid, points = {{0, 50}, {100, 0}, {0, -50}, {0, 50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}, {-100, 100}}), Ellipse(visible = true, origin = {-24.747, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, extent = {{-24.747, -24.747}, {24.747, 24.747}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+A Real input connector to indicate vector inputs.
+This information is part of the Business Simulation Library (BSL).
+A Real output connector to indicate vector or list output.
+This information is part of the Business Simulation Library (BSL).
+A Real output connector.
")); diff --git a/BusinessSimulation/Interfaces/Connectors/StockInfoInput.mo b/BusinessSimulation/Interfaces/Connectors/StockInfoInput.mo new file mode 100644 index 0000000..afd2eb7 --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/StockInfoInput.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Interfaces.Connectors; + +connector StockInfoInput = input Types.StockInformation "Input of record with stock-related information" annotation(Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-100, 0}, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 50}, {100, 0}, {0, -50}, {0, 50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, points = {{-100, 100}, {100, 0}, {-100, -100}, {-100, 100}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Input connector for →StockInformation.
")); diff --git a/BusinessSimulation/Interfaces/Connectors/StockInfoOutput.mo b/BusinessSimulation/Interfaces/Connectors/StockInfoOutput.mo new file mode 100644 index 0000000..634f924 --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/StockInfoOutput.mo @@ -0,0 +1,5 @@ +within BusinessSimulation.Interfaces.Connectors; + +connector StockInfoOutput = output Types.StockInformation "Output of record with stock-related information" annotation(Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {100, 0}, lineColor = {128, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-100, 50}, {0, 0}, {-100, -50}, {-100, 50}}), Text(visible = true, origin = {0, 80}, textColor = {128, 128, 128}, extent = {{-100, -12}, {100, 12}}, textString = "%name", fontName = "Lato", textStyle = {TextStyle.Bold})}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {128, 0, 128}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 1, points = {{-100, 100}, {100, 0}, {-100, -100}, {-100, 100}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Output connector for →StockInformation.
")); diff --git a/BusinessSimulation/Interfaces/Connectors/StockMultiPort.mo b/BusinessSimulation/Interfaces/Connectors/StockMultiPort.mo new file mode 100644 index 0000000..cf08e79 --- /dev/null +++ b/BusinessSimulation/Interfaces/Connectors/StockMultiPort.mo @@ -0,0 +1,11 @@ +within BusinessSimulation.Interfaces.Connectors; + +connector StockMultiPort "Used to represent multiple stock connectors" + extends StockPort; + annotation(Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {-5, 5}, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-55, -55}, {55, 55}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The StockPort is a composite connector and consists of an acausal connector with the Real potential variable stock
indicating the stored amount in a reservoir and the Real flow variable rate
indicating the rate of flow into (rate > 0
) or out of (rate < 0
) the reservoir.
There are also two Boolean output variables, which indicate whether draining the reservoir (stopOutflow
) or filling it (stopInflow
) is prohibited. Since a generic reservoir will have two ports it is possible to allow inflows and outflows on both ports (standard) or give the stock a clear direction of flow with one port serving as inflow
and the other as outflow
connector.
This information is part of the Business Simulation Library (BSL).
+The StockPort is a composite connector and consists of an acausal connector with the Real potential variable stock
indicating the stored amount in a reservoir and the Real flow variable rate
indicating the rate of flow into (rate > 0
) or out of (rate < 0
) the reservoir.
There are also two Boolean output variables, which indicate whether draining the reservoir (stopOutflow
) or filling it (stopInflow
) is prohibited. Since a generic reservoir will have two ports it is possible to allow inflows and outflows on both ports (standard) or give the stock a clear direction of flow with one port serving as inflow
and the other as outflow
connector.
This information is part of the Business Simulation Library (BSL).
+The StockPort_Special is typically used for a dynamic stock, e.g. a stock with some kind of internal behavior (e.g. a higher-order delay, a conveyor or an oven). While usually the rate of flow is determined by flow elements, here the real variable data
is most often used to signal the value of flow to the flow element, as the rate of flow is determined by the stock - not the flow - in that case.
It has the following connectors:
+CONNECTOR | TYPE | DESCRIPTION |
---|---|---|
data | +Real | +
+ Rate of flow to be observed by connected flow element + |
+
rate (flow) | +Real | +
+ Flow that affects the stock + |
+
StockPort_Sepcial connectors will only connect to FlowPort_Special connectors.
+The StockPort_Special
connector was used by Peter Junglas as MassPortR
for his approach to SystemDynamics modeling [18, Chapter 12] (see here for a SystemDynamics Modelica library published by Peter Junglas) and has been simplified for the Business Simulation library.
This information is part of the Business Simulation Library (BSL).
+This package contains connector
classes.
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →BooleanSO class with a Boolean output and a Boolean multi input connector.
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BooleanMISO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/BooleanSI2SO.mo b/BusinessSimulation/Interfaces/PartialConverters/BooleanSI2SO.mo new file mode 100644 index 0000000..9003800 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/BooleanSI2SO.mo @@ -0,0 +1,11 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block BooleanSI2SO "Converter with two boolean inputs and a boolean output" + extends BooleanSO; + Connectors.BooleanInput u1 "Input 1" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Connectors.BooleanInput u2 "Input 2" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, -50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from →BooleanSO with two Boolean input converters and a single Boolean output converter.
+"), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BooleanSI2SO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/BooleanSIRealSO.mo b/BusinessSimulation/Interfaces/PartialConverters/BooleanSIRealSO.mo new file mode 100644 index 0000000..4386cc5 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/BooleanSIRealSO.mo @@ -0,0 +1,9 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block BooleanSIRealSO "Converter with single boolean input and single real output" + extends SO; + Connectors.BooleanInput u "Input" annotation(Placement(visible = true, transformation(origin = {-145, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →SO class with a Real output and a Boolean input connector.
"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BooleanSIRealSO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/BooleanSISO.mo b/BusinessSimulation/Interfaces/PartialConverters/BooleanSISO.mo new file mode 100644 index 0000000..8265da8 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/BooleanSISO.mo @@ -0,0 +1,9 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block BooleanSISO "Converter with single input and single output" + extends BooleanSO; + Connectors.BooleanInput u "Input" annotation(Placement(visible = true, transformation(origin = {-145, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →BooleanSO class with a Boolean output and a Boolean input connector.
"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BooleanSISO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/BooleanSO.mo b/BusinessSimulation/Interfaces/PartialConverters/BooleanSO.mo new file mode 100644 index 0000000..8ba96ac --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/BooleanSO.mo @@ -0,0 +1,10 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block BooleanSO "Generic converter with a boolean output" + extends Icons.Converter; + Connectors.BooleanOutput y "Boolean output" annotation(Placement(visible = true, transformation(origin = {150, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -1440))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block with a Boolean output connector.
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BooleanSO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/InformationProcessing_MO.mo b/BusinessSimulation/Interfaces/PartialConverters/InformationProcessing_MO.mo new file mode 100644 index 0000000..70a9693 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/InformationProcessing_MO.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block InformationProcessing_MO "Information processing block with multiple outputs" + extends Basics.BaseInformationProcessing_MO; + RealMultiOutput[nout] y "Vector of information output signals" annotation(Placement(visible = true, transformation(origin = {150, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →BaseInformationProcessing_MO base class with nmultiple Real output connectors. This is the base class for InformationProcessing components with multiple outputs.
+MoleculesOfStructure.InformationProcessing
+"), __Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end InformationProcessing_MO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/InformationProcessing_SO.mo b/BusinessSimulation/Interfaces/PartialConverters/InformationProcessing_SO.mo new file mode 100644 index 0000000..c0e60fe --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/InformationProcessing_SO.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block InformationProcessing_SO "Information Processing Block" + extends Basics.BaseInformationProcessing; + RealOutput y "Information output signal" annotation(Placement(visible = true, transformation(origin = {160, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →BaseInformationProcessing base class with a Real output connector. This is the base class for InformationProcessing components.
+MoleculesOfStructure.InformationProcessing
+"), __Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end InformationProcessing_SO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/InformationSource_MO.mo b/BusinessSimulation/Interfaces/PartialConverters/InformationSource_MO.mo new file mode 100644 index 0000000..e285ea1 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/InformationSource_MO.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block InformationSource_MO "Information Source with multiple outputs" + extends MO; + extends Icons.InformationSourceIndicator; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →MO partial converter class with multiple Real output connectors. This is the base class for InformationSource components with multiple outputs.
+This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →SO partial converter class with a Real output connector. This is the base class for InformationSource components.
+This information is part of the Business Simulation Library (BSL).
+Partial block extending the →MO partial converter class with vectors of nin
Real input connectors and nout
Real output connectors.
This information is part of the Business Simulation Library (BSL).
+Partial block with multiple Real input and output connectors each of which have nin
elements.
This information is part of the Business Simulation Library (BSL).
+Partial block extending the →BaseConverter class with a vector of nin
Real input connectors and one Real output connector.
This information is part of the Business Simulation Library (BSL).
+Partial block extending the →BaseConverter class with a vector of nout
Real output connectors.
This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →BasePolicy_MO base class with multiple Real output connectors. This is the base class for Policy components used to model decision making with multiple outputs.
+This information is part of the Business Simulation Library (BSL).
+Partial block extending from the →BasePolicy base class with a Real output connector. This is the base class for Policy components used to model decision making.
+This information is part of the Business Simulation Library (BSL).
+Partial block extending from →BooleanSO with two Real input converters and a single Boolean output converter.
+"), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SI2BooleanSO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/SI2SO.mo b/BusinessSimulation/Interfaces/PartialConverters/SI2SO.mo new file mode 100644 index 0000000..c82b629 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/SI2SO.mo @@ -0,0 +1,11 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block SI2SO "Converter with two inputs and a single output" + extends SO; + Connectors.RealInput u1 "Input 1" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Connectors.RealInput u2 "Input 2" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, -50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending the →SO partial converter class with one Real output connector and two Real input connectors.
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SI2SO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/SI3SO.mo b/BusinessSimulation/Interfaces/PartialConverters/SI3SO.mo new file mode 100644 index 0000000..1dd13e5 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/SI3SO.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block SI3SO "Converter with three inputs and single output" + extends SO; + Connectors.RealInput u1 "Input 1" annotation(Placement(visible = true, transformation(origin = {-145, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Connectors.RealInput u3 "Input 3" annotation(Placement(visible = true, transformation(origin = {-145, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, -50}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Connectors.RealInput u2 "Input 2" annotation(Placement(visible = true, transformation(origin = {-145, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending the →SO partial converter class with one Real output connector and three Real input connectors.
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SI3SO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/SIBooleanSO.mo b/BusinessSimulation/Interfaces/PartialConverters/SIBooleanSO.mo new file mode 100644 index 0000000..84f3b97 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/SIBooleanSO.mo @@ -0,0 +1,9 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block SIBooleanSO "Generic converter with real input and boolean output" + extends BooleanSO; + Connectors.RealInput u "Input" annotation(Placement(visible = true, transformation(origin = {-145, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from →BooleanSO with a Real input and a Boolean output converter.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SIBooleanSO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/SISO.mo b/BusinessSimulation/Interfaces/PartialConverters/SISO.mo new file mode 100644 index 0000000..a344a83 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/SISO.mo @@ -0,0 +1,9 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block SISO "Converter with single input and single output" + extends SO; + Connectors.RealInput u "Input" annotation(Placement(visible = true, transformation(origin = {-145, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-80, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + annotation(Documentation(info = " +Partial block extending the →SO partial converter class with one Real output connector and a single Real input connector.
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SISO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/SO.mo b/BusinessSimulation/Interfaces/PartialConverters/SO.mo new file mode 100644 index 0000000..3ebbdac --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/SO.mo @@ -0,0 +1,9 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block SO "Generic converter for signals" + extends Basics.BaseConverter; + RealOutput y annotation(Placement(visible = true, transformation(origin = {160.268, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending the →BaseConverter class with one Real output connector.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/SmoothSISO.mo b/BusinessSimulation/Interfaces/PartialConverters/SmoothSISO.mo new file mode 100644 index 0000000..6bfc219 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/SmoothSISO.mo @@ -0,0 +1,10 @@ +within BusinessSimulation.Interfaces.PartialConverters; + +partial block SmoothSISO "Smooth-like converter" + extends Basics.GenericSmooth; + Connectors.RealInput u "Input" annotation(Placement(visible = true, transformation(origin = {-145, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-93.624, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + replaceable RealOutput y annotation(Placement(visible = true, transformation(origin = {160, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {100, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Partial block extending from →GenericSmooth with a Real input and a Real output connector.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SmoothSISO; diff --git a/BusinessSimulation/Interfaces/PartialConverters/package.mo b/BusinessSimulation/Interfaces/PartialConverters/package.mo new file mode 100644 index 0000000..345e087 --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialConverters/package.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.Interfaces; + +package PartialConverters "Partial converter classes" + extends Icons.VariantsPackage; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains partial classes to build →Converters.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Partial model extending from the →GenericFlow base class. This is a generic class for bi-directional flow components where the value for the rate at port A (A_rate
) can be set by an equation.
B_rate = - A_rate
.This information is part of the Business Simulation Library (BSL).
+Partial model extending from the →GenericFlow base class. This is a generic class for interactional flow components where the values for the rates at port A (A_rate
) and B (B_rate
) can be set by equations. Positive rates will fill the connected stocks, while negative rates will drain them.
This information is part of the Business Simulation Library (BSL).
+Partial model extending from the →GenericFlow base class. This is a generic class for unidirectional flow components where the value for the rate at port A (A_rate
) can be set by an equation. The rate has to be positive; negative values will cause a warning.
portA
) and will thus drain the stock connected to it.B_rate = - A_rate
.This information is part of the Business Simulation Library (BSL).
+This package contains partial classes to build →Flows.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Partial model extending from the →GenericSourceOrSink base class. This partial class can be used to model Sink components using equations to assign a value to the Real variable rate.
Only positive values should be assigned to rate
and accordingly negative values will cause a warning.
This information is part of the Business Simulation Library (BSL).
+Partial model extending from the →GenericSourceOrSink base class. This partial class can be used to model Source components using equations to assign a value to the Real variable rate
.
Only positive values should be assigned to rate
and accordingly negative values will cause a warning.
This information is part of the Business Simulation Library (BSL).
+Partial model extending from the →GenericSourceOrSink base class. This partial class can be used to model SourceOrSink components using equations to assign a value to the Real variable rate
.
A positive value for rate
will fill the connected stock; the reported rate (y, y1, y2
) will follow this convention.
This information is part of the Business Simulation Library (BSL).
+This package contains partial classes to build →SourcesOrSinks components.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This is the general, unrestricted reservoir of the System Dynamics methodology, it accumulates information transported by flow components connected to the StockPorts.
"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -80}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%initialValue", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BasicStock; diff --git a/BusinessSimulation/Interfaces/PartialStocks/package.mo b/BusinessSimulation/Interfaces/PartialStocks/package.mo new file mode 100644 index 0000000..e0669ce --- /dev/null +++ b/BusinessSimulation/Interfaces/PartialStocks/package.mo @@ -0,0 +1,11 @@ +within BusinessSimulation.Interfaces; + +package PartialStocks "Partial models for reservoir components (stocks or levels)" + extends Icons.VariantsPackage; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains partial classes to build →Stocks.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This package contains connectors and partial models (classes).
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This class should be placed in the top level scope of any simulation model. It will automatically be assigned the prefex inner
as it provides global parameters for the model.
This information is part of the Business Simulation Library (BSL).
+This is more or less the classical Bass diffusion model [5] that explains how new products get adopted in a population: Potential adopters turn into adopters being affected either by advertising or promotion (i.e. as innovators) or by social interaction (\"word of mouth\") with adopters (i.e. as imitators).
+The basic model for diffusion can also be used to model the spread of infectious diseases (→SIR). Since the disease is ultimately spread by contact with an infected person, the fractionalAdoptionRate in this case should be zero.
+While the structure in principle folllows Sterman's implementation [3, chapter 9], the component has been put in a more general form. We have to distinguish the following subgroups that make up the total population of potential contacts for social interaction:
+
portA
portB
Depending upon the structural parameter nextStageIsInfluencing
we may choose to take the converted adopters out of the group of influencers, e.g. a freshly converted adopter may not yet be entusiastic enough, while more elaborate epidemic models like the SEIR model distinguish an exposed stage, that is not yet infectious.
The behavior of the component is exactly specified by the following equations:
+totalPopulation = potentialAdopters + otherPopulation + adopters + otherAdopters
+adoptionRate = potentialAdopters · fractionalAdoptionRate
+conversionRate = potentialAdopters·(otherAdopters [+ adopters])·adoptionFraction·contactRate / totalPopulation
+totalAdoptionRate = adoptionRate + conversionRate +
This information is part of the Business Simulation Library (BSL).
+Actuators in general are systems that push and/or pull physical entities (\"mass\") to and from other systems while receiving and/or transmitting information (usually regarding the material process). Examples would be a mining company extracting resources from the ground and delivering raw materials to producers or a temporary employment agency sending workers to companies in need of temporary reinforcements of their labor force. Note, that in the latter example the flow of workers will be controlled by that subsystem, e.g. temporary workers will be sent and retracted by order of the employment agency.
+On a lower level, we may think of processes modeled as a subsystem, e.g. the diffusion of a new product via word of mouth.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Fatigue is modeled as a smooth of the normalized input u which is indicating the current workload with regard to capital equipment or workers. The current workload will be normalized by dividing the input u by a constant or a variable reference workload (referenceWorkload
or u_ref
, respectively). The timeToGetFatigued
describes the time constant for the smooth and indicates the lag between beginning to work at an excessive level and the onset of the full effect on productivity (or quality).
Janoscheks growth curve is used to model the nonlinear effect of a prolonged work intensity. It describes a negatively sloping s-shaped curve that will pass through the reference point (1,1). The upper bound of the effect (effectMax
) must be given slightly above 1.0 as the curve will collapse in all other cases. If the effect is to be clipped at 1.0 then the parameter clipEffect
should be set to true
.
hours worked per month
, output per hour
etc.).init
in the Advanced tab allows to select →InitializationOptions:initialFatigue
to determine the initial output of the smoothed, normalized workload.fatigue
using initialFatigue
as an initial guess.+SmoothN, +JanoschekNegative +
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 0, 128}, extent = {{-100, -12}, {100, 12}}, textString = "Effect of Fatigue", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {3.406, -40}, textColor = {0, 0, 128}, extent = {{-53.406, -6}, {53.406, 6}}, textString = "Fatigue", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {-9.184, -30}, points = {{-46.394, 0}, {77.285, 0}}, color = {128, 128, 128}, thickness = 1), Line(visible = true, origin = {-55.548, 15.857}, rotation = -270, points = {{-45.857, 0}, {34.143, 0}}, color = {128, 128, 128}, thickness = 1), Text(visible = true, origin = {-64.078, 47.363}, textColor = {0, 0, 128}, extent = {{-9.128, -6}, {9.128, 6}}, textString = "y", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {-16.063, -7.873}, points = {{-39.523, 20.125}, {14.222, 20.125}, {32.628, -20.736}, {77.803, -20.736}}, color = {0, 0, 128}, thickness = 3, smooth = Smooth.Bezier), Line(visible = true, origin = {2.099, -2.709}, points = {{-56.948, 1.709}, {-2.099, 1.709}}, color = {128, 128, 128}, pattern = LinePattern.Dot, thickness = 1), Line(visible = true, origin = {1.314, -32.099}, rotation = -90, points = {{-32.099, 1.709}, {-2.099, 1.709}}, color = {128, 128, 128}, pattern = LinePattern.Dot, thickness = 1), Ellipse(visible = true, origin = {3.097, -1}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Ellipse(visible = true, origin = {-55.199, -1}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}}), Ellipse(visible = true, origin = {3.097, -30}, lineColor = {128, 128, 128}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, extent = {{-2, -2}, {2, 2}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end EffectOfFatigue; diff --git a/BusinessSimulation/MoleculesOfStructure/Blocks/package.mo b/BusinessSimulation/MoleculesOfStructure/Blocks/package.mo new file mode 100644 index 0000000..230bcb3 --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/Blocks/package.mo @@ -0,0 +1,16 @@ +within BusinessSimulation.MoleculesOfStructure; + +package Blocks "Subsystems with input and output connectors only (Control and/or information processing)" + extends Icons.Package; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Blocks are information processing systems or (on a lower level of aggregation) processes with information inputs and outputs only. Typical examples will be management seen as a subsystem of a company receiving information from production systems, processing them and sending out information according to decision making policies. On a lower level a simple transformation of information may be modeled as a block.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y reports the balance of an account that is increased or decreased by flows connected to the stock ports or at given rates (u_plus
and u_minus
respectively) if hasRateInputs = true
. When there are interest payments (withInterest = true
) positive and negative balances of the account will lead to interest earned and interest paid, respectively. The associated fractional rates can be given either as constants or as variable inputs.
hasNetRateInput = true
the rate of flow for the account can be given as a netRate using the connector u_plus
only.Account
is a more general structure than the widely known bathtub [6, pp.10f.] +Reservoir +
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {-37.335, -106.294}, points = {{47.335, 101.43}, {57.335, 87.889}, {47.335, 79.179}}, color = {192, 192, 192}, thickness = 2, smooth = Smooth.Bezier), Text(visible = true, origin = {0, 75}, textColor = {76, 112, 136}, extent = {{-100, -12}, {100, 12}}, textString = "Account", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {5.84, -0.234}, points = {{0, 0}, {28.109, 0}}, color = {0, 128, 0}, thickness = 5), Ellipse(visible = true, origin = {19.978, 0}, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 0.5, extent = {{-4.138, -4.138}, {4.138, 4.138}}), Rectangle(visible = true, lineColor = {255, 0, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-10, -10}, {10, 10}}), Polygon(visible = true, origin = {34.453, -0.275}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-2.773, 3.823}, {-2.773, -3.863}, {5.547, 0.041}}), Line(visible = true, origin = {-46.16, -0.234}, points = {{0, 0}, {28.109, 0}}, color = {0, 128, 0}, thickness = 5), Ellipse(visible = true, origin = {-32.022, 0}, lineColor = {0, 128, 0}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 0.5, extent = {{-4.138, -4.138}, {4.138, 4.138}}), Polygon(visible = true, origin = {-17.547, -0.275}, lineColor = {0, 128, 0}, fillColor = {0, 128, 0}, fillPattern = FillPattern.Solid, points = {{-2.773, 3.823}, {-2.773, -3.863}, {5.547, 0.041}}), Line(visible = true, origin = {0, -48.109}, rotation = -270, points = {{0, 0}, {28.109, 0}}, color = {192, 192, 192}, thickness = 5), Ellipse(visible = true, origin = {0, -32.008}, rotation = -270, lineColor = {192, 192, 192}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 0.5, extent = {{-4.138, -4.138}, {4.138, 4.138}}), Polygon(visible = true, origin = {0.149, -18.15}, rotation = -270, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.773, 3.823}, {-2.773, -3.863}, {5.547, 0.041}}), Polygon(visible = true, origin = {0.02, -48.613}, rotation = -450, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.773, 3.823}, {-2.773, -3.863}, {5.547, 0.041}}), Polygon(visible = true, origin = {7.966, -28.246}, rotation = -153.312, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.773, 2.672}, {-2.773, -2.623}, {3.945, -0.02}}), Text(visible = true, origin = {-42.691, -60.518}, textColor = {192, 192, 192}, extent = {{-35.466, -6}, {35.466, 6}}, textString = "interestRate", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-32.399, 14}, textColor = {0, 128, 0}, extent = {{-9.174, -6}, {9.174, 6}}, textString = "+", fontName = "Lato Black"), Text(visible = true, origin = {20, 14}, textColor = {0, 128, 0}, extent = {{-9.174, -6}, {9.174, 6}}, textString = "–", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {-80.11, 43.016}, rotation = -8.77, points = {{71.259, -85.862}, {74.2, -75.29}, {81.612, -69.18}}, color = {192, 192, 192}, thickness = 2, smooth = Smooth.Bezier), Polygon(visible = true, origin = {-8.034, -36.411}, rotation = -153.312, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{2.773, -2.672}, {2.773, 2.623}, {-3.945, 0.02}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Account; diff --git a/BusinessSimulation/MoleculesOfStructure/Incubators/package.mo b/BusinessSimulation/MoleculesOfStructure/Incubators/package.mo new file mode 100644 index 0000000..77d4bfa --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/Incubators/package.mo @@ -0,0 +1,12 @@ +within BusinessSimulation.MoleculesOfStructure; + +package Incubators "Subssystems with stock ports only receiving and providing physical entities usually in a modified form" + extends Icons.Package; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Incubators are subsystems that can be seen as more aggregate versions of a stocks/reservoirs. They receive physical entities from other systems or provide entities to be \"withdrawn\". Entities stored in an incubator will typically be transformed while they are stored within the system.
+An account which allows physical deposits and withdrawals (e.g. a checking account) can be seen as a basic example: While money is stored in the account, interest payments are received increasing the balance of the account.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y is given by applying an aggregate function (e.g. →Min, →GeometricMean, →ArithmeticMean, →Max) to a set of performance indicator inputs u. Optionally a vector of weights can be given as constant weights
or external input u_weights
, so that weighted averages can be used.
BasicOrientation, +PerformanceIndicator +
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -25}, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Performance", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Aggregate", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); +end AggregatePerformance; diff --git a/BusinessSimulation/MoleculesOfStructure/InformationProcessing/BasicOrientation.mo b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/BasicOrientation.mo new file mode 100644 index 0000000..741e16b --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/BasicOrientation.mo @@ -0,0 +1,83 @@ +within BusinessSimulation.MoleculesOfStructure.InformationProcessing; + +model BasicOrientation "Assessing a system's performance and sustainability according to basic orientors" + import BusinessSimulation.Types.{BasicOrientors,AggregateFunctions}; + extends Icons.InformationProcessing; + Interfaces.Connectors.RealMultiInput u_weights[nPerf] if not hasConstantWeights "Weights to be used for performance measurement" annotation(Placement(visible = true, transformation(origin = {-145, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Interfaces.Connectors.RealMultiInput u[BasicOrientors] "Basic orientors to monitor a system's sustainability" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealInput u_psy if hasSentinentBeings "Psychological needs indicator (optional)" annotation(Placement(visible = true, transformation(origin = {-145, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput y_perf(final unit = "1") "Aggregate performance score for the monitored system" annotation(Placement(visible = true, transformation(origin = {160, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput y_sus(final unit = "1") "Aggregate degree of sustainability for the monitored system" annotation(Placement(visible = true, transformation(origin = {160, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Real[:] weights = ones(nPerf) "Weights for calculating a weighted average performance score (default = equal weights)" annotation(Dialog(enable = hasConstantWeights)); + parameter Boolean hasSentinentBeings = false "= true, if the system comprises sentinent beings with psychological needs" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantWeights = true "= true, if constant weights are to be used for performance aggregation" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter AggregateFunctions func = BusinessSimulation.Types.AggregateFunctions.arithmeticMean "Function to apply for aggregation (aggregatePerformance.func)"; +protected + constant Integer nOrientors = size(u, 1) "Number of basic orientors valid for any system"; + parameter Integer nPerf = if hasSentinentBeings then nOrientors + 1 else nOrientors "Number of orientors used for perfomance calculation" annotation(Evaluate = true, Dialog(group = "Initialization", enable = false)); + AggregatePerformance aggregatePerformance(useWeights = true, hasConstantWeights = false, nin = nPerf, func = func) annotation(Placement(visible = true, transformation(origin = {-20, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.PassThrough sustainabilityNonSentinent if not hasSentinentBeings "Sustainability score for systems without sentinent beings" annotation(Placement(visible = true, transformation(origin = {10, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Min sustainabilitySentinent if hasSentinentBeings "Sustainability score for systems with sentinent beings" annotation(Placement(visible = true, transformation(origin = {10, -65}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Vector.ConstantConverter parWeights(redeclare final type OutputType = Units.Dimensionless, final value = weights) if hasConstantWeights "Weights for performance score" annotation(Placement(visible = true, transformation(origin = {-120, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Vector.Min basicSustainability(redeclare final type OutputType = Units.Dimensionless, nin = nOrientors) "Sustainability score according to basic orientors" annotation(Placement(visible = true, transformation(origin = {-50, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(u, basicSustainability.u) annotation(Line(visible = true, origin = {-101.5, -40}, points = {{-43.5, 0}, {43.5, 0}}, color = {0, 0, 128})); + connect(basicSustainability.y, sustainabilityNonSentinent.u) annotation(Line(visible = true, origin = {-20, -40}, points = {{-22, 0}, {22, 0}}, color = {1, 37, 163})); + connect(sustainabilityNonSentinent.y, y_sus) annotation(Line(visible = true, origin = {89, -40}, points = {{-71, 0}, {71, 0}}, color = {1, 37, 163})); + connect(u_psy, sustainabilitySentinent.u1) annotation(Line(visible = true, origin = {-71.5, -60}, points = {{-73.5, 0}, {73.5, 0}}, color = {0, 0, 128})); + connect(sustainabilitySentinent.y, y_sus) annotation(Line(visible = true, origin = {74.5, -52.5}, points = {{-56.5, -12.5}, {-14.5, -12.5}, {-14.5, 12.5}, {85.5, 12.5}}, color = {1, 37, 163})); + connect(basicSustainability.y, sustainabilitySentinent.u2) annotation(Line(visible = true, origin = {-27.5, -55}, points = {{-14.5, 15}, {-7.5, 15}, {-7.5, -15}, {29.5, -15}}, color = {1, 37, 163})); + connect(u, aggregatePerformance.u[1:6]) annotation(Line(visible = true, origin = {-94, 0}, points = {{-51, -40}, {-6, -40}, {-6, 40}, {63, 40}}, color = {0, 0, 128})); + connect(u_psy, aggregatePerformance.u[7]) annotation(Line(visible = true, origin = {-84, -10}, points = {{-61, -50}, {4, -50}, {4, 50}, {53, 50}}, color = {0, 0, 128})); + connect(parWeights.y, aggregatePerformance.u_weights) annotation(Line(visible = true, origin = {-51.333, 70.333}, points = {{-62.667, 9.667}, {31.333, 9.667}, {31.333, -19.333}}, color = {1, 37, 163})); + connect(aggregatePerformance.y, y_perf) annotation(Line(visible = true, origin = {75.5, 40}, points = {{-84.5, 0}, {84.5, 0}}, color = {1, 37, 163})); + connect(u_weights, aggregatePerformance.u_weights) annotation(Line(visible = true, origin = {-61.667, 57}, points = {{-83.333, 3}, {41.667, 3}, {41.667, -6}}, color = {0, 0, 128})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Basic Orientation will provide two outputs: an aggregate performance score (y_perf
) and a score indicating the minimum sustainability (y_sus
) according to a set of basic orientor inputs u
.
While a system is free to emphasize certain orientors over others (i.e. freedom in the choice of weights according to preferences/strategies), no system can excape the pressures put upon it from its environment and other systems therein. In a much cited report to the Balaton Group Hartmut Bossel [22] identified six basic orientors, that will guide a (living) systems evolution in order to maintain viability [10, p. 185]:
+Basic Orientor | +Description | +
EXISTENCE | +The system must be compatible with, and able to exist in the normal environmental state. The information, energy, and material inputs necessary to sustain the system must be available. | +
EFFECTIVENESS | +The system should on balance (over the long-term) be effective (not necessarily efficient) in its efforts to secure scarce resources (information, matter, energy) from, and to exert influence on its environment. | +
FREEDOM OF ACTION | +The system must have the ability to cope in various ways with the challanges posed by environmental variety. | +
SECURITY | +The system must be able to protect itself from the detrimental effects of environmental variability, i.e. variable, fluctuating, and unpredictable conditions outside the normal environmental state. | +
ADAPTABILITY | +The system should be able to learn, adapt, and self-organize in order to generate more appropriate responses to challenges posed by environmental change. | +
COEXISTENCE | +The system must be able to modify its behavior to account for behavior and interestes (orientors) of other (actor) systems in its environment. | +
Each of the six basic dimensions highlights a necessary aspect of viability, that cannot be compensated by a good score in another dimension. Accordingly, the sustainability score according to the inputs for the basic orientors will be aggregated using the min operator. fo further details, see [10, Chapter 4].
++AggregatePerformance, +PerformanceIndicator, DmnlInput
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Basic", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -25}, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Orientation", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BasicOrientation; diff --git a/BusinessSimulation/MoleculesOfStructure/InformationProcessing/FinancialReporting.mo b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/FinancialReporting.mo new file mode 100644 index 0000000..7cead3f --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/FinancialReporting.mo @@ -0,0 +1,36 @@ +within BusinessSimulation.MoleculesOfStructure.InformationProcessing; + +model FinancialReporting "Periodic reporting of a financial flow for the past accounting period" + import BusinessSimulation.Units.Time; + extends Interfaces.PartialConverters.InformationProcessing_SO; + Interfaces.Connectors.RealInput u "Actual rate of financial flow" annotation(Placement(visible = true, transformation(origin = {-145, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-113.106, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + // parameter + parameter Time reportingPeriod = 1 "Accounting period"; + parameter Time offsetFirstReporting = reportingPeriod "The first report will be issued at startTime + offsetFirstRporting"; + parameter Real initialValue = 0 "Initial reported value (value to be reported until the first reporting date)"; +protected + Converters.Gap gap annotation(Placement(visible = true, transformation(origin = {70, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.DiscreteDelay.Sampler previousValue(samplingPeriod = reportingPeriod, offsetStartTime = offsetFirstReporting, initialValue = 0) "Reported flow for the previous reporting period" annotation(Placement(visible = true, transformation(origin = {20, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.DiscreteDelay.Sampler currentValue(samplingPeriod = reportingPeriod, offsetStartTime = offsetFirstReporting, initialValue = initialValue) "Reported actual flow at the end of each reporting period" annotation(Placement(visible = true, transformation(origin = {20, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.DiscreteDelay.DelayFixed delayedAccountingFlow(delayTime = reportingPeriod, initialValue = 0, hasConstantDelayTime = true, hasExogenousHistory = false, init = BusinessSimulation.Types.InitializationOptions.FixedValue) "Accounting flow delayed for one accounting period" annotation(Placement(visible = true, transformation(origin = {-90, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExogenousChange cumulating_previous "Previous flow" annotation(Placement(visible = true, transformation(origin = {-60, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.InformationLevel accruedPreviousFlow(initialValue = 0, init = BusinessSimulation.Types.InitializationOptions.FixedValue, redeclare replaceable type OutputType = OutputType) "Cumulative value for the delayed flow" annotation(Placement(visible = true, transformation(origin = {-10, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExogenousChange cumulating_actual "Current flow" annotation(Placement(visible = true, transformation(origin = {-60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.InformationLevel accruedFlow(init = BusinessSimulation.Types.InitializationOptions.FixedValue, redeclare replaceable type OutputType = OutputType) "Cumulative flow for the reporting period" annotation(Placement(visible = true, transformation(origin = {-10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(u, delayedAccountingFlow.u) annotation(Line(visible = true, origin = {-113.588, -10}, points = {{-31.412, 10}, {5.841, 10}, {5.841, -10}, {14.226, -10}}, color = {0, 0, 127})); + connect(delayedAccountingFlow.y, cumulating_previous.u) annotation(Line(visible = true, origin = {-70.155, -23.333}, points = {{-10.311, 3.333}, {5.155, 3.333}, {5.155, -6.667}}, color = {0, 0, 127})); + connect(u, cumulating_actual.u) annotation(Line(visible = true, origin = {-96.158, 7.3}, points = {{-48.842, -7.3}, {-18.364, -7.3}, {-18.364, 12.7}, {31.158, 12.7}, {31.158, 2.7}}, color = {0, 0, 127})); + connect(cumulating_actual.massPort, accruedFlow.inflow) annotation(Line(visible = true, origin = {-35, 0}, points = {{-15, 0}, {15, 0}}, color = {128, 0, 128})); + connect(accruedFlow.y, currentValue.u) annotation(Line(visible = true, origin = {0.213, 16.8}, points = {{-5.213, -6.4}, {-5.213, 3.2}, {10.425, 3.2}}, color = {0, 0, 127})); + connect(accruedPreviousFlow.y, previousValue.u) annotation(Line(visible = true, origin = {0.213, -23.2}, points = {{-5.213, -6.4}, {-5.213, 3.2}, {10.425, 3.2}}, color = {0, 0, 127})); + connect(cumulating_previous.massPort, accruedPreviousFlow.inflow) annotation(Line(visible = true, origin = {-35, -40}, points = {{-15, 0}, {15, 0}}, color = {128, 0, 128})); + connect(currentValue.y, gap.u1) annotation(Line(visible = true, origin = {43.091, 12.5}, points = {{-13.557, 7.5}, {-3.091, 7.5}, {-3.091, -7.5}, {18.909, -7.5}}, color = {0, 0, 127})); + connect(previousValue.y, gap.u2) annotation(Line(visible = true, origin = {43.091, -12.5}, points = {{-13.557, -7.5}, {-3.091, -7.5}, {-3.091, 7.5}, {18.909, 7.5}}, color = {0, 0, 127})); + connect(gap.y, y) annotation(Line(visible = true, origin = {88.681, 0}, points = {{-11.319, 0}, {71.319, 0}}, color = {0, 0, 127})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+In a continuous time simulation financial flows will show their current value at any time. While this is a clear advantage of a simulation—we will never know the true current rates in reality—we would often like to show the average flow with regard to a defined accounting period as it is typical for financial reporting (e.g. at the end of an acounting period the Finance Department will report a single value for the average revenue in the past period in monetary units per period).
+The FinancialReporting component will report such an averaged flow by showing the difference between the actual flow and the flow delayed by exactly the length of the accounting period. This difference will be sampled at the end of any accounting period during the simulation time horizon. During the accounting period the last reported value will be kept constant.
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -25}, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Reporting", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Financial", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -60}, {148.5, 40}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end FinancialReporting; diff --git a/BusinessSimulation/MoleculesOfStructure/InformationProcessing/PresentValue.mo b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/PresentValue.mo new file mode 100644 index 0000000..c41dbb9 --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/PresentValue.mo @@ -0,0 +1,37 @@ +within BusinessSimulation.MoleculesOfStructure.InformationProcessing; + +block PresentValue "Calculates the present value of a stream of cash flows" + import BusinessSimulation.Units.{Rate,Time}; + extends Interfaces.PartialConverters.InformationProcessing_SO; + Interfaces.Connectors.RealInput u "Cash stream input" annotation(Placement(visible = true, transformation(origin = {-145, 85}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealInput u_r if not hasConstantRate "Discount rate input" annotation(Placement(visible = true, transformation(origin = {-145, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Real initialValue = 0 "Initial PV at start time"; + parameter Rate rate = 0.05 "Constant discount rate per period (optional)" annotation(Dialog(enable = hasConstantRate)); + parameter Boolean hasConstantRate = false "If true the discount rate is a constant parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean isCCR = true "If false the given rate is transformed to a continuously compounding rate" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); +protected + Converters.AccumulationFunction futureValueFactor(isCCR = isCCR, redeclare replaceable type OutputType = Units.Dimensionless) "Accumulation function a(t)" annotation(Placement(visible = true, transformation(origin = {-60, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Division discountedStream "Discounted stream of cash flows" annotation(Placement(visible = true, transformation(origin = {0, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Stocks.InformationLevel PV(initialValue = initialValue, init = BusinessSimulation.Types.InitializationOptions.FixedValue) "Present Value for stream of cash flows" annotation(Placement(visible = true, transformation(origin = {90, 5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.Growth increasingPV "Present value is accumulation of discounted CF-stream" annotation(Placement(visible = true, transformation(origin = {50, 5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterRate parRate(value = rate) if hasConstantRate "Discount rate" annotation(Placement(visible = true, transformation(origin = {-130, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(increasingPV.massPort, PV.inflow) annotation(Line(visible = true, origin = {70, 5}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); + connect(PV.y1, y) annotation(Line(visible = true, origin = {112.625, 21.5}, points = {{-12.125, -21.5}, {7.375, -21.5}, {7.375, -21.5}, {47.375, -21.5}}, color = {0, 0, 127})); + connect(u_r, futureValueFactor.u) annotation(Line(visible = true, origin = {-106.5, 20}, points = {{-38.5, 0}, {38.5, 0}}, color = {0, 0, 128})); + connect(parRate.y, futureValueFactor.u) annotation(Line(visible = true, origin = {-98, 5}, points = {{-26, -15}, {-2, -15}, {-2, 15}, {30, 15}}, color = {1, 37, 163})); + connect(u, discountedStream.u1) annotation(Line(visible = true, origin = {-76.5, 85}, points = {{-68.5, 0}, {68.5, 0}}, color = {0, 0, 128})); + connect(futureValueFactor.y, discountedStream.u2) annotation(Line(visible = true, origin = {-25, 47.5}, points = {{-27, -27.5}, {-5, -27.5}, {-5, 27.5}, {17, 27.5}}, color = {1, 37, 163})); + connect(discountedStream.y, increasingPV.u) annotation(Line(visible = true, origin = {32.667, 58.333}, points = {{-24.667, 21.667}, {12.333, 21.667}, {12.333, -43.333}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The PresentValue component will accumulate a discounted cash flow stream. The discount factor at any time is given by the accumulation function a(t) for a given interest rate, that may be either a constant (rate
) or a variable input (u_r
).
Additional information can be found on Jim Hines' Molecules of Structure website: →Present Value.
++TimeValueOfMoney, +AccumulationFunction, +ForceOfInterest +
+"), Diagram(coordinateSystem(extent = {{-148.5, -35}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Present Value", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -25}, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "PV", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); +end PresentValue; diff --git a/BusinessSimulation/MoleculesOfStructure/InformationProcessing/ResidenceTime.mo b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/ResidenceTime.mo new file mode 100644 index 0000000..0f422b8 --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/ResidenceTime.mo @@ -0,0 +1,35 @@ +within BusinessSimulation.MoleculesOfStructure.InformationProcessing; + +block ResidenceTime "Calculate average time of residence or time needed for completion" + import BusinessSimulation.Constants.inf; + extends Icons.InformationProcessing; + parameter Real durationAtZeroRate = inf "Value for duration if the rateOfDepletion becomes zero"; + Interfaces.Connectors.RealInput u_level "Current level of work to do or simply level of stock being depleted by flow" annotation(Placement(visible = true, transformation(origin = {-145, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-109.796, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealInput u_rate "The rate at which the stock is drained or the tasks being completed" annotation(Placement(visible = true, transformation(origin = {-145, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110.231, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput y(quantity = "Time", unit = "s") "Time needed to complete work or drain stock" annotation(Placement(visible = true, transformation(origin = {160, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {112.58, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +protected + Converters.Division_Guarded residenceTime(outputIfZero = durationAtZeroRate, redeclare replaceable type OutputType = Units.Time) "Average time of residence in a stock that is being depleted" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ZeroIfNegative currentLevel "Current amount that is being depleted" annotation(Placement(visible = true, transformation(origin = {-50, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ZeroIfNegative rateOfDepletion(redeclare replaceable type OutputType = Units.Rate) "Rate of Depletion" annotation(Placement(visible = true, transformation(origin = {-50, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(residenceTime.y, y) annotation(Line(visible = true, origin = {84, 0}, points = {{-76, 0}, {76, 0}}, color = {0, 0, 127})); + connect(u_level, currentLevel.u) annotation(Line(visible = true, origin = {-101.5, 20}, points = {{-43.5, 0}, {43.5, 0}}, color = {0, 0, 127})); + connect(currentLevel.y, residenceTime.u1) annotation(Line(visible = true, origin = {-21.909, 12.5}, points = {{-20.091, 7.5}, {1.909, 7.5}, {1.909, -7.5}, {13.909, -7.5}}, color = {0, 0, 127})); + connect(u_rate, rateOfDepletion.u) annotation(Line(visible = true, origin = {-101.5, -20}, points = {{-43.5, 0}, {43.5, 0}}, color = {0, 0, 127})); + connect(rateOfDepletion.y, residenceTime.u2) annotation(Line(visible = true, origin = {-21.909, -12.5}, points = {{-20.091, -7.5}, {1.909, -7.5}, {1.909, 7.5}, {13.909, 7.5}}, color = {0, 0, 127})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Real output y is obtained by dividing the current amount in a material stocku_level
by the (positive) rate of its outflow u_rate
. According to Little's Law—a famous result from queueing theory—the output y will be equal to the mean time of residence in the stock if the system is in equilibrium.
u_level
) and the rate of outflow (u_rate
) have to be positive; negative values will be assumed to be zero.durationAtZeroRate
(default = Constants.inf
will be used to obtain the output.Additional information can be found on Jim Hines' Molecules of Structure website: →Residence Time.
+
+Decay
+
This information is part of the Business Simulation Library (BSL).
+The Real output y indicates the nominal value of the input u at the end (Future Value) or the beginning (Present Value) of a horizon of length u_T
using the interest rate u_r
according to the formula:
The given rate is assumed to be a continuously compounding rate (aka force of interest). Using the switch isCCR
automatic conversion of a discrete rate can be activated.
+PresentValue, +ForceOfInterest, +AccumulationFunction +
+"), Diagram(coordinateSystem(extent = {{-148.5, -70}, {148.5, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Time Value", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -25}, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "TVM", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); +end TimeValueOfMoney; diff --git a/BusinessSimulation/MoleculesOfStructure/InformationProcessing/Trend.mo b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/Trend.mo new file mode 100644 index 0000000..7399a6e --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/Trend.mo @@ -0,0 +1,60 @@ +within BusinessSimulation.MoleculesOfStructure.InformationProcessing; + +block Trend "Calculating a fractional rate of change to be used in forecasting" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.{Rate,Time}; + extends Interfaces.PartialConverters.InformationProcessing_SO(redeclare replaceable type OutputType = Rate); + Interfaces.Connectors.RealInput u "Current value as basis for trend formulation" annotation(Placement(visible = true, transformation(origin = {-145, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput y_ppc if reportPPC "Report the perceived present condition (optional)" annotation(Placement(visible = true, transformation(origin = {160, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {110, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Rate initialTrend = 0 "Initial trend" annotation(Dialog(enable = not init == InitializationOptions.SteadyState)); + parameter Time tppc(min = 0) = 1 "Averaging time for perception of current quantity (i.e. the present condition)"; + parameter Time thrc(min = 0) = 1 "Time horizon for reference condition"; + parameter Time tpt(min = 0) = 1 "Time to perceive the trend (i.e. there is gradual adaptation to a new trend)" annotation(Dialog(enable = smoothTrend)); + parameter Boolean smoothTrend = false "= true, if the calculated trend is to be smoothed" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean reportPPC = false "= true, if the perceived present conditon is to be reported" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter InitializationOptions init = modelSettings.init "Provide InitializationOptions (Free, FixedValue, SteadyState)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + outer ModelSettings modelSettings; +protected + parameter Real initialRC(fixed = false) "Initial Value for the reference condition" annotation(Dialog(tab = "Initialization", enable = false)); + parameter Real initialPPC(fixed = false) "InitialValue for the perceived present condition" annotation(Dialog(tab = "Initialization", enable = false)); + Converters.PassThrough actualTrend if not smoothTrend annotation(Placement(visible = true, transformation(origin = {80, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.DiscreteDelay.Smooth rc(initialValue = initialRC, hasConstantDelayTime = false, init = init) "Reference condition for calculating the fractional trend" annotation(Placement(visible = true, transformation(origin = {-50, -40}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); + Converters.DiscreteDelay.Smooth ppc(initialValue = initialPPC, hasConstantDelayTime = false, init = init) "Perceived present condition" annotation(Placement(visible = true, transformation(origin = {-85, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime parTPPC(value = tppc) "Time to perceive present condition" annotation(Placement(visible = true, transformation(origin = {-105, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime parTHRC(value = thrc) "Time horizon for the reference condition (duration of trend formulation)" annotation(Placement(visible = true, transformation(origin = {-105, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime parTPT(value = tpt) if smoothTrend "Time to perceive the trend (i.e. adjustment time)" annotation(Placement(visible = true, transformation(origin = {100, 25}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.DiscreteDelay.Smooth perceivedTrend(initialValue = initialTrend, hasConstantDelayTime = false, redeclare replaceable type OutputType = Rate, init = init) if smoothTrend "Perceived growth rate" annotation(Placement(visible = true, transformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Division_Guarded indicatedTrend "Indicated fractional growth rate (trend)" annotation(Placement(visible = true, transformation(origin = {30, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Gap delta "Difference between perceived present condition and reference condition" annotation(Placement(visible = true, transformation(origin = {-20, -5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Product_2 rcTimesTHRC "Referenc condition times time horizon for reference condition" annotation(Placement(visible = true, transformation(origin = {-6.933, -45}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +initial equation + initialPPC = u / (1 + tppc * initialTrend); + initialRC = initialPPC / (1 + thrc * initialTrend); +equation + connect(ppc.y, rc.u) annotation(Line(visible = true, origin = {-68.591, -20}, points = {{-6.409, 20}, {-1.409, 20}, {-1.409, -20}, {9.228, -20}}, color = {0, 0, 127})); + connect(u, ppc.u) annotation(Line(visible = true, origin = {-119.681, 0}, points = {{-25.319, 0}, {25.319, 0}}, color = {0, 0, 127})); + connect(perceivedTrend.y, y) "Fractional trend (fractional rate of growth)" annotation(Line(visible = true, origin = {122.384, -5}, points = {{-32.384, 5}, {-2.384, 5}, {-2.384, 5}, {27.616, 5}}, color = {1, 37, 163})); + connect(parTPPC.y, ppc.u_delayTime) annotation(Line(visible = true, origin = {-89.667, 15}, points = {{-9.333, 5}, {4.667, 5}, {4.667, -10}}, color = {1, 37, 163})); + connect(parTHRC.y, rc.u_delayTime) annotation(Line(visible = true, origin = {-66.333, -55}, points = {{-32.667, -5}, {16.333, -5}, {16.333, 10}}, color = {1, 37, 163})); + connect(parTPT.y, perceivedTrend.u_delayTime) annotation(Line(visible = true, origin = {84.667, 18.333}, points = {{9.333, 6.667}, {-4.667, 6.667}, {-4.667, -13.333}}, color = {1, 37, 163})); + connect(indicatedTrend.y, perceivedTrend.u) annotation(Line(visible = true, origin = {49.659, -5}, points = {{-11.659, -5}, {-4.659, -5}, {-4.659, 5}, {20.978, 5}}, color = {0, 0, 127})); + connect(ppc.y, delta.u1) annotation(Line(visible = true, origin = {-51.5, 0}, points = {{-23.5, 0}, {23.5, 0}}, color = {0, 0, 127})); + connect(delta.y, indicatedTrend.u1) annotation(Line(visible = true, origin = {5, -5}, points = {{-17, 0}, {17, 0}}, color = {0, 0, 127})); + connect(rc.y, delta.u2) annotation(Line(visible = true, origin = {-31.366, -25}, points = {{-8.634, -15}, {1.366, -15}, {1.366, 15}, {3.366, 15}}, color = {0, 0, 127})); + connect(rcTimesTHRC.y, indicatedTrend.u2) annotation(Line(visible = true, origin = {13.857, -30}, points = {{-12.79, -15}, {1.143, -15}, {1.143, 15}, {8.143, 15}}, color = {0, 0, 127})); + connect(parTHRC.y, rcTimesTHRC.u2) annotation(Line(visible = true, origin = {-45.868, -55}, points = {{-53.132, -5}, {15.868, -5}, {15.868, 5}, {30.935, 5}}, color = {0, 0, 127})); + connect(rc.y, rcTimesTHRC.u1) annotation(Line(visible = true, origin = {-27.466, -40}, points = {{-12.534, 0}, {12.534, 0}}, color = {0, 0, 127})); + connect(indicatedTrend.y, actualTrend.u) annotation(Line(visible = true, origin = {50, -20}, points = {{-12, 10}, {-5, 10}, {-5, -10}, {22, -10}}, color = {1, 37, 163})); + connect(actualTrend.y, y) annotation(Line(visible = true, origin = {122, -15}, points = {{-34, -15}, {-2, -15}, {-2, 15}, {38, 15}}, color = {1, 37, 163})); + connect(ppc.y, y_ppc) annotation(Line(visible = true, origin = {30.833, -51.667}, points = {{-105.833, 51.667}, {-100.833, 51.667}, {-100.833, -43.333}, {89.167, -43.333}, {89.167, -8.333}, {129.167, -8.333}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Trend component represents forecasting in behavioral models and has been proposed by Sterman [3, pp. 634 - 638]. The basic idea is rather intuitive: Forecasters perceive a present condition of some input as a smoothed input (ppc), while they also perceive the historic or reference condition (rc) as a smooth of their current perception.
+Dividing the diffence between the current condition and the reference condition by the reference condition will determine the fractional increase. A further division by the time horizon for the reference condition will then turn this into a fractional rate. The thus calculated rate of change (i.e. the indicated trend) may then again be smoothed, if smoothTrend = true
.
+TrendBasedForecast, +Smooth +
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {0, 0, 128}, extent = {{-96.456, -12}, {96.456, 12}}, textString = "Trend", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Rectangle(visible = true, origin = {12.357, -32.5}, lineColor = {128, 128, 128}, fillColor = {255, 255, 255}, pattern = LinePattern.Dash, extent = {{-45, -42.5}, {45, 42.5}}), Text(visible = true, origin = {10.611, -80}, textColor = {128, 128, 128}, extent = {{-54.39, -6.559}, {54.39, 6.559}}, textString = "indicatedTrend = ( ppc- rc ) / rc / thrc", fontSize = 16, fontName = "Arial")})); +end Trend; diff --git a/BusinessSimulation/MoleculesOfStructure/InformationProcessing/TrendBasedForecast.mo b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/TrendBasedForecast.mo new file mode 100644 index 0000000..e71373e --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/InformationProcessing/TrendBasedForecast.mo @@ -0,0 +1,44 @@ +within BusinessSimulation.MoleculesOfStructure.InformationProcessing; + +block TrendBasedForecast "Trend-based forecast for an exponentially growing quantity" + import BusinessSimulation.Units.{Rate,Time}; + extends Interfaces.PartialConverters.InformationProcessing_SO; + Interfaces.Connectors.RealInput u "Current value as basis for trend formulation" annotation(Placement(visible = true, transformation(origin = {-145, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + parameter Units.Rate initialTrend = 0 "Initial trend (fracGrowthRate.initialTrend)"; + parameter Time fcsth(min = 0) = 1 "Forecast horizon"; + parameter Time tppc(min = 0) = 1 "Averaging time for perception of current quantity (i.e. the present condition)"; + parameter Time thrc(min = 0) = 1 "Time horizon for reference condition"; + parameter Time tpt(min = 0) = 1 "Time to perceive the trend (i.e. there is gradual adaptation to a new trend)" annotation(Dialog(enable = smoothTrend)); + parameter Boolean smoothTrend = false "= true, if the calculated trend is to be smoothed (fracGrowthRate.smoothTrend)" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); +protected + Converters.Product_2 fractionalGrowth "FractionalGrowthRate times perceptionTime" annotation(Placement(visible = true, transformation(origin = {-7.422, 40.047}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Add_2 extrapolationFactor "Extrapolaton factor using fractional growth rate and perception time to eliminate perception lage" annotation(Placement(visible = true, transformation(origin = {21.781, 45}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Trend fracGrowthRate(tppc = tppc, thrc = thrc, tpt = tpt, reportPPC = true, initialTrend = initialTrend, smoothTrend = smoothTrend) "TREND-formulation is used to calculate a fractional growth rate" annotation(Placement(visible = true, transformation(origin = {-47.422, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Product_2 extrapolPC "Present Condition extrapolated from perceived quantity and the time to perceive it" annotation(Placement(visible = true, transformation(origin = {51.661, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + TimeValueOfMoney futureValue "Future value according to exponential growth model" annotation(Placement(visible = true, transformation(origin = {91.661, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime timePPC(value = tppc) "Time to perceive present condition" annotation(Placement(visible = true, transformation(origin = {-50, 45}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime forecastHorizon(value = fcsth) "Forecast horizon (T)" annotation(Placement(visible = true, transformation(origin = {56.661, -15}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverter one(value = 1, redeclare replaceable type OutputType = Units.Dimensionless) "Time to perceive present condition" annotation(Placement(visible = true, transformation(origin = {-6.688, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(u, fracGrowthRate.u) annotation(Line(visible = true, origin = {-101.896, 0}, points = {{-43.104, 0}, {43.103, 0}}, color = {0, 0, 127})); + connect(futureValue.y, y) annotation(Line(visible = true, origin = {115.342, 0}, points = {{-12.681, 0}, {44.658, -0}}, color = {0, 0, 127})); + connect(forecastHorizon.y, futureValue.u_T) annotation(Line(visible = true, origin = {71.286, -10}, points = {{-9.625, -5}, {0.375, -5}, {0.375, 5}, {8.875, 5}}, color = {1, 37, 163})); + connect(extrapolPC.y, futureValue.u) annotation(Line(visible = true, origin = {76.563, 10}, points = {{-16.902, 10}, {-1.466, 10}, {-1.466, -10}, {4.098, -10}}, color = {1, 37, 163})); + connect(fractionalGrowth.y, extrapolationFactor.u2) annotation(Line(visible = true, origin = {5.879, 40.023}, points = {{-5.301, 0.023}, {-1.301, 0.023}, {-1.301, -0.023}, {7.902, -0.023}}, color = {1, 37, 163})); + connect(one.y, extrapolationFactor.u1) annotation(Line(visible = true, origin = {5.68, 55}, points = {{-7.367, 5}, {-0.367, 5}, {-0.367, -5}, {8.102, -5}}, color = {1, 37, 163})); + connect(timePPC.y, fractionalGrowth.u1) annotation(Line(visible = true, origin = {-32.605, 45.023}, points = {{-12.395, -0.023}, {-2.395, -0.023}, {-2.395, 0.023}, {17.184, 0.023}}, color = {1, 37, 163})); + connect(extrapolationFactor.y, extrapolPC.u1) annotation(Line(visible = true, origin = {36.751, 35}, points = {{-6.97, 10}, {0.03, 10}, {0.03, -10}, {6.91, -10}}, color = {1, 37, 163})); + connect(fracGrowthRate.y, futureValue.u_r) annotation(Line(visible = true, origin = {43.56, 2.5}, points = {{-79.982, -2.5}, {21.44, -2.5}, {21.44, 2.5}, {37.101, 2.5}}, color = {1, 37, 163})); + connect(fracGrowthRate.y_ppc, extrapolPC.u2) annotation(Line(visible = true, origin = {-12.282, 5}, points = {{-24.14, -10}, {12.282, -10}, {12.282, 10}, {55.943, 10}}, color = {1, 37, 163})); + connect(fracGrowthRate.y, fractionalGrowth.u2) annotation(Line(visible = true, origin = {-26.593, 17.477}, points = {{-9.829, -17.477}, {-3.407, -17.523}, {-3.407, 17.523}, {11.171, 17.57}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The trend-based forecast makes use of a perceived present condition and a fractional growth rate computed by a →Trend block that follows the model proposed by Sterman [3, pp. 34 - 38].
+The perceived present condition (PPC) will be \"brought forward\" to the actual time using linear extrapolation:
+Extrapolated Present Condition = Perceived Present Condition · ( 1 + fractional growth rate · time to perceive present condition)
The actual forecast is then arrived at by using exponential growth and continuous compounding:
+forecast = extrapolated present condition · EXP( fractional growth rate · forecast horizon)
This information is part of the Business Simulation Library (BSL).
+This package contains components that represent some form of information processing—as opposed to actual decision making.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The output y is the product of the amount of some resource (u_res
) and its ability to generate a flow/action (i.e. its productivity u_prod
).
y[1/s] = u_res[1] · u_prod[1/s]
Additonal information can be found in [6, p. 109] and on Jim Hines's Molecules of Structure website: →Flow From Resource.
+This information is part of the Business Simulation Library (BSL).
+The output y is given by the expression:
+y = (u_reference - u_current) / u_adjTime
where the time to close the gap (u_adjTime
) can alternatively be a constant (adjTime
). If the adjustement time is zero, then the output y will be zero as well.
This information is part of the Business Simulation Library (BSL).
+The output y indicates the rate of inflow required to keep a stock at a desired level. The (perceived) outflow from the stock will be replaced immediately to keep the stock at its current level, while the gap between the current level and the desired level will be closed using a →CloseGap component.
+u_outflow
one should be aware of the fact, that in reality there will likely be a perception lag which may be modeled by a →Smooth or a more elaborate structure.+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 12.5}, textColor = {0, 0, 128}, extent = {{-77.269, -12}, {77.269, 12}}, textString = "First-Order", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -12.5}, textColor = {0, 0, 128}, extent = {{-77.987, -12}, {77.987, 12}}, textString = "Stock Adjustment", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end FirstOrderStockAdjustment; diff --git a/BusinessSimulation/MoleculesOfStructure/Policy/PID.mo b/BusinessSimulation/MoleculesOfStructure/Policy/PID.mo new file mode 100644 index 0000000..2a9f0b1 --- /dev/null +++ b/BusinessSimulation/MoleculesOfStructure/Policy/PID.mo @@ -0,0 +1,44 @@ +within BusinessSimulation.MoleculesOfStructure.Policy; + +block PID "Limited PID controller" + extends Interfaces.PartialConverters.Policy_SO; + import BusinessSimulation.Constants.{small,inf,eps}; + import BusinessSimulation.Units.Time; + import Modelica.Blocks.Types.InitPID; + import Modelica.Blocks.Types.Init; + import Modelica.Blocks.Types.SimpleController; + Interfaces.Connectors.RealInput u_desiredValue "The goal to meet (setpoint)" annotation(Placement(visible = true, transformation(origin = {-145, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -360))); + Interfaces.Connectors.RealInput u_currentValue "The measured state of the system under control" annotation(Placement(visible = true, transformation(origin = {-145, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -450))); + Interfaces.Connectors.RealInput u_feedForward if hasFeedForward "An optional feedforward input" annotation(Placement(visible = true, transformation(origin = {-145, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {50, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -450))); + parameter .Modelica.Blocks.Types.SimpleController controllerType = Modelica.Blocks.Types.SimpleController.PID "Type of controller" annotation(Dialog(group = "Structural Parameters")); + parameter Boolean hasFeedForward = false "Use feed-forward input? (PID.withFeedForward)" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Real k(min = 0) = 1 "Gain of controller"; + parameter Modelica.SIunits.Time Ti(min = small) = 0.5 "Time constant of Integrator block" annotation(Dialog(enable = controllerType == .Modelica.Blocks.Types.SimpleController.PI or controllerType == .Modelica.Blocks.Types.SimpleController.PID)); + parameter Modelica.SIunits.Time Td(min = 0) = 0.1 "Time constant of Derivative block" annotation(Dialog(enable = controllerType == .Modelica.Blocks.Types.SimpleController.PD or controllerType == .Modelica.Blocks.Types.SimpleController.PID)); + parameter Real yMax = inf "Upper limit of output"; + parameter Real yMin = -yMax "Lower limit of output"; + parameter Real wp(min = 0) = 1 "Set-point weight for Proportional block (0..1)"; + parameter Real wd(min = 0) = 0 "Set-point weight for Derivative block (0..1)" annotation(Dialog(enable = controllerType == .Modelica.Blocks.Types.SimpleController.PD or controllerType == .Modelica.Blocks.Types.SimpleController.PID)); + parameter Real Ni(min = 100 * eps) = 0.9 "Ni*Ti is time constant of anti-windup compensation" annotation(Dialog(enable = controllerType == .Modelica.Blocks.Types.SimpleController.PI or controllerType == .Modelica.Blocks.Types.SimpleController.PID)); + parameter Real Nd(min = 100 * eps) = 10 "The higher Nd, the more ideal the derivative block" annotation(Dialog(enable = controllerType == .Modelica.Blocks.Types.SimpleController.PD or controllerType == .Modelica.Blocks.Types.SimpleController.PID)); + parameter Real kFF = 1 "Gain of feed-forward input" annotation(Dialog(enable = withFeedForward)); + parameter .Modelica.Blocks.Types.InitPID initType = .Modelica.Blocks.Types.InitPID.DoNotUse_InitialIntegratorState "Type of initialization (1: no init, 2: steady state, 3: initial state, 4: initial output)" annotation(Evaluate = true, Dialog(group = "Initialization")); + parameter Real xi_start = 0 "Initial or guess value for integrator output (= integrator state)" annotation(Dialog(group = "Initialization", enable = controllerType == .Modelica.Blocks.Types.SimpleController.PI or controllerType == .Modelica.Blocks.Types.SimpleController.PID)); + parameter Real xd_start = 0 "Initial or guess value for state of derivative block" annotation(Dialog(group = "Initialization", enable = controllerType == .Modelica.Blocks.Types.SimpleController.PD or controllerType == .Modelica.Blocks.Types.SimpleController.PID)); + parameter Real y_start = 0 "Initial value of output" annotation(Dialog(enable = initType == .Modelica.Blocks.Types.InitPID.InitialOutput, group = "Initialization")); + parameter Modelica.Blocks.Types.LimiterHomotopy homotopyType = Modelica.Blocks.Types.LimiterHomotopy.Linear "Simplified model for homotopy-based initialization" annotation(Evaluate = true, Dialog(group = "Initialization")); + parameter Boolean strict = false "= true, if strict limits with noEvent(..)" annotation(Evaluate = true, choices(checkBox = true), Dialog(tab = "Advanced")); + parameter Boolean limitsAtInit = true "Has no longer an effect and is only kept for backwards compatibility (the implementation uses now the homotopy operator)" annotation(Dialog(tab = "Dummy"), Evaluate = true, choices(checkBox = true)); +protected + Modelica.Blocks.Continuous.LimPID PID(controllerType = Modelica.Blocks.Types.SimpleController.PID, withFeedForward = hasFeedForward, Ti = Ti, k = k, Td = Td, yMax = yMax, yMin = yMin, wp = wp, wd = wd, Ni = Ni, Nd = Nd, kFF = kFF, xi_start = xi_start, xd_start = xd_start, y_start = y_start, homotopyType = homotopyType) annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(u_desiredValue, PID.u_s) annotation(Line(visible = true, origin = {-78.5, 0}, points = {{-66.5, 0}, {66.5, 0}}, color = {0, 0, 127})); + connect(u_currentValue, PID.u_m) annotation(Line(visible = true, origin = {-48.333, -30.667}, points = {{-96.667, -9.333}, {48.333, -9.333}, {48.333, 18.667}}, color = {0, 0, 127})); + connect(PID.y, y) annotation(Line(visible = true, origin = {85.5, 0}, points = {{-74.5, 0}, {74.5, 0}}, color = {0, 0, 127})); + connect(u_feedForward, PID.u_ff) annotation(Line(visible = true, origin = {-44.333, -44}, points = {{-100.667, -16}, {50.333, -16}, {50.333, 32}}, color = {0, 0, 128})); + annotation(Documentation(info = " +
This information is part of the Business Simulation Library (BSL).
+This element makes use of the →LimPID element in the Modelica Standard Library. The controller is a very flexible component which allows to model P, PI, PD, PID controllers as needed.
+A PID controller continually calculates the error e(t) = u_desiredValue - u_currentValue
and then applies a correction based upon proportional (P), integral (I), and derivatice (D) terms.
This information is part of the Business Simulation Library (BSL).
+This package contains pre-built components for typical \"policy\" modules representing some form of decision making (sometimes also of information processing).
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+A chain (aka cascade) consists of a series of →reservoirs that are connected in a sequence. Depending upon the Boolean parameter hasFlowPort
the component will either end in a →Cloud or in a →FlowPort.
This information is part of the Business Simulation Library (BSL).
+The reservoir structure consists of a stock component that is typically filled via the accumulated net flow received at its stockPort
. The stock is then drained at a rate set by the input u.
The stock component used is declared as
+replaceable Stocks.Informationlevel stock constrainedby Interfaces.PartialStocks.BasicStock+
Accordingly the →InformationLevel
can be redeclared either as a →MaterialStock
or a →CapacityRestrictedStock
.
This information is part of the Business Simulation Library (BSL).
+The flow connected to the stock port (stockPort
) will be split or broken into n = nout
flows. This is a rather generic component, so that the input vector u of weights or factors may add up to 1 (the flow is split into n components that in sum will match the aggregate flow) or not.
When the factors do not add up to 1, the structure can be used to describe some kind of multiple-production from one main effort, e.g. the flow of work hours per period may be used to produce n products according to a productivity ratio ( products per work hour ).
+stockPort
. If a negative rate at stockPort
splits an inflow to a stock, then several stocks connected to flowPort
will be drained.stopInflow
and stopOutflow
signals at its flowPort
, so that if any of these are true
, the corresponding signal will be set to true
at the stockPort side.This information is part of the Business Simulation Library (BSL).
+Transceivers are the most general type of subsystem as they will be receptors as well as actuators with regard to physical entities (\"mass\"). Typically all manufacturing in an economy (seconday sector) can by seen as a transceiver, receiving raw material while pushing onward finished goods to distributors. Note, that when order flows are modeled explicitly even subsystems of the primary sector (e.g. mining, fishing, and agriculture) may be modeled as transceivers.
+On a lower level of aggregation we may simply conceive of transceivers as subsystems that start with a stock port on one end while transmitting stuff via a flow port on the other end.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This package contains generic model structure widely used by the System Dynamics community. Since this library makes use of acausal connectors to represent \"mass ports\"—connectors for what would be a double arrow connecting in classical System Dynamics notation—it turned out, that the organization of Molecules in this library should best be done with a focus on the actual interfaces (i.e. connectors) of a generic structure.
+There exist well known generic structures in the System Dynamics methodology that are reused over and over—quite independent from the actual modeling domain. James \"Jim\" Hines [6] has meticulously collected such elementary structures and coined the term \"Molecules of Structure\".
+In building the Business Simulation Library the name \"Molecules of Structure\" was adapted and whenever possible it was tried to stick to the names in Jim Hines' publication as that use is widespread in the System Dynamics community. Nevertheless, the object-oriented nature of Modelica allows to do what Hines has only hinted at: It can reuse components and thus truly arrive at new structure built upon existing structure.
++Tutorial.ElementaryBuildingBlocks, +Molecules of Structure Website (maintained by Jim Hines) +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The AbsoluteSensor connects to the StockInfoOutput
connectors (y_stockInfo
), which can be turned on and off). It reports the following information via its output connectors:
StockPort
—for this to be meaningful known inflows and outflows should be connected to the designated inflow
and outflow
ports of a stock. If a bi-flow is connected to a stock's port, then no other flow component should be connected to that port.-1
will be reported.This information is part of the Business Simulation Library (BSL).
+The DynamicStockInfo is used inside stock components with inherent dynamic behavior (e.g. a →DelayN) and will be connected to the matching outside connectors of a component to collect basic →stock-related information which will be passed as a record to the StockInfoOutput
connector.
StockPort
—for this to be meaningful known inflows and outflows should be connected to the designated inflow
and outflow
ports of a stock. If a bi-flow is connected to a stock's port, then no other flow component should be connected to that port.residenceTimeInfo
input connector. This information is part of the Business Simulation Library (BSL).
+This component is typically used to build submodels where the information regarding the amount in a connected stock needs to be extracted from an outside FlowPort
.
For example, the FlowPortSensor is used inside the SourceOrSink component ExponentialGrowth, where the level information is needed for the stock as it will be multiplied with a fractional rate to obtain the actual rate for the component's flow into the stock.
+FlowPortSensor_Control, StockPortSensor
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {0, 33.849}, points = {{0, -33.849}, {0, 33.849}}, color = {128, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {0, 70}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {76, 112, 136}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-20.708, -20.708}, {20.708, 20.708}}), Line(visible = true, origin = {-14.33, 77.5}, rotation = -300, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-8.5, 83.33}, rotation = 30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {0.219, 86.375}, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-2.624, 73.453}, rotation = -300, points = {{2.435, 4.688}, {-2.435, -4.688}}, color = {255, 0, 0}, thickness = 1), Line(visible = true, origin = {13.857, 78.141}, rotation = 660, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {7.922, 84.346}, rotation = -30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Text(visible = true, origin = {0, 60}, textColor = {255, 255, 255}, extent = {{-12.617, -10}, {12.617, 10}}, textString = "S", fontSize = 30, fontName = "Arial", textStyle = {TextStyle.Bold}), Ellipse(visible = true, origin = {0.097, 70}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Text(visible = true, origin = {1.113, -50.492}, textColor = {0, 0, 128}, extent = {{-141.113, -29.508}, {141.113, 29.508}}, textString = "%name", fontSize = 100, fontName = "Arial", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end FlowPortSensor; diff --git a/BusinessSimulation/Sensors/FlowPortSensor_Control.mo b/BusinessSimulation/Sensors/FlowPortSensor_Control.mo new file mode 100644 index 0000000..45439bf --- /dev/null +++ b/BusinessSimulation/Sensors/FlowPortSensor_Control.mo @@ -0,0 +1,27 @@ +within BusinessSimulation.Sensors; + +model FlowPortSensor_Control "Level information for an outside FlowPort" + Interfaces.Connectors.FlowPort flowPort annotation(Placement(visible = true, transformation(origin = {0, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.RealOutput stock "Current amount in connected stock" annotation(Placement(visible = true, transformation(origin = {160, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0.488, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); + Interfaces.Connectors.BooleanOutput stopInflow "Report the signal received" annotation(Placement(visible = true, transformation(origin = {150, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-20, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Interfaces.Connectors.BooleanOutput stopOutflow "Report the signal received" annotation(Placement(visible = true, transformation(origin = {150, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {20, 30}, extent = {{10, -10}, {-10, 10}}, rotation = -540))); +initial equation + // properly initialize discret vars with fixed = false + pre(stopInflow) = flowPort.stopInflow; + pre(stopOutflow) = flowPort.stopOutflow; +equation + // no flow for this component + flowPort.rate = 0; + stock = flowPort.stock; + stopInflow = flowPort.stopInflow; + stopOutflow = flowPort.stopOutflow; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This component is typically used to build submodels where the information regarding the amount in a connected stock needs to be extracted from an outside FlowPort
.
For example, the FlowPortSensor is used inside the SourceOrSink component ExponentialGrowth, where the level information is needed for the stock as it will be multiplied with a fractional rate to obtain the actual rate for the component's flow into the stock.
+While the FlowPortSensor only reports the rate of flow, this component additionally reports the Boolean signals (stopInflow, stopOutflow
) received at the outside FlowPort
.
FlowPortSensor, StockPortSensor
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {0, 33.849}, points = {{0, -33.849}, {0, 33.849}}, color = {128, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {0, 70}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {76, 112, 136}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-20.708, -20.708}, {20.708, 20.708}}), Line(visible = true, origin = {-14.33, 77.5}, rotation = -300, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-8.5, 83.33}, rotation = 30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {0.219, 86.375}, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-2.624, 73.453}, rotation = -300, points = {{2.435, 4.688}, {-2.435, -4.688}}, color = {255, 0, 0}, thickness = 1), Line(visible = true, origin = {13.857, 78.141}, rotation = 660, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {7.922, 84.346}, rotation = -30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Text(visible = true, origin = {0, 60}, textColor = {255, 255, 255}, extent = {{-12.617, -10}, {12.617, 10}}, textString = "S", fontSize = 30, fontName = "Arial", textStyle = {TextStyle.Bold}), Ellipse(visible = true, origin = {0.097, 70}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Text(visible = true, origin = {1.113, -50.492}, textColor = {0, 0, 128}, extent = {{-141.113, -29.508}, {141.113, 29.508}}, textString = "%name", fontSize = 100, fontName = "Arial", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end FlowPortSensor_Control; diff --git a/BusinessSimulation/Sensors/StockInfo.mo b/BusinessSimulation/Sensors/StockInfo.mo new file mode 100644 index 0000000..20da92a --- /dev/null +++ b/BusinessSimulation/Sensors/StockInfo.mo @@ -0,0 +1,32 @@ +within BusinessSimulation.Sensors; + +model StockInfo "Collect basic stock-related information for basic stocks" + extends Interfaces.Basics.GenericStockInfo; +protected + Real totalFlow = inPort.rate + outPort.rate; + Real inflowInflow, inflowOutflow, outflowInflow, outflowOutflow; +equation + // separate the flows + inflowInflow = if noEvent(inPort.rate > 0) then inPort.rate else 0; + inflowOutflow = if noEvent(inPort.rate < 0) then -inPort.rate else 0; + outflowInflow = if noEvent(outPort.rate > 0) then outPort.rate else 0; + outflowOutflow = if noEvent(outPort.rate < 0) then -outPort.rate else 0; + // report information + y_stockInfo.infoLevel = levelInfo; + y_stockInfo.infoInflow = inflowInflow + outflowInflow; + y_stockInfo.infoOutflow = inflowOutflow + outflowOutflow; + y_stockInfo.infoNetFlow = totalFlow; + y_stockInfo.infoMeanResidenceTime = if noEvent(y_stockInfo.infoOutflow > 0) then levelInfo / y_stockInfo.infoOutflow else -1; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The StockInfo is used inside stock components and will be connected to the matching outside connectors of a component to collect basic →stock-related information which will be passed as a record to the StockInfoOutput connector.
+StockPort
—for this to be meaningful known inflows and outflows should be connected to the designated inflow
and outflow
ports of a stock. If a bi-flow is connected to a stock's port, then no other flow component should be connected to that port.-1
will be reported.AbsoluteSensor, DynamicStockInfo
+"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end StockInfo; diff --git a/BusinessSimulation/Sensors/StockPortSensor.mo b/BusinessSimulation/Sensors/StockPortSensor.mo new file mode 100644 index 0000000..bef88a2 --- /dev/null +++ b/BusinessSimulation/Sensors/StockPortSensor.mo @@ -0,0 +1,20 @@ +within BusinessSimulation.Sensors; + +model StockPortSensor "Rate of flow information from stock ports" + Interfaces.Connectors.RealOutput netFlow(quantity = "Rate", unit = "1/s") "Current netflow" annotation(Placement(visible = true, transformation(origin = {160, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0.237, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); + Interfaces.Connectors.StockPort stockPort annotation(Placement(visible = true, transformation(origin = {-148.083, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-100, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.FlowPort flowPort annotation(Placement(visible = true, transformation(origin = {147.868, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {97.643, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + netFlow = stockPort.rate; + stockPort.stock = flowPort.stock; + flowPort.rate = -stockPort.rate; + // relay the boolean signals from flowPort to stockPort + stockPort.stopInflow = flowPort.stopInflow; + stockPort.stopOutflow = flowPort.stopOutflow; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This component is typically used to build submodels where the information regarding the rate of flow needs to be extracted from the outside StockPort
.
StockPortSensor_Control, FlowPortSensor
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {0, 33.849}, points = {{0, -33.849}, {0, 33.849}}, color = {128, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {0, 70}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {76, 112, 136}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-20.708, -20.708}, {20.708, 20.708}}), Line(visible = true, origin = {-14.33, 77.5}, rotation = -300, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-8.5, 83.33}, rotation = 30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {0.219, 86.375}, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-2.624, 73.453}, rotation = -300, points = {{2.435, 4.688}, {-2.435, -4.688}}, color = {255, 0, 0}, thickness = 1), Line(visible = true, origin = {13.857, 78.141}, rotation = 660, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {7.922, 84.346}, rotation = -30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Text(visible = true, origin = {0, 60}, textColor = {255, 255, 255}, extent = {{-12.617, -10}, {12.617, 10}}, textString = "F", fontSize = 30, fontName = "Arial", textStyle = {TextStyle.Bold}), Ellipse(visible = true, origin = {0.097, 70}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Line(visible = true, origin = {0.848, 0}, points = {{-99.152, 0}, {99.152, 0}}, color = {128, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {0.202, 0.791}, rotation = 5.118, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-2.202, -2.202}, {2.202, 2.202}}), Text(visible = true, origin = {1.113, -50.492}, textColor = {0, 0, 128}, extent = {{-141.113, -29.508}, {141.113, 29.508}}, textString = "%name", fontSize = 100, fontName = "Arial", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end StockPortSensor; diff --git a/BusinessSimulation/Sensors/StockPortSensor_Control.mo b/BusinessSimulation/Sensors/StockPortSensor_Control.mo new file mode 100644 index 0000000..326cb27 --- /dev/null +++ b/BusinessSimulation/Sensors/StockPortSensor_Control.mo @@ -0,0 +1,33 @@ +within BusinessSimulation.Sensors; + +model StockPortSensor_Control "Rate of flow information from stock ports" + Interfaces.Connectors.RealOutput netFlow(quantity = "Rate", unit = "1/s") "Current netflow" annotation(Placement(visible = true, transformation(origin = {160, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {0.237, 110}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); + Interfaces.Connectors.StockPort stockPort annotation(Placement(visible = true, transformation(origin = {-148.083, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-100, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.FlowPort flowPort annotation(Placement(visible = true, transformation(origin = {147.868, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {97.643, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Interfaces.Connectors.BooleanInput u_stopOutflow "Boolean signal to prevent outflow from the component" annotation(Placement(visible = true, transformation(origin = {-145, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {49.994, 99.994}, extent = {{-9.994, -9.994}, {9.994, 9.994}}, rotation = -90))); + Interfaces.Connectors.BooleanInput u_stopInflow "Boolean signal to prevent inflow into the component" annotation(Placement(visible = true, transformation(origin = {-145, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Interfaces.Connectors.BooleanOutput stopInflow "Report the signal received at the flow port side" annotation(Placement(visible = true, transformation(origin = {160, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-20, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Interfaces.Connectors.BooleanOutput stopOutflow "Report the signal received at the flow port side" annotation(Placement(visible = true, transformation(origin = {160, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {20, 30}, extent = {{10, -10}, {-10, 10}}, rotation = -540))); +initial equation + // properly initialize discrete vars with fixed = false + pre(stopInflow) = flowPort.stopInflow; + pre(stopOutflow) = flowPort.stopOutflow; + pre(stockPort.stopInflow) = u_stopInflow; + pre(stockPort.stopOutflow) = u_stopOutflow; +equation + netFlow = stockPort.rate; + stockPort.stock = flowPort.stock; + flowPort.rate = -stockPort.rate; + // report signals received at flow port side + stopInflow = flowPort.stopInflow; + stopOutflow = flowPort.stopOutflow; + // boolean signals are set according to the explicitly given inputs + stockPort.stopInflow = u_stopInflow; + stockPort.stopOutflow = u_stopOutflow; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This component is typically used to build submodels where the information regarding the rate of flow needs to be extracted from the outside StockPort
. In this component the Boolean flags stopInflow
and stopOutflow
can be explicitly set using the Boolean input connectors and the input values will override the signals received at the FlowPort
, which will typically be connected to the inside StockPort
which would normally be directly connected to the outside one.
StockPortSensor, FlowPortSensor
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, origin = {0, 33.849}, points = {{0, -33.849}, {0, 33.849}}, color = {128, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {0, 70}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {76, 112, 136}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-20.708, -20.708}, {20.708, 20.708}}), Line(visible = true, origin = {-14.33, 77.5}, rotation = -300, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-8.5, 83.33}, rotation = 30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {0.219, 86.375}, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-2.624, 73.453}, rotation = -300, points = {{2.435, 4.688}, {-2.435, -4.688}}, color = {255, 0, 0}, thickness = 1), Line(visible = true, origin = {13.857, 78.141}, rotation = 660, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {7.922, 84.346}, rotation = -30, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {-16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Line(visible = true, origin = {16, 70}, rotation = -270, points = {{0, 3}, {0, -3}}, color = {255, 255, 255}, thickness = 1), Text(visible = true, origin = {0, 60}, textColor = {255, 255, 255}, extent = {{-12.617, -10}, {12.617, 10}}, textString = "F", fontSize = 30, fontName = "Arial", textStyle = {TextStyle.Bold}), Ellipse(visible = true, origin = {0.097, 70}, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, extent = {{-3, -3}, {3, 3}}), Line(visible = true, origin = {0.848, 0}, points = {{-99.152, 0}, {99.152, 0}}, color = {128, 0, 128}, thickness = 3), Ellipse(visible = true, origin = {0.202, 0.791}, rotation = 5.118, lineColor = {128, 0, 128}, fillColor = {128, 0, 128}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-2.202, -2.202}, {2.202, 2.202}}), Text(visible = true, origin = {1.113, -50.492}, textColor = {0, 0, 128}, extent = {{-141.113, -29.508}, {141.113, 29.508}}, textString = "%name", fontSize = 100, fontName = "Arial", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end StockPortSensor_Control; diff --git a/BusinessSimulation/Sensors/package.mo b/BusinessSimulation/Sensors/package.mo new file mode 100644 index 0000000..95ac29a --- /dev/null +++ b/BusinessSimulation/Sensors/package.mo @@ -0,0 +1,12 @@ +within BusinessSimulation; + +package Sensors "Package with sensor components" + extends Icons.Package; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains sensor components especially needed to access acausal connector information from within a component.
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The Cloud
is a reservoir (stock or level) with an infinite capacty. It is used at a system's border to provide a source for incoming or a sink for outgoing \"matter\".
This information is part of the Business Simulation Library (BSL).
+Decline can be used to model an outflow from a stock into a sink with infinite capacity outside the border of the system in focus. The rate of flow can either be set by the real input u (hasConstantRate = false
) or by the parameter rate
(hasConstantRate = true
).
This information is part of the Business Simulation Library (BSL).
+ExogenousChange can be used to model an inflow to a stock from a source or an outflow from a stock to a sink. In either case it is assumed, that the source or sink has infinite capacity and thus lies outside the border of the system in focus. By convention, a positive rate will fill the connected stock, while a negative rate will drain it. The rate of flow is determined by the real input u.
+This information is part of the Business Simulation Library (BSL).
+ExponentialChange will fill (or drain) the connected stock from a source (or into a sink) with infinite capacity at a rate that is determined at any time as the product of the current amount in the connected stock and the fractional rate given by the real input u. By convention, a positive rate will fill the stock, while a negative rate will drain it.
+isCCR = true
). If this is not case, the rate will be converted using the →ForceOfInterest converter.ExponentialGrowth, ExponentialDecline, ExponentialDecay
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "EXP Change", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-5.081, -78.316}, textColor = {0, 0, 128}, extent = {{-76.882, -12}, {76.882, 12}}, textString = "fractional rate", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {63.558, -10.273}, rotation = -5.306, points = {{32.722, 10.515}, {13.878, -30.192}, {-7.496, -34.124}, {-24.956, -15.69}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Line(visible = true, origin = {-32.154, -19.63}, rotation = 5.306, points = {{27.907, -47.216}, {36.663, -27.43}, {51.602, -8.364}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {39.835, -26.283}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}}), Polygon(visible = true, origin = {19.113, -25.409}, rotation = -30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {-5, -5}, {5, -5}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ExponentialChange; diff --git a/BusinessSimulation/SourcesOrSinks/ExponentialDecay.mo b/BusinessSimulation/SourcesOrSinks/ExponentialDecay.mo new file mode 100644 index 0000000..a56a313 --- /dev/null +++ b/BusinessSimulation/SourcesOrSinks/ExponentialDecay.mo @@ -0,0 +1,40 @@ +within BusinessSimulation.SourcesOrSinks; + +model ExponentialDecay "A stock is drained at a rate proportional to its content" + import BusinessSimulation.Units.Time; + extends Interfaces.Basics.GenericSourceOrSink; + extends Icons.Sink; + Interfaces.Connectors.RealInput u if not hasConstantResidenceTime "Residence time input" annotation(Placement(visible = true, transformation(origin = {-140, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + parameter Boolean hasConstantResidenceTime = false "= true, if the constant residence time is used instead of the real input u" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Time residenceTime(min = 0, unit = "s") = 1 "Constant time of average residence (optional) (decaying.residenceTime)" annotation(Dialog(enable = hasConstantResidenceTime)); +protected + Converters.ConstantConverterTime parResidenceTime(value = residenceTime) if hasConstantResidenceTime "Constant residence time (optional)" annotation(Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.Decay decaying(hasConstantResidenceTime = false, residenceTime = residenceTime) annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 540))); + Cloud drainedMaterial "System boundary - the stock will be assumed to have infinite capacity" annotation(Placement(visible = true, transformation(origin = {-50, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(massPort, decaying.portA) annotation(Line(visible = true, origin = {85, 0}, points = {{75, 0}, {-75, 0}}, color = {128, 0, 128})); + connect(decaying.portB, drainedMaterial.massPort) annotation(Line(visible = true, origin = {-25, 0}, points = {{15, 0}, {-15, 0}}, color = {128, 0, 128})); + connect(u, decaying.u) annotation(Line(visible = true, origin = {-43.333, 43.333}, points = {{-96.667, 16.667}, {48.333, 16.667}, {48.333, -33.333}}, color = {1, 37, 163})); + connect(decaying.y, y1) annotation(Line(visible = true, origin = {50, 50.133}, points = {{-55, -39.733}, {-55, 19.867}, {110, 19.867}}, color = {1, 37, 163})); + connect(decaying.y, y) annotation(Line(visible = true, origin = {50, 23.467}, points = {{-55, -13.067}, {-55, 6.533}, {110, 6.533}}, color = {1, 37, 163})); + connect(decaying.y2, y2) annotation(Line(visible = true, origin = {52.625, -27.5}, points = {{-42.125, 22.5}, {-32.625, 22.5}, {-32.625, -22.5}, {107.375, -22.5}}, color = {1, 37, 163})); + connect(parResidenceTime.y, decaying.u) annotation(Line(visible = true, origin = {-35, 30}, points = {{-80, 10}, {40, 10}, {40, -20}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+ExponentialDecay is identical to →ExponentialDecline, e.g. the connected stock is drained at a rate proportional to its content into a sink with infinite capacity outside the border of the system in focus. Instead of using a fractional rate λ to describe the process, we are using the mean residence time τ (aka mean lifetime or the exponential time constant) to parameterize the process:
+ +The mean residence time can be given either as a constant parameter (residenceTime) or as a continuous time input u.
+The effective rate of decay with respect to a connected stock x at any time will be given by
+ +ExponentialDecline, Decay, ExponentialChange
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "EXP Decay", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -75.728}, textColor = {0, 0, 128}, extent = {{-75.716, -11.684}, {75.716, 11.684}}, textString = "residence time", fontSize = 60, textStyle = {TextStyle.Bold}), Line(visible = true, origin = {63.558, -10.273}, rotation = -5.306, points = {{32.722, 10.515}, {27.406, -27.31}, {3.18, -33.132}, {-12.083, -16.513}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Line(visible = true, origin = {-22.154, -19.63}, rotation = 5.306, points = {{26.276, -45.045}, {36.663, -27.43}, {51.602, -8.364}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {51.134, -25.316}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}}), Polygon(visible = true, origin = {29.113, -25.409}, rotation = -30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {-5, -5}, {5, -5}})})); +end ExponentialDecay; diff --git a/BusinessSimulation/SourcesOrSinks/ExponentialDecline.mo b/BusinessSimulation/SourcesOrSinks/ExponentialDecline.mo new file mode 100644 index 0000000..b49b873 --- /dev/null +++ b/BusinessSimulation/SourcesOrSinks/ExponentialDecline.mo @@ -0,0 +1,41 @@ +within BusinessSimulation.SourcesOrSinks; + +model ExponentialDecline "Exponential decline of connected stock" + import BusinessSimulation.Units.Rate; + extends Interfaces.Basics.GenericSourceOrSink; + extends Icons.Sink; + Interfaces.Connectors.RealInput u if not hasConstantRate "Fractional rate given as exogenous input" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 100}, extent = {{-10, 10}, {10, -10}}, rotation = 270))); + parameter OutputType fractionalRate(min = 0) = 0 "Constant fractional rate to be used if chosen" annotation(Dialog(enable = hasConstantRate)); + parameter Boolean isCCR = true "= true, if the factional rate given is assumed to be a continuously compounding rate else the rate will be converted" annotation(Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantRate = false "= true, if the constant fractional rate is used instead of the real input u" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); +protected + Flows.Unidirectional.ProportionalTransition decreasing annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Cloud cloud "System boundary" annotation(Placement(visible = true, transformation(origin = {-30, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverter parFractionalRate(value = fractionalRate) if hasConstantRate "Constant rate (optional)" annotation(Placement(visible = true, transformation(origin = {-110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.PassThrough indicatedRate if isCCR "Indicated fractional rate" annotation(Placement(visible = true, transformation(origin = {-70, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ForceOfInterest convertedRate if not isCCR "Continuously compounding rate" annotation(Placement(visible = true, transformation(origin = {-70, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + connect(massPort, decreasing.portA) annotation(Line(visible = true, origin = {85, 0}, points = {{75, 0}, {-75, 0}}, color = {128, 0, 128})); + connect(decreasing.portB, cloud.massPort) annotation(Line(visible = true, origin = {-15, 0}, points = {{5, 0}, {-5, 0}}, color = {128, 0, 128})); + connect(parFractionalRate.y, convertedRate.u) annotation(Line(visible = true, origin = {-92.269, 70}, points = {{-14.269, 0}, {14.269, 0}}, color = {1, 37, 163})); + connect(indicatedRate.y, decreasing.u) annotation(Line(visible = true, origin = {-17.546, 36.667}, points = {{-45.092, 13.333}, {22.546, 13.333}, {22.546, -26.667}}, color = {1, 37, 163})); + connect(u, convertedRate.u) annotation(Line(visible = true, origin = {-109.5, 55}, points = {{-35.5, -15}, {14.5, -15}, {14.5, 15}, {31.5, 15}}, color = {1, 37, 163})); + connect(parFractionalRate.y, indicatedRate.u) annotation(Line(visible = true, origin = {-91.135, 60}, points = {{-15.404, 10}, {1.135, 10}, {1.135, -10}, {13.135, -10}}, color = {1, 37, 163})); + connect(u, indicatedRate.u) annotation(Line(visible = true, origin = {-107, 45}, points = {{-38, -5}, {17, -5}, {17, 5}, {29, 5}}, color = {1, 37, 163})); + connect(convertedRate.y, decreasing.u) annotation(Line(visible = true, origin = {-17.546, 50}, points = {{-45.092, 20}, {22.546, 20}, {22.546, -40}}, color = {1, 37, 163})); + connect(decreasing.y2, y) annotation(Line(visible = true, origin = {52.625, 12.5}, points = {{-42.125, -17.5}, {-32.625, -17.5}, {-32.625, 17.5}, {107.375, 17.5}}, color = {1, 37, 163})); + connect(decreasing.y2, y2) annotation(Line(visible = true, origin = {52.625, -27.5}, points = {{-42.125, 22.5}, {-32.625, 22.5}, {-32.625, -22.5}, {107.375, -22.5}}, color = {1, 37, 163})); + connect(decreasing.y2, y1) annotation(Line(visible = true, origin = {52.625, 32.5}, points = {{-42.125, -37.5}, {-32.625, -37.5}, {-32.625, 37.5}, {107.375, 37.5}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+ExponentialDecline will drain the connected stock into a sink with infinite capacity at a rate that is determined at any time as the product of the current amount in the connected stock and the fractional rate given. The rate can either be given as a constant parameter fractionalRate
or as a real input u, making it variable in time.
isCCR = true
). If this is not case, the rate will be converted using the →ForceOfInterest converter.ExponentialGrowth, ExponentialDecay, ExponentialChange
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "EXP Decline", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {63.558, -10.273}, rotation = -5.306, points = {{32.722, 10.515}, {27.406, -27.31}, {3.18, -33.132}, {-12.083, -16.513}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Text(visible = true, origin = {0, -78.316}, textColor = {0, 0, 128}, extent = {{-71.945, -12}, {71.945, 12}}, textString = "fractional rate", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {-22.154, -19.63}, rotation = 5.306, points = {{36.522, -45.771}, {36.663, -27.43}, {51.602, -8.364}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {51.134, -25.316}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}}), Polygon(visible = true, origin = {29.113, -25.409}, rotation = -30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {-5, -5}, {5, -5}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ExponentialDecline; diff --git a/BusinessSimulation/SourcesOrSinks/ExponentialGrowth.mo b/BusinessSimulation/SourcesOrSinks/ExponentialGrowth.mo new file mode 100644 index 0000000..35cd47f --- /dev/null +++ b/BusinessSimulation/SourcesOrSinks/ExponentialGrowth.mo @@ -0,0 +1,47 @@ +within BusinessSimulation.SourcesOrSinks; + +model ExponentialGrowth "Exponential growth of connected stock" + import BusinessSimulation.Units.Rate; + extends Interfaces.Basics.GenericSourceOrSink; + extends Icons.Source; + Interfaces.Connectors.RealInput u if not hasConstantRate "Fractional rate given as exogenous input" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 100}, extent = {{-10, 10}, {10, -10}}, rotation = 270))); + parameter OutputType fractionalRate(min = 0) = 0 "Constant fractional rate to be used if chosen" annotation(Dialog(enable = hasConstantRate)); + parameter Boolean isCCR = true "= true, if the factional rate given is assumed to be a continuously compounding rate else the rate will be converted" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantRate = false "= true, if the constant fractional rate is used instead of the real input u" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); +protected + Cloud cloud "System boundary" annotation(Placement(visible = true, transformation(origin = {-50, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.Transition growing "Inflow to connected stock" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Sensors.FlowPortSensor stockLevel "Report amount in connected stock" annotation(Placement(visible = true, transformation(origin = {90, 10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Product_2 rate "Rate of growth is proportional to level of connected stock" annotation(Placement(visible = true, transformation(origin = {-5, 25}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverter parFractionalRate(value = fractionalRate) if hasConstantRate "Constant rate (optional)" annotation(Placement(visible = true, transformation(origin = {-130, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.PassThrough indicatedFractionalRate if isCCR "Output is equal to input" annotation(Placement(visible = true, transformation(origin = {-50, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ForceOfInterest ccRate if not isCCR "Continuously Compounding Rate" annotation(Placement(visible = true, transformation(origin = {-50, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +equation + // positive rate grows the connected stock + connect(stockLevel.flowPort, massPort) annotation(Line(visible = true, origin = {135, 5}, points = {{-45, 5}, {-45, -5}, {25, -5}}, color = {128, 0, 128})); + connect(growing.portB, massPort) annotation(Line(visible = true, origin = {85, 0}, points = {{-75, 0}, {75, 0}}, color = {128, 0, 128})); + connect(stockLevel.stock, rate.u1) annotation(Line(visible = true, origin = {45.024, 33.5}, points = {{45.024, -12.5}, {45.024, 6.5}, {-45.024, 6.5}, {-45.024, -0.5}}, color = {1, 37, 163})); + connect(rate.y, growing.u) annotation(Line(visible = true, origin = {-5, 13.819}, points = {{0, 3.819}, {0, -3.819}}, color = {1, 37, 163})); + connect(cloud.massPort, growing.portA) annotation(Line(visible = true, origin = {-25, 0}, points = {{-15, 0}, {15, 0}}, color = {128, 0, 128})); + connect(growing.y, y1) annotation(Line(visible = true, origin = {56.667, 50.133}, points = {{-51.667, -39.733}, {-51.667, 19.867}, {103.333, 19.867}}, color = {1, 37, 163})); + connect(growing.y, y) annotation(Line(visible = true, origin = {56.667, 23.467}, points = {{-51.667, -13.067}, {-51.667, 6.533}, {103.333, 6.533}}, color = {1, 37, 163})); + connect(growing.y1, y2) annotation(Line(visible = true, origin = {52.625, -27.5}, points = {{-42.125, 22.5}, {-32.625, 22.5}, {-32.625, -22.5}, {107.375, -22.5}}, color = {1, 37, 163})); + connect(parFractionalRate.y, indicatedFractionalRate.u) annotation(Line(visible = true, origin = {-92.269, 70}, points = {{-34.269, 0}, {34.269, 0}}, color = {1, 37, 163})); + connect(indicatedFractionalRate.y, rate.u2) annotation(Line(visible = true, origin = {-20.879, 57.667}, points = {{-21.758, 12.333}, {10.879, 12.333}, {10.879, -24.667}}, color = {1, 37, 163})); + connect(parFractionalRate.y, ccRate.u) annotation(Line(visible = true, origin = {-103.25, 60}, points = {{-21.75, 10}, {-11.75, 10}, {-11.75, -10}, {45.25, -10}}, color = {1, 37, 163})); + connect(ccRate.y, rate.u2) annotation(Line(visible = true, origin = {-20.667, 44.333}, points = {{-21.333, 5.667}, {10.667, 5.667}, {10.667, -11.333}}, color = {1, 37, 163})); + connect(u, ccRate.u) annotation(Line(visible = true, origin = {-107, 45}, points = {{-38, -5}, {7, -5}, {7, 5}, {49, 5}}, color = {1, 37, 163})); + connect(u, indicatedFractionalRate.u) annotation(Line(visible = true, origin = {-97.43, 55}, points = {{-47.57, -15}, {-2.57, -15}, {-2.57, 15}, {39.43, 15}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+ExponentialGrowth will fill the connected stock from a source with infinite capacity at a rate that is determined at any time as the product of the current amount in the connected stock and the fractional rate given. The rate can either be given as a constant parameter fractionalRate
or as a real input u, making it variable in time.
isCCR = true
). If this is not case, the rate will be converted using the →ForceOfInterest converter.ExponentialDecline, Decay, ExponentialChange
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "EXP Growth", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {63.558, -10.273}, rotation = -5.306, points = {{32.722, 10.515}, {13.878, -30.192}, {-15.693, -37.076}, {-32.22, -15.961}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Line(visible = true, origin = {-42.154, -19.63}, rotation = 5.306, points = {{36.522, -45.771}, {36.663, -27.43}, {51.602, -8.364}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Text(visible = true, origin = {6.087, -78}, textColor = {0, 0, 128}, extent = {{-81.281, -12}, {81.281, 12}}, textString = "fractional rate", fontName = "Lato", textStyle = {TextStyle.Bold}), Polygon(visible = true, origin = {31.134, -25.316}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}}), Polygon(visible = true, origin = {9.113, -25.409}, rotation = -30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {-5, -5}, {5, -5}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end ExponentialGrowth; diff --git a/BusinessSimulation/SourcesOrSinks/Growth.mo b/BusinessSimulation/SourcesOrSinks/Growth.mo new file mode 100644 index 0000000..adad9e9 --- /dev/null +++ b/BusinessSimulation/SourcesOrSinks/Growth.mo @@ -0,0 +1,33 @@ +within BusinessSimulation.SourcesOrSinks; + +model Growth "A stock is filled at a given rate" + import BusinessSimulation.Units.Rate; + extends Interfaces.Basics.GenericSourceOrSink; + extends Icons.Source; + Interfaces.Connectors.RealInput u if not hasConstantRate "Rate of growth given as exogenous input" annotation(Placement(visible = true, transformation(origin = {-140, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 100}, extent = {{-10, 10}, {10, -10}}, rotation = 270))); + parameter OutputType rate = 0 "Constant rate of growth (optional)" annotation(Dialog(enable = hasConstantRate)); + parameter Boolean hasConstantRate = false "= true, if the constant rate is used instead of an exogenous input u" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); +protected + Converters.ConstantConverter parConstantRate(value = rate) if hasConstantRate "Constante rate of growth (optional)" annotation(Placement(visible = true, transformation(origin = {-110, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Flows.Unidirectional.Transition growing(hasConstantRate = false) annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Cloud cloud annotation(Placement(visible = true, transformation(origin = {-50, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); +equation + connect(cloud.massPort, growing.portA) annotation(Line(visible = true, origin = {-25, 0}, points = {{-15, 0}, {15, 0}}, color = {128, 0, 128})); + connect(growing.portB, massPort) annotation(Line(visible = true, origin = {79.167, 0}, points = {{-69.167, 0}, {69.167, 0}}, color = {128, 0, 128})); + connect(growing.y, y1) annotation(Line(visible = true, origin = {56.667, 50.133}, points = {{-51.667, -39.733}, {-51.667, 19.867}, {103.333, 19.867}}, color = {0, 0, 127})); + connect(growing.y, y) annotation(Line(visible = true, origin = {56.667, 23.467}, points = {{-51.667, -13.067}, {-51.667, 6.533}, {103.333, 6.533}}, color = {0, 0, 127})); + connect(growing.y1, y2) annotation(Line(visible = true, origin = {-10.763, -28.5}, points = {{21.263, 23.5}, {30.763, 23.5}, {30.763, -21.5}, {170.763, -21.5}}, color = {0, 0, 127})); + connect(parConstantRate.y, growing.u) annotation(Line(visible = true, origin = {-38.333, 50}, points = {{-66.667, 20}, {33.333, 20}, {33.333, -40}}, color = {1, 37, 163})); + connect(u, growing.u) annotation(Line(visible = true, origin = {-50, 30}, points = {{-90, 10}, {45, 10}, {45, -20}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+Growth can be used to model an inflow to a stock from a source with infinite capacity outside the border of the system in focus. The rate of flow can either be set by the real input u (hasConstantRate = false
) or by the parameter rate
(hasConstantRate = true
).
This information is part of the Business Simulation Library (BSL).
+LogisticGrowth describes the growth of some population that is limited by the availability of some finite resource. While the population starts to grow exponentially at first at a given fractional rate of growth (either given by the constant parameter r
or by the time-variant input u[1]
), its growth rate will continously diminish until the population reaches its sustainable level (either given by the constant parameter K
or the time-variant input u[2]
), which is called the carrying capacity.
The rate of inflow to a connected stock is given by the so called Verhulst equation:
+ +The diagram below shows the s-shaped growth for a population x for different rates of growth:
++ |
isCCR = true
). If this is not case, the rate will be converted using the →ForceOfInterest converter.K < x
the inflow to the stock can become negative. This is allowed and the modeler has to take care that the input or parameter values make sense for the process being modeled.The logistic growth equation is originally due to the Belgian mathematican Pierre-François Verhulst (1804 - 1849).
+"), __Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 75}, textColor = {0, 128, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Logistic Growth", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {60, -80}, textColor = {0, 0, 128}, extent = {{-16.681, -12}, {16.681, 12}}, textString = "K", fontName = "Lato", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {-40, -68.863}, textColor = {0, 0, 128}, extent = {{-5.153, -12}, {5.153, 12}}, textString = "r", fontName = "Lato", textStyle = {TextStyle.Bold}), Line(visible = true, origin = {63.558, -10.273}, rotation = -5.306, points = {{32.722, 10.515}, {13.878, -30.192}, {-15.693, -37.076}, {-32.22, -15.961}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Line(visible = true, origin = {-42.154, -19.63}, rotation = 5.306, points = {{9.831, -44.191}, {31.025, -33.382}, {47.07, -12.788}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {31.134, -25.316}, rotation = 30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {5, -5}, {-5, -5}}), Polygon(visible = true, origin = {5.5, -27.794}, rotation = -30, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {-5, -5}, {5, -5}}), Line(visible = true, origin = {-31.891, -23.609}, points = {{77.861, -51.711}, {56.151, -35.748}, {51.602, -8.364}}, color = {0, 0, 128}, thickness = 2.5, arrowSize = 0, smooth = Smooth.Bezier), Polygon(visible = true, origin = {20, -29}, lineColor = {0, 0, 128}, fillColor = {0, 0, 128}, fillPattern = FillPattern.Solid, points = {{0, 9}, {-5, -5}, {5, -5}})})); +end LogisticGrowth; diff --git a/BusinessSimulation/SourcesOrSinks/package.mo b/BusinessSimulation/SourcesOrSinks/package.mo new file mode 100644 index 0000000..d43225b --- /dev/null +++ b/BusinessSimulation/SourcesOrSinks/package.mo @@ -0,0 +1,38 @@ +within BusinessSimulation; + +package SourcesOrSinks "Flows into or out of a stock with infinite capacity at a system's boundary" + extends Icons.Package; + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {72.114, -0.25}, rotation = -450, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-22.295, -7.943}, {22.191, -7.943}, {0.104, 15.886}}), Line(visible = true, origin = {27.342, -10}, points = {{-39.852, 0}, {39.852, 0}}, color = {255, 255, 255}, thickness = 5), Line(visible = true, origin = {28.79, 11.777}, points = {{-41.21, 0}, {41.21, 0}}, color = {255, 255, 255}, thickness = 5), Rectangle(visible = true, origin = {-51.38, -0.345}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-38.62, -38.62}, {38.62, 38.62}}), Ellipse(visible = true, origin = {28.899, 0}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 5, extent = {{-15.107, -15.107}, {15.107, 15.107}}), Line(visible = true, origin = {-54.639, -1.132}, points = {{-19.013, -1.251}, {-19.013, 5.61}, {-13.146, 10.097}, {-4.518, 6.3}, {3.107, -1.637}, {9.976, -6.855}, {16.533, -6.855}, {19.639, -3.018}, {19.639, 4.92}, {13.107, 11.132}, {6.525, 8.716}, {3.107, 3.145}, {-4.173, -6.855}, {-14.872, -8.539}, {-19.013, -1.251}, {-19.013, -1.251}}, color = {76, 112, 136}, thickness = 4, smooth = Smooth.Bezier), Bitmap(visible = true, origin = {149.207, -5.816}, fileName = "", imageSource = "iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAACXBIWXMAAAsTAAALEwEAmpwYAAAABGdBTUEAALGeYUxB9wAAACBjSFJNAAB6JQAAgIMAAPn/AACA6AAAUggAARVYAAA6lwAAF2/XWh+QAAAB7klEQVR42mJsufTiPwMZACCAWP5//4Fd4tcnBsndRQzyn/aA+Q/5XBieu/Yx/GHjA/MBAojl3zfsGmWOlDHo/N7DoKEA4Qu83MPAfKCM4Z7NBDAfIIBY/uKwUebtDrAmDlYIX0OcgeHDgx0Mt6HqAQKI5Q8OjbgATD1AALH8xuHUJ8IeDDde7gDbBAI3XkLEYOoBAojlF5Dx69dvhrev34MFePm4GXh4uRkuCqcw/P39B+g8ROBcAYrBNAIEEMuXT18Y3rx6z2Ctp8hgoCbNMHfTcYY/QIM4uTgYTgjlgDEc/AIREI0AAcTy+uU7BjtDZYZkP0uGn7/+MOSFOzBMXHGA4dfP3wzs7KwM////Z/j06SvDnz9/wRp4eLjA4gABxGRvpMKQEWjN8PfvPzCWEOJjSAPyQbZ+/vyN4cOHLwwC3BwMsV5mDN7W2gw/f/wEiwMEEOOPn7///wDa9PP3bwYwDcQg+tGLdwwLt55kYGVlYQhxNADb9gNo2Kt3nxkOXbjLABBATH/+AW0C4j9QG2G0iAAPQ5iLETDg/jDce/oGIg5Ux83FzmCqJccAEEBMCMX/Ic5FMkiIj4vBz06X4fiVBwwPnr+Fe4eLnY0BIIBYYDaAFf/7B5f8CzVMgJeTwcdGG+yFPyDDoeoAAgwAAiQQgeLRB5kAAAAASUVORK5CYII=", extent = {{-0.793, -0.07}, {0.793, 0.07}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This pacakge contains sources or sinks with regard to the flow of conserved matter or information (\"mass flows\"). While in the narrow sense only a cloud (i.e. a stock with infinite capacity) is a source or sink, in this library we will extend the definition of a source or sink to also pertain to inflows from or outflows into a stock with infinite capacity, e.g. the cloud will be integrated into a flow element with a single flow port.
+The direction of flow will not always be clear for SourcesOrSinks elements. For a constant or an exogenous input given the rate of flow these sign conventions are to be observed:
+Element | +Behavior for positive rate | +
---|---|
Sink | +DRAIN connected stock | +
Source | +FILL connected stock | +
SourceOrSink | +FILL connected stock | +
+Tutorial.ElementaryBuildingBlocks +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This is a restricted reservoir of the System Dynamics methodology, which accumulates material (i.e. countable entities, some kind of mass) transported by flow components connected to the component's StockPorts. Like a MaterialStock the CapacityRestrictedStock can never become negative—we are not collecting \"antimatter\"—and will prevent connected flow components from draining its value below zero. Unlike other stocks, minCapacity
and maxCapacity
are seen as capacity restrictions that for \"physical\" reasons cannot be violated—the restrictions can be given as either constant parameters (minValue, maxValue
) or as variable inputs (u_min, u_max
). Accordingly, the component will signal flow restrictions via its port that must be observed by connected flow components.
The value of the stock will be set to zero if the calculated value x
is less than a very small positive amount and if reinitializeStock = true
is chosen in the Advanced tab:
if reinitializeStock then + when x < 0 then + reinit(x, 0); + end when; + end if;+
CapacityRestrictedStock components will prevent connected flows from draining the stock via their →StockPort connectors' Boolean flags, should the calculated state variable x
be less than a very small positive amount:
inflow.stopInflow = not x < maxCapacity - BusinessSimulation.Constants.small; + outflow.stopInflow = inflow.stopInflow;
inflow.stopOutflow = not x > minCapacity + BusinessSimulation.Constants.small; + outflow.stopOutflow = inflow.stopOutflow;
inflow
and outflow
→StockPorts are only indicative; in general the reservoir may be filled or drained by flows connected to either port.assert
using useAssert = true
in the Advanced tab. The switch causeError
controls whether an error or a warning is to be raised.init
allows to select →InitializationOptions:initialValue
to determine the initial value.der(x) = 0
in order to find an initial value that establishes equilibrium. initialValue
-- in this case used as a start value for numerical iteration -- should be set to a value different from zero.)MaterialStock, InformationLevel
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-80.87, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {-70.87, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {70.439, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {80.439, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end CapacityRestrictedStock; diff --git a/BusinessSimulation/Stocks/Conveyor.mo b/BusinessSimulation/Stocks/Conveyor.mo new file mode 100644 index 0000000..19d9a4a --- /dev/null +++ b/BusinessSimulation/Stocks/Conveyor.mo @@ -0,0 +1,150 @@ +within BusinessSimulation.Stocks; + +model Conveyor "Conveyor delay (aka pipeline ~) with variable delay time" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.{Rate,Time}; + import BusinessSimulation.Constants.small; + extends Icons.Conveyor; + extends Icons.DiscreteStockLabel; + extends Interfaces.Basics.GenericStock_Special(hasStockInfoOutput = false, init = modelSettings.init); + Interfaces.Connectors.RealInput u(quantity = "Time") if not hasConstantDelayTime "Delay time input (optional)" annotation(Placement(visible = true, transformation(origin = {-145, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 100}, extent = {{-10, 10}, {10, -10}}, rotation = 270))); + parameter OutputType initialValue(min = 0) = 0 "Initial load"; + parameter Time delayTime(min = 0, max = maxDelayTime) "Constant delay time (optional)" annotation(Dialog(enable = hasConstantDelayTime)); + parameter Time maxDelayTime(min = 0) = 10 "Maximum delay time (to restrict memory usage)" annotation(Evaluate = true); + parameter Time samplingPeriod(min = small, max = modelSettings.dt) = modelSettings.samplingPeriod "Sampling period for discrete behavior (should be smaller than dt/2)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + parameter Boolean hasConstantDelayTime = true "= true, if the delay time is to be given by a constant parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasExogenousHistory = false "=true, if the outflow-profile for the initial load is to be given by an external lookup function" annotation(Evaluate = true, Dialog(enable = false, group = "Structural Parameters")); + parameter Boolean strict = true "= true, if strict limits with noEvent(..) (clippedDelayTime.strict)" annotation(Evaluate = true, Dialog(tab = "Advanced")); + outer ModelSettings modelSettings; +protected + parameter Integer n = integer(ceil(maxDelayTime / samplingPeriod)) "Array dimensions for storing the loaded material" annotation(Evaluate = true, Dialog(tab = "Initialization", enable = false)); + // discrete vars + discrete Rate[n] conveyor "Storage boxes for the incoming rates"; + discrete OutputType load(start = initialValue) "Sum of material in the conveyor" annotation(Dialog(enable = false, tab = "Initialization")); + discrete Rate carry "Material that is leaving the conveyor prematurely due to decreases in delay time"; + discrete Time actDelayTime "Actual delay time"; + discrete Rate currentInflowRate "Rate of flow at current time"; + discrete Rate rateToStore "Average rate to store in the conveyor"; + discrete Rate outflowRate "Rate of outflow from the conveyor"; + discrete Integer i_start "Index of the first box corresponding to the actual delay time"; + discrete Integer shiftIndex "Positive or negative index difference due to changes in delay time"; + // components + Converters.ConstantConverterTime parDelayTime(value = delayTime) if hasConstantDelayTime "Constant delay time" annotation(Placement(visible = true, transformation(origin = {-120, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.Clip clippedDelayTime(minValue = modelSettings.dt, maxValue = maxDelayTime, strict = strict) "Valid delay time to use" annotation(Placement(visible = true, transformation(origin = {-80, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Sensors.DynamicStockInfo dynamicStockInfo if hasStockInfoOutput "Report infos for StockInfoPort" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +initial equation + // properly initialize discrete vars with fixed = false + pre(inflow.stopInflow) = false; + pre(inflow.stopOutflow) = true; +initial algorithm + // initialize the conveyor + conveyor := zeros(n); + currentInflowRate := inflow.rate; + actDelayTime := clippedDelayTime.y; + // determine the initial load + if init == InitializationOptions.FixedValue then + load := initialValue; + elseif init == InitializationOptions.SteadyState then + // use Little's Law + load := actDelayTime * currentInflowRate; + end if; + // calculate the start index for storing the initial rates (may be larger than n, if delay time is zero) + i_start := n - integer(ceil(actDelayTime / samplingPeriod)) + 1; + rateToStore := if actDelayTime > 0 then load / (n - i_start + 1) / samplingPeriod else load / samplingPeriod; + // as in the PureDelay the last package goes out immediately so one box less needed for storing + for i in i_start + 1:n loop + if not hasExogenousHistory then + // constant value + conveyor[i] := rateToStore; + else + /* + use initial load profile in future versions + conveyor[i] := initialLoad.y[i] / samplingPeriod; + */ + conveyor[i] := rateToStore; + end if; + end for; + // if the delay time is zero then the currentInflowRate should be added to the outflowRate + outflowRate := rateToStore; + if i_start > n then + outflowRate := outflowRate + currentInflowRate; + else + // store inflowRate + conveyor[i_start] := currentInflowRate; + end if; + shiftIndex := 0; + carry := 0; +algorithm + // series of events starting at modelStartTime + samplingPeriod then every samplingPeriod + when sample(modelSettings.modelStartTime + samplingPeriod, samplingPeriod) then + // get current values + actDelayTime := clippedDelayTime.y; + currentInflowRate := inflow.rate; + // set rateToStore in order to have equations balance out + rateToStore := 0; + // check for a change in delay time + i_start := n - integer(ceil(actDelayTime / samplingPeriod)) + 1; + shiftIndex := i_start - pre(i_start); + // shift conveyor +1 for sampling time having passed and and additional +shiftIndex for chane of delay time + (conveyor, carry) := Functions.shiftList(conveyor, shiftIndex + 1); + outflowRate := carry; + // load must count current outflow rate + load := (sum(conveyor) + outflowRate) * samplingPeriod; + // put inflowRate on the conveyor belt + if i_start > n then + outflowRate := outflowRate + currentInflowRate; + else + conveyor[i_start] := conveyor[i_start] + currentInflowRate; + // conveyor[i_start] should be zero + end if; + end when; +equation + // textual equations + inflow.stopInflow = false; + inflow.stopOutflow = true; + inflow.stock = load; + outflow.data = outflowRate; + // report current load + y = inflow.stock; + y1 = inflow.stock; + y2 = inflow.stock; + // connect equations + connect(u, clippedDelayTime.u) annotation(Line(visible = true, origin = {-116.5, 60}, points = {{-28.5, 0}, {28.5, 0}}, color = {1, 37, 163})); + connect(parDelayTime.y, clippedDelayTime.u) annotation(Line(visible = true, origin = {-100.75, 50}, points = {{-13.25, -10}, {0.75, -10}, {0.75, 10}, {12.75, 10}}, color = {1, 37, 163})); + connect(inflow, dynamicStockInfo.inPort) annotation(Line(visible = true, origin = {-83, 0}, points = {{-77, 0}, {77, 0}}, color = {128, 0, 128})); + connect(dynamicStockInfo.outPort, outflow) annotation(Line(visible = true, origin = {83, 0}, points = {{-77, 0}, {77, 0}}, color = {128, 0, 128})); + connect(dynamicStockInfo.y_stockInfo, y_stockInfo) annotation(Line(visible = true, origin = {64, -24.8}, points = {{-64, 30.8}, {-64, 39.8}, {16, 39.8}, {16, -55.2}, {86, -55.2}}, color = {128, 0, 128})); + connect(y2, dynamicStockInfo.levelInfo) annotation(Line(visible = true, origin = {80, -37.772}, points = {{80, -12.228}, {80, -12.228}, {-80, -12.228}, {-80, 31.772}}, color = {1, 37, 163})); + connect(clippedDelayTime.y, dynamicStockInfo.residenceTimeInfo) annotation(Line(visible = true, origin = {-28.4, 14.8}, points = {{-43.6, 45.2}, {-11.6, 45.2}, {-11.6, -34.8}, {33.4, -34.8}, {33.4, -20.8}}, color = {1, 37, 163})); + // assert equations + assert(samplingPeriod < modelSettings.dt, "Sampling period should be significantly smaller than dt", level = AssertionLevel.warning); + assert(samplingPeriod > small, "Sampling period must be greater than zero", level = AssertionLevel.error); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Conveyor (aka pipeline delay) bevhaves as one would expect a conveyor belt to work: What flows into the Conveyor will flow out after a period given by delayTime
or the variable input u
has passed. The order of outflow will preserve the order of inflow, i.e. when the delay time increases or decreases during the simulation, then it will affect everything that is currently \"loaded\" on the conveyor in the same way. Therefore, material might come out at the same time as material that had entered before, but it can never overtake older entries (this would be possible in a PureDelay).
The Conveyor will work at discrete time intervals:
+when sample(modelSettings.modelStartTime + samplingPeriod, samplingPeriod) then + // load new material onto conveyor, move loaded material, unload material +end when; ++
The values for the in- and outflows and the load will be kept constant between events.
+inflow
port of the Conveyor.OutflowDynamicStock
or →SplitOutflowDynamicStock
have to be connected to the outflow
port.SplitOutflowDynamicStock
) can be used to model leaking.init
in the Advanced tab allows to select →InitializationOptions:
+initialValue
.inflow.rate * delayTime
startValue
.SimpleConveyor, PureDelay, DelayFixed, DelayInformation
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -80}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%initialValue", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 140}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end Conveyor; diff --git a/BusinessSimulation/Stocks/DelayN.mo b/BusinessSimulation/Stocks/DelayN.mo new file mode 100644 index 0000000..954999f --- /dev/null +++ b/BusinessSimulation/Stocks/DelayN.mo @@ -0,0 +1,85 @@ +within BusinessSimulation.Stocks; + +model DelayN "Material delay of n-th Order" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.Time; + extends Icons.DelayN; + extends Interfaces.Basics.GenericStock_Special(hasStockInfoOutput = false, init = modelSettings.init); + Interfaces.Connectors.RealInput u(quantity = "Time", unit = "s") if not hasConstantDelayTime "Delay time input (optional)" annotation(Placement(visible = true, transformation(origin = {-145, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-50, 100}, extent = {{10, 10}, {-10, -10}}, rotation = -270))); + parameter Integer n(min = 1) = 3 "Order of the exponential delay" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter OutputType initialValue(min = 0) = 0 "Initial stock"; + parameter Time delayTime(min = BusinessSimulation.Constants.small) = 1 "Constant time of delay (optional)" annotation(Dialog(enable = hasConstantDelayTime)); + parameter Boolean hasConstantDelayTime = true "= true, if DelayTime is to be set by a constant parameter" annotation(Dialog(group = "Structural Parameters")); + outer ModelSettings modelSettings; +protected + OutputType x(min = 0) "Total material in the stock"; + OutputType[n] x_hidden(each start = initialValue / n) "Hidden (internal) stocks" annotation(Dialog(enable = false, tab = "Initialization")); + Time stageDelayTime "Delay-time for the transition from internal stock_i to internal stock_i+1"; + Sensors.DynamicStockInfo dynamicStockInfo if hasStockInfoOutput "Generate information for StockInfoOutput" annotation(Placement(visible = true, transformation(origin = {-0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime parDelayTime(value = delayTime) if hasConstantDelayTime "Constant delay time (optional)" annotation(Placement(visible = true, transformation(origin = {-110, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ClipProcessTime actualDelayTime "Delay time" annotation(Placement(visible = true, transformation(origin = {-68.47, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); +initial equation + // set up in steady state or use fixed value + if init == InitializationOptions.FixedValue then + x_hidden[1:n] = array(initialValue / n for i in 1:n); + elseif init == InitializationOptions.SteadyState then + // make use of Little's Law + x_hidden[1:n] = array(inflow.rate * (actualDelayTime.y / n) for i in 1:n); + end if; + // properly initialize discrete vars with fixed = false + // inflow to stock is restricted to inflow port; no draining allowed + pre(inflow.stopInflow) = false; + pre(inflow.stopOutflow) = true; +equation + stageDelayTime = actualDelayTime.y / n; + // equations for the n hidden 'in-transit' stocks + der(x_hidden[1]) = inflow.rate - x_hidden[1] / stageDelayTime; + for i in 2:n loop + der(x_hidden[i]) = (x_hidden[i - 1] - x_hidden[i]) / stageDelayTime; + end for; + // total material in transit + x = sum(x_hidden); + // DelayN will signal outflow rate at its outflow-side via SpecialFlowPort + outflow.data = x_hidden[end] / stageDelayTime; + // set the inflow.stock value + inflow.stock = x; + // inflow to stock is restricted to inflow port; no draining allowed + inflow.stopInflow = false; + inflow.stopOutflow = true; + // report current value of stock via output connectors + y = inflow.stock; + y1 = inflow.stock; + y2 = inflow.stock; + // connect equations for StockInformationPort (conditional) + connect(inflow, dynamicStockInfo.inPort) annotation(Line(visible = true, origin = {-83, 0}, points = {{-77, 0}, {77, 0}}, color = {128, 0, 128})); + connect(dynamicStockInfo.outPort, outflow) annotation(Line(visible = true, origin = {83, 0}, points = {{-77, 0}, {77, 0}}, color = {128, 0, 128})); + connect(y2, dynamicStockInfo.levelInfo) annotation(Line(visible = true, origin = {53.333, -35.333}, points = {{106.667, -14.667}, {-53.333, -14.667}, {-53.333, 29.333}}, color = {1, 37, 163})); + connect(parDelayTime.y, actualDelayTime.u) annotation(Line(visible = true, origin = {-92.618, 35}, points = {{-11.382, -5}, {-2.382, -5}, {-2.382, 5}, {16.148, 5}}, color = {1, 37, 163})); + connect(actualDelayTime.y, dynamicStockInfo.residenceTimeInfo) annotation(Line(visible = true, origin = {-21.118, 6.8}, points = {{-39.99, 33.2}, {-6.123, 33.2}, {-6.123, -26.8}, {26.118, -26.8}, {26.118, -12.8}}, color = {1, 37, 163})); + connect(dynamicStockInfo.y_stockInfo, y_stockInfo) annotation(Line(visible = true, origin = {56, -24.8}, points = {{-56, 30.8}, {-56, 39.8}, {4, 39.8}, {4, -55.2}, {94, -55.2}}, color = {128, 0, 128})); + connect(u, actualDelayTime.u) annotation(Line(visible = true, origin = {-110.735, 40}, points = {{-34.265, 0}, {34.265, 0}}, color = {1, 37, 163})); + // assert + assert(n > 0, "Order of the delay must be at least 1"); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The DelayN is a →MaterialStock with inherent dynamic behavior that will result in a delay—which may have a constant (delayTime
) or a variable delay time (u
). Internally a material delay of order n
is made up of a sequence of n
first-order delays (→Decay ) each having a delay time of delayTime/n
.
To better grasp the behavior of a DelayN, it helps to be aware of the fact, that given a single pulse input (e.g. a Dirac delta function) as inflow to a DelayN with constant delay time, its outflow will correspond to an Exponential distribution for n = 1
and more generally to an Erlang distribution of order k = n for n ≥ 1
. In other words, the time of residence within the stock is distributed according to an Erlang distribution with the mean residence time corresponding to the delay time and a diminishing variance as n
increases—in the limit, as n
approaches infinity, the DelayN will be equivalent to the →PureDelay (aka pipeline delay). For more detail, see Sterman [3, Chapter 11].
inflow
stock port.init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial value for all n hidden states as initialValue/n
.inflow.rate * delayTime / n
startValue
.MaterialStock, PureDelay, Converters.DiscreteDelay
+"), __Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {62.999, 75}, textColor = {255, 0, 0}, extent = {{-24.503, -12}, {24.503, 12}}, textString = "%n", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -80}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%initialValue", fontName = "Lato"), Text(visible = true, origin = {0, 75}, textColor = {255, 0, 0}, extent = {{-50, -12}, {50, 12}}, textString = "Delay", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end DelayN; diff --git a/BusinessSimulation/Stocks/HinesCoflow.mo b/BusinessSimulation/Stocks/HinesCoflow.mo new file mode 100644 index 0000000..75890fc --- /dev/null +++ b/BusinessSimulation/Stocks/HinesCoflow.mo @@ -0,0 +1,48 @@ +within BusinessSimulation.Stocks; + +model HinesCoflow "Accounting for changes in average quality of a stock as new entries with different characteristic flow in" + extends Interfaces.Basics.GenericStock(hasStockInfoOutput = false, y.start = initialValue); + extends Icons.Stock; + extends Icons.FlowIndicators; + Interfaces.Connectors.StockInfoInput u_stockInfo "Stock information input port" annotation(Placement(visible = true, transformation(origin = {-145, 90}, extent = {{-10, -10}, {10, 10}}, rotation = -360), iconTransformation(origin = {0, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Interfaces.Connectors.RealInput u "Characteristic of new elements flowing into the stock of fundamental quality" annotation(Placement(visible = true, transformation(origin = {-145, 45}, extent = {{10, -10}, {-10, 10}}, rotation = -540), iconTransformation(origin = {-50, 100}, extent = {{-10, 10}, {10, -10}}, rotation = -90))); + parameter OutputType initialValue = 0 "Initial value for average characteristic"; +protected + InformationLevel avgCharacteristic(redeclare final type OutputType = OutputType, initialValue = initialValue) "Average characteristic" annotation(Placement(visible = true, transformation(origin = {50, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + SourcesOrSinks.ExogenousChange changing "Change in the average characteristic" annotation(Placement(visible = true, transformation(origin = {10, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + MoleculesOfStructure.Policy.CloseGap rateOfChange(hasConstantAdjTime = false) "Rate of change is given as a first-order smooth" annotation(Placement(visible = true, transformation(origin = {-10, 45}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + MoleculesOfStructure.InformationProcessing.ResidenceTime dilutionTime(durationAtZeroRate = 0) "Time to dilute the average characteristic" annotation(Placement(visible = true, transformation(origin = {-50, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Sensors.AbsoluteSensor absoluteSensor annotation(Placement(visible = true, transformation(origin = {-110, 37.865}, extent = {{10, -10}, {-10, 10}}, rotation = 180))); +equation + connect(avgCharacteristic.y, y) annotation(Line(visible = true, origin = {90, 23.467}, points = {{-35, -13.067}, {-35, 6.533}, {70, 6.533}}, color = {0, 0, 127})); + connect(avgCharacteristic.y, y1) annotation(Line(visible = true, origin = {90, 50.133}, points = {{-35, -39.733}, {-35, 19.867}, {70, 19.867}}, color = {0, 0, 127})); + connect(avgCharacteristic.y1, y2) annotation(Line(visible = true, origin = {69.237, -28.5}, points = {{-8.737, 23.5}, {30.763, 23.5}, {30.763, -21.5}, {90.763, -21.5}}, color = {0, 0, 127})); + connect(outflow, avgCharacteristic.outflow) annotation(Line(visible = true, origin = {104.232, 0}, points = {{44.232, 0}, {-44.232, 0}}, color = {128, 0, 128})); + connect(inflow, avgCharacteristic.inflow) annotation(Line(visible = true, origin = {-50, -8.333}, points = {{-98.205, 8.333}, {-70, 8.333}, {80, 8.333}, {90, 8.333}}, color = {128, 0, 128})); + connect(changing.massPort, avgCharacteristic.inflow) annotation(Line(visible = true, origin = {34.275, 10}, points = {{-14.275, 10}, {-1.625, 10}, {-1.625, -10}, {5.725, -10}}, color = {128, 0, 128})); + connect(u_stockInfo, absoluteSensor.u_stockInfo) annotation(Line(visible = true, origin = {-60, 88.5}, points = {{-85, 1.5}, {-85, 1.5}, {-50, 1.5}, {-50, -46.635}}, color = {128, 0, 128})); + connect(absoluteSensor.stock, dilutionTime.u_level) annotation(Line(visible = true, origin = {-96.961, 27.955}, points = {{-17.991, 5.91}, {-17.991, -2.955}, {35.981, -2.955}}, color = {1, 37, 163})); + connect(u_stockInfo, y_stockInfo) annotation(Line(visible = true, origin = {64, 21}, points = {{-209, 69}, {16, 69}, {16, -101}, {86, -101}}, color = {128, 0, 128})); + connect(dilutionTime.y, rateOfChange.u_adjTime) annotation(Line(visible = true, origin = {-28.38, 37.884}, points = {{-10.362, -17.884}, {-1.62, -17.884}, {-1.62, 2.116}, {7.38, 2.116}}, color = {0, 0, 127})); + connect(rateOfChange.y, changing.u) annotation(Line(visible = true, origin = {3.667, 40}, points = {{-2.667, 5}, {1.333, 5}, {1.333, -10}}, color = {1, 37, 163})); + connect(u, rateOfChange.u_reference) annotation(Line(visible = true, origin = {-59, 52.5}, points = {{-86, -7.5}, {24, -7.5}, {24, -7.5}, {38, -7.5}}, color = {0, 0, 128})); + connect(avgCharacteristic.y, rateOfChange.u_current) annotation(Line(visible = true, origin = {22.5, 49.1}, points = {{32.5, -38.7}, {32.5, 15.9}, {-32.5, 15.9}, {-32.5, 6.9}}, color = {1, 37, 163})); + connect(absoluteSensor.inFlow, dilutionTime.u_rate) annotation(Line(visible = true, origin = {-107.342, 24.433}, points = {{-12.658, 9.432}, {-12.658, -9.433}, {46.319, -9.433}}, color = {1, 37, 163})); + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The HinesCoflow is a modification of the classical coflow structure used in System Dynamics [6, pp. 50f.]. The traditional coflow is a model of a stock's average quality (e.g. age, weight, price, income etc.) changing, as new entities with different characteristics u
flow in while older entities flow out—in which case we assume, that the outflowing entities have an average quality [3, pp. 497-511].
The HinesCoflow makes use of the fact, that the average quality of the entities in the stock is diluted by inflowing entities of different quality, i.e. the process is a smooth with a variable time constant. The benefit of this formulation is, that the average quality of the stock is directly modeled by a stock, so that processes that change the average (e.g. gaining experience over the time of residence for a stock of workers) can be directly modeled as in- or outflows to the HinesCoflow.
+StockInfoInput
connector to collect the required information from a connected stock. For this to properly work out, inflows and outflows should not be mixed at a single StockPort
(e.g. it is best practice to connect known inflows to the inflow
and known outflows to the outflow
port). In case of a bi-directional flow, only one bi-flow should be connected to any single StockPort
—no additional flows should be present at that port (see notes for →AbsoluteSensor).StockInfoOutput
(y_stockInfo
) can be used to pass the stock information received from a connected stock onward to additional coflow components—or sensors.The Hines Coflow is explicitly named after its creator, James Hines. More information can be found on his website.
+This information is part of the Business Simulation Library (BSL).
+This is the general, unrestricted reservoir of the System Dynamics methodology, it accumulates information transported by flow components connected to the StockPorts. The InformationLevel can become negative.
+inflow
and outflow
→StockPorts are only indicative; in general the reservoir may be filled or drained by flows connected to either port.maxValue
and minValue
allow to define an admissable range. It can be monitored by an assert
using useAssert = true
in the Advanced tab. The switch causeError
controls whether an error or a warning is to be raised.init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial value.der(x) = 0
in order to find an initial value that establishes equilibrium. initialValue
-- in this case used as a start value for numerical iteration -- should be set to a value different from zero.)MaterialStock, CapacityRestrictedStock
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end InformationLevel; diff --git a/BusinessSimulation/Stocks/MaterialStock.mo b/BusinessSimulation/Stocks/MaterialStock.mo new file mode 100644 index 0000000..3f216f8 --- /dev/null +++ b/BusinessSimulation/Stocks/MaterialStock.mo @@ -0,0 +1,64 @@ +within BusinessSimulation.Stocks; + +model MaterialStock "Reservoir that cannot be drained below zero" + import BusinessSimulation.Constants.{small,zero}; + import BusinessSimulation.Types.InitializationOptions; + extends Interfaces.PartialStocks.BasicStock(initialValue(min = 0), minValue = zero); + extends Icons.MaterialStockIndicator; + parameter Boolean reinitializeStock = false "= true, if the stock is to be reinitalized to guarante nonnegativity" annotation(Evaluate = true, Dialog(tab = "Advanced")); +initial equation + // properly initialize discrete vars with fixed = false + // inflow to stock is unrestricted + pre(inflow.stopInflow) = false; + pre(outflow.stopInflow) = false; + // provide Boolean signal in case of negative stock + pre(inflow.stopOutflow) = not x > small; + pre(outflow.stopOutflow) = pre(inflow.stopOutflow); +equation + // inflow to stock is unrestricted + inflow.stopInflow = false; + outflow.stopInflow = false; + // provide Boolean signal in case of negative stock + inflow.stopOutflow = not x > small; + outflow.stopOutflow = inflow.stopOutflow; + // optional reinitialize stock to zero if negative // + if reinitializeStock then + when x < 0 then + reinit(x, 0); + end when; + end if; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This is a restricted reservoir of the System Dynamics methodology, which accumulates material (i.e. countable entities, some kind of mass) transported by flow components connected to the component's StockPorts. The MaterialStock can never become negative – we are not collecting \"antimatter\" – and will prevent connected flow components from draining its value below zero.
+The value of the stock will be set to zero if the calculated value x
is less than a very small positive amount and if reinitializeStock = true
is chosen in the Advanced tab:
if reinitializeStock then + when x < 0 then + reinit(x, 0); + end when; + end if;+
MaterialStock components will prevent connected flows from draining the stock via their →StockPort connectors' Boolean flags, should the calculated value x
be less than a very small positive amount:
inflow.stopOutflow = not x > small; + outflow.stopOutflow = inflow.stopOutflow;
inflow
and outflow
→StockPorts are only indicative; in general the reservoir may be filled or drained by flows connected to either port.maxValue
and minValue
allow to define an admissable range. It can be monitored by an assert
using useAssert = true
in the Advanced tab. The switch causeError
controls whether an error or a warning is to be raised.init
in the Advanced tab allows to select →InitializationOptions:initialValue
to determine the initial value.der(x) = 0
in order to find an initial value that establishes equilibrium. initialValue
-- in this case used as a start value for numerical iteration -- should be set to a value different from zero.)+InformationLevel, CapacityRestrictedStock
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-80.87, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {-70.87, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {70.439, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}}), Polygon(visible = true, origin = {80.439, 0}, lineColor = {192, 192, 192}, fillColor = {192, 192, 192}, fillPattern = FillPattern.Solid, points = {{-2.435, 13.229}, {-2.435, -13.344}, {4.87, 0.115}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end MaterialStock; diff --git a/BusinessSimulation/Stocks/Oven.mo b/BusinessSimulation/Stocks/Oven.mo new file mode 100644 index 0000000..718bb0a --- /dev/null +++ b/BusinessSimulation/Stocks/Oven.mo @@ -0,0 +1,186 @@ +within BusinessSimulation.Stocks; + +model Oven "Batch processing of inflow (aka batch delay)" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.Time; + import BusinessSimulation.Constants.{inf,INF}; + extends Icons.Oven; + extends Interfaces.Basics.GenericStock_Special(final init = InitializationOptions.FixedValue, hasStockInfoOutput = false); + + expandable connector InputConnector "Named inputs for the component" + extends Icons.DataInPort; + OutputType u_BatchSize "Size of batch to be processed"; + Time u_processingTime "Time to process batch"; + Time u_maxLoadingTime "Maximum allowed duration for loading"; + Time u_setupTime "Time for preparing the next operation"; + Time u_unloadingTime "Time needed to unload"; + end InputConnector; + + expandable connector OutputConnector + extends Icons.DataOutPort; + OutputType y_load "Current load"; + discrete Time y_leadTime "Manufacturing lead time (time from first unit enters to last unit exits on a batch)"; + discrete Time y_processingTime "Effective processing time for the batch process or per unit loaded"; + discrete Time y_setupTime "Effective setup time"; + discrete Time y_loadingTime "Effective loading time"; + discrete Time y_unloadingTime "Effective unloading time"; + end OutputConnector; + + InputConnector dataIn if not (hasConstantLoadingTime and hasConstantBatchSize and hasConstantProcessingTime and hasConstantSetupTime and hasConstantUnloadingTime) "Expandable connector for inputs" annotation(Placement(visible = true, transformation(origin = {0, 85}, extent = {{-10, -10}, {10, 10}}, rotation = -90), iconTransformation(origin = {-50, 100}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + OutputConnector dataOut "Expandable connector for outputs" annotation(Placement(visible = true, transformation(origin = {40, 85}, extent = {{-10, -10}, {10, 10}}, rotation = -270), iconTransformation(origin = {0, 104}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); + parameter OutputType initialLoad(min = 0) = 0 "Amount loaded at start time"; + parameter Time initialLoadingTime(min = 0) = 0 "Time that has already passed to load the initial load at start time"; + parameter OutputType batchSize(min = 0) = 10 "Constant number of units processed in one batch (optional)" annotation(Dialog(enable = hasConstantBatchSize)); + parameter Time maxLoadingTime(min = 0) = inf "Constant maximum allowed time for loading (optional)" annotation(Dialog(enable = hasConstantLoadingTime)); + parameter Time processingTime(min = 0) = 1 "Constant processing time for the batch process or per unit loaded (optional)" annotation(Dialog(enable = hasConstantProcessingTime)); + parameter Time setupTime(min = 0) = 0 "Time needed after processing is finished before loading can start (set to zero for simultaneous loading and unloading)" annotation(Dialog(enable = hasConstantSetupTime)); + parameter Time unloadingTime(min = 0) = modelSettings.dt "Time needed to unload" annotation(Dialog(enable = hasConstantUnloadingTime)); + parameter Boolean hasFixedProcessingTime = true "= true, if the processing time is given for the process, otherwise it is the time per unit loaded" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantLoadingTime = true "= true, if the maximum allowed time for loading is to be given by the parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantBatchSize = true "= true, if the batch size is to be given by the parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantProcessingTime = true "= true, if the processing time is to be given by the parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantSetupTime = true "= true, if the setup time is to be given by a parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + parameter Boolean hasConstantUnloadingTime = true "= true, if the unloading time is to be given as a parameter" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); + outer ModelSettings modelSettings; +protected + // converters + Converters.ConstantConverterTime parMaxLoadingTime(value = maxLoadingTime) if hasConstantLoadingTime "Constant max loading time" annotation(Placement(visible = true, transformation(origin = {-90, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterTime parProcessingTime(value = processingTime) if hasConstantProcessingTime "Constant processing time" annotation(Placement(visible = true, transformation(origin = {30, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverter parBatchSize(value = batchSize) if hasConstantBatchSize "Constant batch size" annotation(Placement(visible = true, transformation(origin = {120, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.PassThrough u_maxLoadingTime if not hasConstantLoadingTime "Variable input of loading time" annotation(Placement(visible = true, transformation(origin = {-65, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.PassThrough u_processingTime if not hasConstantProcessingTime "Variable input of processing time" annotation(Placement(visible = true, transformation(origin = {60, 48.274}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.PassThrough u_BatchSize if not hasConstantBatchSize "Variable batch size" annotation(Placement(visible = true, transformation(origin = {90, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterTime parSetupTime(value = setupTime) if hasConstantSetupTime "Constant setup time (optional)" annotation(Placement(visible = true, transformation(origin = {-135, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.PassThrough u_setupTime if not hasConstantSetupTime "Variable input of setup time" annotation(Placement(visible = true, transformation(origin = {-110, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ClipProcessTime actualMaxLoadingTime "Maximum allowed loading time" annotation(Placement(visible = true, transformation(origin = {-50, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ClipProcessTime actualProcessingTime "Processing time" annotation(Placement(visible = true, transformation(origin = {10, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.ZeroIfNegative actualBatchSize "Batch size to be processed" annotation(Placement(visible = true, transformation(origin = {70, 10}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); + Converters.ZeroIfNegative actualSetupTime "Setup time for further calculations" annotation(Placement(visible = true, transformation(origin = {-90, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Sensors.DynamicStockInfo dynamicStockInfo1 if hasStockInfoOutput annotation(Placement(visible = true, transformation(origin = {-0, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.PassThrough residenceTimeInfo "Residence time info for StockInfoPort" annotation(Placement(visible = true, transformation(origin = {-80, -47.043}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ClipProcessTime actualUnloadingTime "Unloading time" annotation(Placement(visible = true, transformation(origin = {0, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.PassThrough u_unloadingTime if not hasConstantUnloadingTime "Variable input of unloading time" annotation(Placement(visible = true, transformation(origin = {-35, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + Converters.ConstantConverterTime parUnloadingTime(value = unloadingTime) if hasConstantUnloadingTime "Constant unloading time" annotation(Placement(visible = true, transformation(origin = {-15, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -90))); + // local vars + Real x(min = 0) "Load"; + discrete Time latestStartTime "Time at which the process will commence latest"; + discrete Time lastStartLoading "Time at which the process finished last"; + discrete Time lastStartTime "Time at which the process actually started last"; + discrete Time nextStartLoading "Time at which the process will restart loading next"; + discrete Time fixedProcessingTime "The value for processing time used in current or last process"; + discrete Time fixedLoadingTime "The value for loading time used in the current or last process"; + discrete Time fixedSetupTime "The value for unloading time used in the current or last process"; + discrete Time fixedMaxLoadingTime "Maximum allowed loading time using for current calculations"; + discrete Time fixedUnloadingTime "The value for unloading time used in the current or last process"; +initial equation + // find an initial value for the lastStartLoading of the process + x = initialLoad; + outflow.data = 0; + // properly initialize discrete vars with fixed = false + // oven may be filled at inflow-port, but never drained + pre(inflow.stopOutflow) = true; + pre(fixedMaxLoadingTime) = actualMaxLoadingTime.y; + pre(lastStartTime) = -1; + pre(nextStartLoading) = inf; + // we don't know yet + pre(fixedLoadingTime) = -1; + // fix initial values + pre(fixedProcessingTime) = if not hasFixedProcessingTime then actualBatchSize.y * actualProcessingTime.y else actualProcessingTime.y; + pre(fixedSetupTime) = actualSetupTime.y; + pre(fixedUnloadingTime) = actualUnloadingTime.y; + // take the min(initialLoadingTime, actualLoadingTime) to calculate the lastStartLoading initially + pre(lastStartLoading) = if initialLoadingTime < fixedMaxLoadingTime then time - initialLoadingTime else time - fixedMaxLoadingTime; + pre(latestStartTime) = lastStartLoading + fixedMaxLoadingTime; + // no setup time included in the initial case + pre(inflow.stopInflow) = if initialLoad < actualBatchSize.y then false else true; + pre(inflow.stopOutflow) = true; + pre(dataOut.y_leadTime) = fixedSetupTime + fixedLoadingTime + fixedProcessingTime + fixedLoadingTime; + pre(dataOut.y_processingTime) = fixedProcessingTime; + pre(dataOut.y_loadingTime) = fixedLoadingTime; + pre(dataOut.y_setupTime) = fixedSetupTime; +algorithm + // in this section event-based, discrete behavior takes place + // check wheter production can start + when time >= pre(latestStartTime) or x > actualBatchSize.y then + inflow.stopInflow := true; + // no more inflow + lastStartTime := time; + // update the last time the process started + // fix all variable 'parameters' + fixedProcessingTime := if not hasFixedProcessingTime then x * actualProcessingTime.y else actualProcessingTime.y; + fixedSetupTime := actualSetupTime.y; + fixedLoadingTime := time - lastStartLoading; + fixedUnloadingTime := actualUnloadingTime.y; + nextStartLoading := time + fixedProcessingTime + fixedSetupTime; + lastStartLoading := nextStartLoading; + end when; + //check whether production is done + when time >= pre(lastStartTime) + pre(fixedProcessingTime) then + outflow.data := x / fixedUnloadingTime; + // drain the stock in minimum time dt + // check whether loading can commence + elsewhen time >= pre(lastStartTime) + pre(fixedProcessingTime) + pre(fixedUnloadingTime) then + outflow.data := 0; + end when; + // check whether loading can start + when time >= pre(nextStartLoading) then + inflow.stopInflow := false; + fixedMaxLoadingTime := actualMaxLoadingTime.y; + latestStartTime := lastStartLoading + fixedMaxLoadingTime; + end when; + /* TO DO: + Processing Time should be a fixed amount or a variable amount (x * processTime) depending upon a switch + Batch Size should also be a fixed variable to make this easier to understand + */ +equation + // basic idendities + dataOut.y_load = y; + dataOut.y_leadTime = fixedSetupTime + fixedLoadingTime + fixedProcessingTime + fixedLoadingTime; + dataOut.y_processingTime = fixedProcessingTime; + dataOut.y_loadingTime = fixedLoadingTime; + dataOut.y_setupTime = fixedSetupTime; + residenceTimeInfo.u = fixedSetupTime + (fixedLoadingTime + fixedUnloadingTime) / 2 + fixedProcessingTime; + // textual equations + der(x) = inflow.rate + outflow.rate; + inflow.stock = x; + // outflow.info = 1; + // data will always be the rate to drain the stock + inflow.stopOutflow = true; + // oven must never be drained via inflow-port + // report current load via output connectors + y = inflow.stock; + y1 = inflow.stock; + y2 = inflow.stock; + // connect equations + connect(u_maxLoadingTime.u, dataIn.u_maxLoadingTime) "External input of maximum allowed loading time" annotation(Line(visible = true, origin = {-30, 72}, points = {{-35, -14}, {-35, -2}, {30, -2}, {30, 13}}, color = {1, 37, 163})); + connect(u_processingTime.u, dataIn.u_processingTime) "External input of processing time" annotation(Line(visible = true, origin = {15, 72}, points = {{45, -15.726}, {45, -2}, {-15, -2}, {-15, 13}}, color = {1, 37, 163})); + connect(u_BatchSize.u, dataIn.u_BatchSize) "External input of batch size" annotation(Line(visible = true, origin = {40, 72}, points = {{50, -14}, {50, -2}, {-40, -2}, {-40, 13}}, color = {1, 37, 163})); + connect(parMaxLoadingTime.y, actualMaxLoadingTime.u) annotation(Line(visible = true, origin = {-79.333, 28}, points = {{-10.667, 16}, {-10.667, -8}, {21.333, -8}}, color = {1, 37, 163})); + connect(u_maxLoadingTime.y, actualMaxLoadingTime.u) annotation(Line(visible = true, origin = {-62.667, 27.333}, points = {{-2.333, 14.667}, {-2.333, -7.333}, {4.667, -7.333}}, color = {1, 37, 163})); + connect(parProcessingTime.y, actualProcessingTime.u) annotation(Line(visible = true, origin = {26, 28}, points = {{4, 16}, {4, -8}, {-8, -8}}, color = {1, 37, 163})); + connect(u_processingTime.y, actualProcessingTime.u) annotation(Line(visible = true, origin = {46, 26.758}, points = {{14, 13.516}, {14, -6.758}, {-28, -6.758}}, color = {1, 37, 163})); + connect(u_BatchSize.y, actualBatchSize.u) annotation(Line(visible = true, origin = {86, 20.879}, points = {{4, 21.758}, {4, -10.879}, {-8, -10.879}}, color = {1, 37, 163})); + connect(parBatchSize.y, actualBatchSize.u) annotation(Line(visible = true, origin = {106, 21.667}, points = {{14, 23.333}, {14, -11.667}, {-28, -11.667}}, color = {1, 37, 163})); + connect(u_setupTime.u, dataIn.u_setupTime) "Input of variable unloading time" annotation(Line(visible = true, origin = {-60, 72}, points = {{-50, -14}, {-50, -2}, {60, -2}, {60, 13}}, color = {1, 37, 163})); + connect(parSetupTime.y, actualSetupTime.u) annotation(Line(visible = true, origin = {-122.667, 14.667}, points = {{-12.333, 29.333}, {-12.333, -14.667}, {24.667, -14.667}}, color = {1, 37, 163})); + connect(actualSetupTime.u, u_setupTime.y) annotation(Line(visible = true, origin = {-106, 14}, points = {{8, -14}, {-4, -14}, {-4, 28}}, color = {1, 37, 163})); + connect(inflow, dynamicStockInfo1.inPort) annotation(Line(visible = true, origin = {-114, -10}, points = {{-46, 10}, {-31, 10}, {-31, -10}, {108, -10}}, color = {128, 0, 128})); + connect(dynamicStockInfo1.outPort, outflow) annotation(Line(visible = true, origin = {101.996, -10}, points = {{-95.996, -10}, {18.004, -10}, {18.004, 10}, {58.004, 10}}, color = {128, 0, 128})); + connect(dynamicStockInfo1.y_stockInfo, y_stockInfo) annotation(Line(visible = true, origin = {48, -36.8}, points = {{-48, 22.8}, {-48, 31.8}, {-8, 31.8}, {-8, -43.2}, {102, -43.2}}, color = {128, 0, 128})); + connect(y2, dynamicStockInfo1.levelInfo) annotation(Line(visible = true, origin = {80, -39}, points = {{80, -11}, {80, -1}, {-80, -1}, {-80, 13}}, color = {1, 37, 163})); + connect(u_unloadingTime.y, actualUnloadingTime.u) annotation(Line(visible = true, origin = {-26, -26}, points = {{-9, 68}, {-9, -34}, {18, -34}}, color = {1, 37, 163})); + connect(parUnloadingTime.y, actualUnloadingTime.u) annotation(Line(visible = true, origin = {-12.667, -25.333}, points = {{-2.333, 69.333}, {-2.333, -34.667}, {4.667, -34.667}}, color = {1, 37, 163})); + connect(residenceTimeInfo.y, dynamicStockInfo1.residenceTimeInfo) annotation(Line(visible = true, origin = {-20.879, -40.029}, points = {{-51.758, -7.014}, {25.879, -7.014}, {25.879, 14.029}}, color = {1, 37, 163})); + connect(u_unloadingTime.u, dataIn.u_unloadingTime) "Input unloading time" annotation(Line(visible = true, origin = {-20, 72}, points = {{-15, -14}, {-15, -2}, {20, -2}, {20, 13}}, color = {1, 37, 163})); + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -80}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%initialLoad", fontName = "Lato")}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+An oven (aka batch delay) can be seen as an idealized model of a batch process, e.g. cookies are put on a baking tray, the oven is loaded, the cookies are baked for some time, and finally the oven is unloaded (the process may then start over again).
+The parameters or inputs batchSize
, maxLoadingTime
, processingTime
, and setupTime
specify the behavior of the batch process. The oven is loaded by a flow connected to its inflow
port (usually from a cloud or another stock representing a buffer stock) until either the batchSize
is reached (the oven's capacity) or the time since the loading of the oven commenced has reached the maxLoadingTime
. It will then close and prevent further inflow for the duration of the processingTime
. The unloading of the finished \"material\" will take place in dt
time - a global variable that indicates the shortest possible durationa of any process in a model. The reloading can commence after setupTime
has passed since the process has ended. For setupTime = 0
simulatenous loading and unloading will take place.
To initialize the oven, an initialLoad
and an initialLoadingTime
(e.g. how much time has already passed loading the oven when the simulation starts) have to be given.
batchSize
, maxLoadingTime
, processingTime
, and setupTime
can be time-varying continuous inputs, but are internally recalculated every time the process starts and then are held fixed.This information is part of the Business Simulation Library (BSL).
+At any given time, the inflow to the PureDelay is delayed by an exact amount of time given either by the parameter delayTime
or the continuous input u
. Changes in the delay time will only affect the current or later inflow, i.e. whatever is already in the process of being delayed will not be affected.
The PureDelay will work at discrete time intervals:
+when sample(modelSettings.modelStartTime + samplingPeriod, samplingPeriod) then + // load new material into the stock, move loaded material, unload material +end when; ++
The values for the in- and outflows and the load will be kept constant between events.
+inflow
port of the PureDelay.OutflowDynamicStock
or →SplitOutflowDynamicStock
have to be connected to the outflow
port.SplitOutflowDynamicStock
) can be used to model leaking.init
in the Advanced tab allows to select →InitializationOptions:
+initialValue
.inflow.rate * delayTime
startValue
.Conveyor
should be used, which will preserve order of entry (units can at best leave at the same time, but not earlier than units, that have already entered the stock).SimpleConveyor, Conveyor, DelayN, DelayFixed, DelayInformation
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, -80}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%initialValue", fontName = "Lato"), Text(visible = true, origin = {0, 75}, textColor = {255, 0, 0}, extent = {{-100, -12}, {100, 12}}, textString = "Pure Delay", fontName = "Lato Black", textStyle = {TextStyle.Bold})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end PureDelay; diff --git a/BusinessSimulation/Stocks/SimpleConveyor.mo b/BusinessSimulation/Stocks/SimpleConveyor.mo new file mode 100644 index 0000000..c7b03bd --- /dev/null +++ b/BusinessSimulation/Stocks/SimpleConveyor.mo @@ -0,0 +1,80 @@ +within BusinessSimulation.Stocks; + +model SimpleConveyor "Conveyor (aka pipeline delay) with constant delay time and no leakage" + import BusinessSimulation.Types.InitializationOptions; + import BusinessSimulation.Units.{Time,Rate}; + extends Icons.Conveyor; + extends Interfaces.Basics.GenericStock_Special(hasStockInfoOutput = false, init = modelSettings.init); + parameter OutputType initialValue(min = 0) = 0 "Initial load"; + parameter Time delayTime(min = 0) = 1 "Time of residence in the stock"; +protected + outer ModelSettings modelSettings; + parameter Time clippedDelayTime = max(modelSettings.dt, delayTime) "Delay time should not be less than dt" annotation(Dialog(tab = "Initialization", enable = false)); + parameter Rate initialFlow(fixed = false) "Constant initial outflow" annotation(Dialog(tab = "Initialization", enable = false)); + Real x(start = initialValue, min = 0) "Initial load" annotation(Dialog(tab = "Initialization", enable = false)); + Real delayedFlow "Shifted inflow"; + Sensors.DynamicStockInfo dynamicStockInfo if hasStockInfoOutput "Generate stock information data" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); + Converters.ConstantConverterTime reportedDelayTime(value = clippedDelayTime) annotation(Placement(visible = true, transformation(origin = {50, -30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); +initial equation + // initialize the stock by finding a valid initial value, by using a given initialValue, or by trying to find a steady state solution + if init == InitializationOptions.FixedValue then + x = initialValue; + elseif init == InitializationOptions.SteadyState then + x = clippedDelayTime * inflow.rate; + // use Little's law + end if; + initialFlow = x / clippedDelayTime; + // properly initialize discrete vars with fixed = false + // inflow to stock is restricted to inflow port + pre(inflow.stopInflow) = false; + pre(inflow.stopOutflow) = true; +equation + delayedFlow = delay(inflow.rate, clippedDelayTime); + // conveyor will signal outflow rate at its outflow-side + outflow.data = if time - modelSettings.modelStartTime < clippedDelayTime then initialFlow else delayedFlow; + // set the inflow.stock value + inflow.stock = x; + // the stock equations determine the current load x + der(x) = inflow.rate + outflow.rate; + // inflow to stock is restricted to inflow port + inflow.stopInflow = false; + inflow.stopOutflow = true; + // report current value of stock via output connectors + y = inflow.stock "Current load"; + y1 = inflow.stock "Current load"; + y2 = inflow.stock "Current load"; + // connect equations + connect(inflow, dynamicStockInfo.inPort) annotation(Line(visible = true, origin = {-83, 0}, points = {{-77, 0}, {77, 0}}, color = {128, 0, 128})); + connect(dynamicStockInfo.outPort, outflow) annotation(Line(visible = true, origin = {83, 0}, points = {{-77, 0}, {77, 0}}, color = {128, 0, 128})); + connect(dynamicStockInfo.y_stockInfo, y_stockInfo) annotation(Line(visible = true, origin = {64, -24.8}, points = {{-64, 30.8}, {-64, 39.8}, {16, 39.8}, {16, -55.2}, {96, -55.2}}, color = {128, 0, 128})); + connect(dynamicStockInfo.levelInfo, y2) annotation(Line(visible = true, origin = {53.333, -35.333}, points = {{-53.333, 29.333}, {-53.333, -14.667}, {106.667, -14.667}}, color = {1, 37, 163})); + connect(reportedDelayTime.y, dynamicStockInfo.residenceTimeInfo) annotation(Line(visible = true, origin = {18.333, -22}, points = {{26.667, -8}, {-13.333, -8}, {-13.333, 16}}, color = {1, 37, 163})); + // assert statements + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The SimpleConveyor (aka pipeline delay) bevhaves as one would expect a conveyor belt to work: What flows into the SimpleConveyor will flow out after a period given by the parameter delayTime
has elapsed. The delayTime
will be clipped, so that it can never be smaller than the global parameter modelSettings.dt
.
The Conveyor internally uses Modelica's delay()
function with a constant time of delay to delay the rate of inflow.
inflow
port of the Conveyor—no draining is allowed via this port.OutflowDynamicStock
or →SplitOutflowDynamicStock
have to be connected to the outflow
port.SplitOutflowDynamicStock
) can be used to model leaking.[modelSettings.modelStartTime, delayTime]
the outflow will simply be the initial value for the stock divided by the delay time.init
in the Advanced tab allows to select →InitializationOptions:
+initialValue
.inflow.rate * delayTime
startValue
.Conveyor, PureDelay, DelayFixed, DelayInformation
+"), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {240.961, -10}, fillColor = {255, 255, 255}, extent = {{-0.961, -0}, {0.961, 0}}), Text(visible = true, origin = {0, -80}, textColor = {0, 0, 128}, extent = {{-100, -6}, {100, 6}}, textString = "%initialValue", fontName = "Lato")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end SimpleConveyor; diff --git a/BusinessSimulation/Stocks/package.mo b/BusinessSimulation/Stocks/package.mo new file mode 100644 index 0000000..bb66e7d --- /dev/null +++ b/BusinessSimulation/Stocks/package.mo @@ -0,0 +1,25 @@ +within BusinessSimulation; + +package Stocks "Containers (\"reservoirs\") used to represent entities that have been stored in a specific state" + extends Icons.Package annotation(Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); + annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, origin = {0, 5}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, lineThickness = 10, extent = {{-50, -50}, {50, 50}})}), Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+This package contains stock (\"reservoirs\") elements of the System Dynamics method.
+While stocks do have an inflow and an outflow port (indicated by two small arrows pointing into and out of the component respectively), this designation will in general not be relevant for their behavior with regard to flows:
+A stock may be filled or drained on either side - the flow element connected to a stock will determine the direction of flow!
+Nevertheless, it is good modeling practice to follow the convention of connecting flows that are strictly inflows or outflows to the corresponding stock port.
+There are two important cases, where closely sticking to the inflow and outflow designations is very important:
++Tutorial.ElementaryBuildingBlocks +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+A record of stock-related information. It groups that following variables:
+Variable (Type) | +
+ Description + |
+
infoLevel (Real) | +
+ Current amount in the stock or level + |
+
infoInflow (Rate) | +
+ Current rate of total inflow into stock + |
+
infoOutflow (Rate) | +
+ Current rate of total outflow from the stock + |
+
infoNetFlow (Rate) | +
+ Current net-rate of flow (> 0 inflow, < 0 outflow) + |
+
infoMeanResidenceTime (Time) | +
+ Current average time of residence for elements in the stock (if there is no outflow, -1 is to be reported) + |
+
This information is part of the Business Simulation Library (BSL).
+This package contains types
.
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This package contains types to represent SI-units and (quite often) non-SIunits used in modeling social and ecological systems.
++Tutorial.UnitsInBusinessSimulations +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This page contains the contact information for the library's main author and a list of contributors.
++
Name + | Guido Wolf Reichert | +
Address |
+
+
+Schauenburgerstr. 116
+ |
+
Phone | ++49 431 5606-855 | +
Fax | ++49 431 5606-856 | +
gwr@bsl-support.de | +|
Web | +https://www.bsl-support.de | +
+
EUPL © the European Union 2007, 2016+")); +end Licence; diff --git a/BusinessSimulation/UsersGuide/References.mo b/BusinessSimulation/UsersGuide/References.mo new file mode 100644 index 0000000..74d476d --- /dev/null +++ b/BusinessSimulation/UsersGuide/References.mo @@ -0,0 +1,143 @@ +within BusinessSimulation.UsersGuide; + +final class References "Bibliography" + annotation(Documentation(info = " +
This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
below) which is provided under the terms of this Licence. Any use of the Work,
other than as authorised under this Licence is prohibited (to the extent such
use is covered by a right of the copyright holder of the Work).
The Work is provided under the terms of this Licence when the Licensor (as
defined below) has placed the following notice immediately following the
copyright notice for the Work:
Licensed under the EUPL
or has expressed by any other means his willingness to license under the EUPL.
1. Definitions
In this Licence, the following terms have the following meaning:
- ‘The Licence’: this Licence.
- ‘The Original Work’: the work or software distributed or communicated by the
Licensor under this Licence, available as Source Code and also as Executable
Code as the case may be.
- ‘Derivative Works’: the works or software that could be created by the
Licensee, based upon the Original Work or modifications thereof. This Licence
does not define the extent of modification or dependence on the Original Work
required in order to classify a work as a Derivative Work; this extent is
determined by copyright law applicable in the country mentioned in Article 15.
- ‘The Work’: the Original Work or its Derivative Works.
- ‘The Source Code’: the human-readable form of the Work which is the most
convenient for people to study and modify.
- ‘The Executable Code’: any code which has generally been compiled and which is
meant to be interpreted by a computer as a program.
- ‘The Licensor’: the natural or legal person that distributes or communicates
the Work under the Licence.
- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
Licence, or otherwise contributes to the creation of a Derivative Work.
- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
the Work under the terms of the Licence.
- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
renting, distributing, communicating, transmitting, or otherwise making
available, online or offline, copies of the Work or providing access to its
essential functionalities at the disposal of any other natural or legal
person.
2. Scope of the rights granted by the Licence
The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
sublicensable licence to do the following, for the duration of copyright vested
in the Original Work:
- use the Work in any circumstance and for all usage,
- reproduce the Work,
- modify the Work, and make Derivative Works based upon the Work,
- communicate to the public, including the right to make available or display
the Work or copies thereof to the public and perform publicly, as the case may
be, the Work,
- distribute the Work or copies thereof,
- lend and rent the Work or copies thereof,
- sublicense rights in the Work or copies thereof.
Those rights can be exercised on any media, supports and formats, whether now
known or later invented, as far as the applicable law permits so.
In the countries where moral rights apply, the Licensor waives his right to
exercise his moral right to the extent allowed by law in order to make effective
the licence of the economic rights here above listed.
The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
any patents held by the Licensor, to the extent necessary to make use of the
rights granted on the Work under this Licence.
3. Communication of the Source Code
The Licensor may provide the Work either in its Source Code form, or as
Executable Code. If the Work is provided as Executable Code, the Licensor
provides in addition a machine-readable copy of the Source Code of the Work
along with each copy of the Work that the Licensor distributes or indicates, in
a notice following the copyright notice attached to the Work, a repository where
the Source Code is easily and freely accessible for as long as the Licensor
continues to distribute or communicate the Work.
4. Limitations on copyright
Nothing in this Licence is intended to deprive the Licensee of the benefits from
any exception or limitation to the exclusive rights of the rights owners in the
Work, of the exhaustion of those rights or of other applicable limitations
thereto.
5. Obligations of the Licensee
The grant of the rights mentioned above is subject to some restrictions and
obligations imposed on the Licensee. Those obligations are the following:
Attribution right: The Licensee shall keep intact all copyright, patent or
trademarks notices and all notices that refer to the Licence and to the
disclaimer of warranties. The Licensee must include a copy of such notices and a
copy of the Licence with every copy of the Work he/she distributes or
communicates. The Licensee must cause any Derivative Work to carry prominent
notices stating that the Work has been modified and the date of modification.
Copyleft clause: If the Licensee distributes or communicates copies of the
Original Works or Derivative Works, this Distribution or Communication will be
done under the terms of this Licence or of a later version of this Licence
unless the Original Work is expressly distributed only under this version of the
Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
(becoming Licensor) cannot offer or impose any additional terms or conditions on
the Work or Derivative Work that alter or restrict the terms of the Licence.
Compatibility clause: If the Licensee Distributes or Communicates Derivative
Works or copies thereof based upon both the Work and another work licensed under
a Compatible Licence, this Distribution or Communication can be done under the
terms of this Compatible Licence. For the sake of this clause, ‘Compatible
Licence’ refers to the licences listed in the appendix attached to this Licence.
Should the Licensee's obligations under the Compatible Licence conflict with
his/her obligations under this Licence, the obligations of the Compatible
Licence shall prevail.
Provision of Source Code: When distributing or communicating copies of the Work,
the Licensee will provide a machine-readable copy of the Source Code or indicate
a repository where this Source will be easily and freely available for as long
as the Licensee continues to distribute or communicate the Work.
Legal Protection: This Licence does not grant permission to use the trade names,
trademarks, service marks, or names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the copyright notice.
6. Chain of Authorship
The original Licensor warrants that the copyright in the Original Work granted
hereunder is owned by him/her or licensed to him/her and that he/she has the
power and authority to grant the Licence.
Each Contributor warrants that the copyright in the modifications he/she brings
to the Work are owned by him/her or licensed to him/her and that he/she has the
power and authority to grant the Licence.
Each time You accept the Licence, the original Licensor and subsequent
Contributors grant You a licence to their contributions to the Work, under the
terms of this Licence.
7. Disclaimer of Warranty
The Work is a work in progress, which is continuously improved by numerous
Contributors. It is not a finished work and may therefore contain defects or
‘bugs’ inherent to this type of development.
For the above reason, the Work is provided under the Licence on an ‘as is’ basis
and without warranties of any kind concerning the Work, including without
limitation merchantability, fitness for a particular purpose, absence of defects
or errors, accuracy, non-infringement of intellectual property rights other than
copyright as stated in Article 6 of this Licence.
This disclaimer of warranty is an essential part of the Licence and a condition
for the grant of any rights to the Work.
8. Disclaimer of Liability
Except in the cases of wilful misconduct or damages directly caused to natural
persons, the Licensor will in no event be liable for any direct or indirect,
material or moral, damages of any kind, arising out of the Licence or of the use
of the Work, including without limitation, damages for loss of goodwill, work
stoppage, computer failure or malfunction, loss of data or any commercial
damage, even if the Licensor has been advised of the possibility of such damage.
However, the Licensor will be liable under statutory product liability laws as
far such laws apply to the Work.
9. Additional agreements
While distributing the Work, You may choose to conclude an additional agreement,
defining obligations or services consistent with this Licence. However, if
accepting obligations, You may act only on your own behalf and on your sole
responsibility, not on behalf of the original Licensor or any other Contributor,
and only if You agree to indemnify, defend, and hold each Contributor harmless
for any liability incurred by, or claims asserted against such Contributor by
the fact You have accepted any warranty or additional liability.
10. Acceptance of the Licence
The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
placed under the bottom of a window displaying the text of this Licence or by
affirming consent in any other similar way, in accordance with the rules of
applicable law. Clicking on that icon indicates your clear and irrevocable
acceptance of this Licence and all of its terms and conditions.
Similarly, you irrevocably accept this Licence and all of its terms and
conditions by exercising any rights granted to You by Article 2 of this Licence,
such as the use of the Work, the creation by You of a Derivative Work or the
Distribution or Communication by You of the Work or copies thereof.
11. Information to the public
In case of any Distribution or Communication of the Work by means of electronic
communication by You (for example, by offering to download the Work from a
remote location) the distribution channel or media (for example, a website) must
at least provide to the public the information requested by the applicable law
regarding the Licensor, the Licence and the way it may be accessible, concluded,
stored and reproduced by the Licensee.
12. Termination of the Licence
The Licence and the rights granted hereunder will terminate automatically upon
any breach by the Licensee of the terms of the Licence.
Such a termination will not terminate the licences of any person who has
received the Work from the Licensee under the Licence, provided such persons
remain in full compliance with the Licence.
13. Miscellaneous
Without prejudice of Article 9 above, the Licence represents the complete
agreement between the Parties as to the Work.
If any provision of the Licence is invalid or unenforceable under applicable
law, this will not affect the validity or enforceability of the Licence as a
whole. Such provision will be construed or reformed so as necessary to make it
valid and enforceable.
The European Commission may publish other linguistic versions or new versions of
this Licence or updated versions of the Appendix, so far this is required and
reasonable, without reducing the scope of the rights granted by the Licence. New
versions of the Licence will be published with a unique version number.
All linguistic versions of this Licence, approved by the European Commission,
have identical value. Parties can take advantage of the linguistic version of
their choice.
14. Jurisdiction
Without prejudice to specific agreement between parties,
- any litigation resulting from the interpretation of this License, arising
between the European Union institutions, bodies, offices or agencies, as a
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
of Justice of the European Union, as laid down in article 272 of the Treaty on
the Functioning of the European Union,
- any litigation arising between other parties and resulting from the
interpretation of this License, will be subject to the exclusive jurisdiction
of the competent court where the Licensor resides or conducts its primary
business.
15. Applicable Law
Without prejudice to specific agreement between parties,
- this Licence shall be governed by the law of the European Union Member State
where the Licensor has his seat, resides or has his registered office,
- this licence shall be governed by Belgian law if the Licensor has no seat,
residence or registered office inside a European Union Member State.
Appendix
‘Compatible Licences’ according to Article 5 EUPL are:
- GNU General Public License (GPL) v. 2, v. 3
- GNU Affero General Public License (AGPL) v. 3
- Open Software License (OSL) v. 2.1, v. 3.0
- Eclipse Public License (EPL) v. 1.0
- CeCILL v. 2.0, v. 2.1
- Mozilla Public Licence (MPL) v. 2
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
works other than software
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
Reciprocity (LiLiQ-R+).
The European Commission may update this Appendix to later versions of the above
licences without producing a new version of the EUPL, as long as they provide
the rights granted in Article 2 of this Licence and protect the covered Source
Code from exclusive appropriation.
All other changes or additions to this Appendix require the production of a new
EUPL version.
This information is part of the Business Simulation Library (BSL).
+[1] | +
+ J. W. Forrester, \"Industrial dynamics: a major breakthrough for decision makers,\" Harvard Business Review, vol. 36, no. 4, pp. 37-66, 1958. + |
+
[2] | +
+ J. W. Forrester, Industrial Dynamics, Cambridge, MA, USA: M.I.T. Press, 1961. + |
+
[3] | +J. D. Sterman, Business Dynamics: Systems Thinking and Modeling for a Complex World. Boston, MA, USA: McGraw-Hill Higher Education, 2000. | +
[4] | +K. Saeed and A. A. Irdamidiris, \"Continuous non-linear functions for use in system dynamics modeling,\" DYNAMICA, vol. 10, no. 1, pp. 16-23, Summer 1984. Available: https://systemdynamics.org/wp-content/uploads/assets/dynamica/volume-10/10-1/6.pdf | +
[5] | +F. M. Bass, \"A new product growth for model consumer durables,\" Management Science, vol. 15, no. 5, pp. 215-227, Jan. 1969. | +
[6] | +
+ J. Hines, Molecules of Structure: Building Blocks for System Dynamics Models Version 2.03 (2015). + |
+
[7] | +
+ J. D. W. Morecroft, “A critical review of diagramming tools for conceptualizing feedback system models,” DYNAMICA, vol. 8, no. 1, pp. 20–29, Summer 1982. Available: https://systemdynamics.org/wp-content/uploads/assets/dynamica/volume-8/8-1/5.pdf + |
+
[8] | +
+ B. Richmond, An Introduction to Systems Thinking, Lebanon, NH, USA: isee systems, 2004. + |
+
[9] | +
+ A. Ford, Modeling the Environment, 2nd ed. Washington, DC, USA: Island Press, 2010. + |
+
[10] | +
+ H. Bossel, Systems and Models: Complexity, Dynamics, Evolution, Sustainability. Norderstedt, Germany: Books on Demand, 2007. + |
+
[11] | +
+ H. Bossel, System Zoo 1 Simulation Models: Elementary Systems, Physics, Engineering. Norderstedt, Germany: Books on Demand, 2007. + |
+
[12] | +
+ H. Bossel, System Zoo 2 Simulation Models: Climate, Ecosystems, Resources. Norderstedt, Germany: Books on Demand, 2007. + |
+
[13] | +
+ H. Bossel, System Zoo 3 Simulation Models: Economy, Society, Development. Norderstedt, Germany: Books on Demand, 2007. + |
+
[14] | +
+ R. G. Coyle, System Dynamics Modelling: A Practical Approach, 1st ed. London, UK: Chapman & Hall, 1996. + |
+
[15] | +
+ K. Warren, Strategic Management Dynamics. Chichester, UK: John Wiley & Sons, 2008. + |
+
[16] | +
+ M. J. Radzicki, “Dyadic processes, tempestous relationsships, and system dynamics,” System Dynamics Review, vol. 9, no. 1, pp. 79–94, 1993. + |
+
[17] | +
+ F. Hoppenstedt, “Predator-prey model,” Scholarpedia, vol. 1, p. 1523, 2006. Available: http://www.scholarpedia.org/article/Predator-prey_model + |
+
[18] | +
+ P. Junglas, Praxis der Simulationstechnik - Eine Einführung in signal- und objektorientierte Methoden, 1st ed. Haan-Gruiten: Verl. Europa-Lehrmittel, 2014. + |
+
[19] | +
+ A. Janoschek, “Das reaktionskinetische Grundgesetz und seine Beziehungen zum Wachstums-und Ertragsgesetz,” Statistische Vierteljahresschrift, vol. 10, pp. 25–37, 1957. + |
+
[20] | +
+ D. N. Ford, \"A system dynamics glossary,\" System Dynamics Review, vol. 35, no. 4, pp. 369–379, 2019. Available: https://onlinelibrary.wiley.com/doi/epdf/10.1002/sdr.1641 + |
+
[21] | +
+ United Nations, System of environmental-economic accounting 2012: Central framework. New York, 2014. + |
+
[22] | +
+ H. Bossel, Indicators for sustainable development: Theory, method, applications; a report to the Balaton group. Winnipeg: IISD, 1999. Available: https://www.iisd.org/system/files/publications/balatonreport.pdf + |
+
[23] | +
+ W. O. Kermack and A. G. McKendrick, \"A contribution to the mathematical theory of epidemics,\" Proceedings of the royal society of london. Series A, Containing papers of a mathematical and physical character, vol. 115, no. 772, pp. 700-721, 1927. + |
+
This information is part of the Business Simulation Library (BSL).
+This is the first official release of the library.
+I'm deeply indebted to the excellent support that I received from Wolfram MathCore and its whole team. I would like to explicitly mention Malte Lenz, Quentin Lambert, and Ankit Naik, who patiently answered my questions and followed up on issues. Thanks a lot, guys.
+
+
Wolfram System Modeler™ is a trademark of Wolfram Research, Inc.
Wolfram Mathematica and Mathematica™ are registered trademarks of Wolfram Research, Inc.
This information is part of the Business Simulation Library (BSL).
+This release contains fixes to the first release:
+html
code in the documentation.partial
for the package SourcesOrSinks
had been erroneously placed and has been removed.conditional components
being used within equations as this is prohitibed according to Modelica specifications.unit
attribute for the builtin class Real
has parametric variability; accordingly constant
variables used for setting this have been given the parameter
prefix now.smoothness
in Examples.LookupFunctions
violated lookup rules and now correctly references Modelica.Blocks.Types.Smoothness.LinearSegments
.outputIfZero
for Converters.Division_Guarded
now correctly has type OutputType
.ConstantConverter
components used discrete
variables outside of when-clauses
; the discrete
declaration for these variables has been deemed unnecessary and accordingly been dropped.Icons.Clock
and Icons.Clock_white
have been renamed to Clockface
and Clockface_white
in order to avoid errors in other tools.Examples.ManagingEmployment
did not match up because OutputType
was not propagated further down in the hierarchy.OutputType
which is defined as a replaceable type
has been made encapsulated
as type
cannot be looked up in classes that are not packages
unless they are encapsulated.BasicStock
within the class Stocks.CapacityRestrictedStock
contained hasVariableAdmissableRange
which is not included in the class.This information is part of the Business Simulation Library (BSL).
+"), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, lineColor = {56, 56, 56}, fillColor = {246, 246, 246}, fillPattern = FillPattern.Solid, points = {{-80, -100}, {-80, 100}, {20, 100}, {20, 40}, {80, 40}, {80, -100}, {-80, -100}}), Polygon(visible = true, lineColor = {56, 56, 56}, fillColor = {230, 230, 230}, fillPattern = FillPattern.Solid, points = {{20, 100}, {80, 40}, {20, 40}, {20, 100}}), Line(visible = true, points = {{2, -12}, {50, -12}}, color = {56, 56, 56}), Line(visible = true, points = {{2, -60}, {50, -60}}, color = {56, 56, 56}), Ellipse(visible = true, origin = {-35, -60}, lineColor = {56, 56, 56}, fillColor = {160, 160, 164}, fillPattern = FillPattern.Solid, extent = {{-12.5, -12.5}, {12.5, 12.5}}), Ellipse(visible = true, origin = {-35, -12.5}, lineColor = {56, 56, 56}, fillColor = {160, 160, 164}, fillPattern = FillPattern.Solid, extent = {{-12.5, -12.5}, {12.5, 12.5}})})); +end ReleaseNotes; diff --git a/BusinessSimulation/UsersGuide/ReleaseNotes/package.order b/BusinessSimulation/UsersGuide/ReleaseNotes/package.order new file mode 100644 index 0000000..9e49e47 --- /dev/null +++ b/BusinessSimulation/UsersGuide/ReleaseNotes/package.order @@ -0,0 +1,2 @@ +Version_1_0_1 +Version_1_0_0 diff --git a/BusinessSimulation/UsersGuide/Tutorial/ElementaryBuildingBlocks.mo b/BusinessSimulation/UsersGuide/Tutorial/ElementaryBuildingBlocks.mo new file mode 100644 index 0000000..ab3e579 --- /dev/null +++ b/BusinessSimulation/UsersGuide/Tutorial/ElementaryBuildingBlocks.mo @@ -0,0 +1,331 @@ +within BusinessSimulation.UsersGuide.Tutorial; + +final class ElementaryBuildingBlocks "A quick tour introducing the library's main classes" + extends Icons.Info; + annotation(Documentation(info = " +This information is part of the Business Simulation Library (BSL).
+The Business Simulation Library provides the following elementary classes to build dynamic models:
+Icon | +Main Class | +Description | +
---|---|---|
+ | Stocks | +
+ Stocks describe the states of a system, e.g. some measurable quantity, which might—at least on principle—be measured even when we (hypothetically) \"freeze the system\". + |
+
+ | Flows | +
+ Flows are aggregate processes that change the states of a system, i.e. they fill and drain stocks at a certain rate. + |
+
+ | Sources or Sinks | +
+ Sources or Sinks are stocks with an infinite capacity (aka \"clouds\") out of or into which elements flow at a system's boundary. The BSL extends the narrow definition of sources or sinks and also considers the combination of a stock with infinite capacity and a connected flow to describe processes of growth or decline from external sources or sinks. + |
+
+ | Converters | +
+ Converters can be used to model information processing on a very low level. In a converter some information input is immediately processed to provide some information output. + |
+
+ | Information Sources | +
+ Information sources describe information inputs from \"information processors\" or \"controllers\" that are outside a system's boundary. + |
+
+ | Molecules of Structure | +
+ Pre-built components to model information processing, decision making or subsystems in general. + |
+
+→Flows
+→Sources or Sinks
+→Converters
+→Molecules of Structure
+
+
In the System Dynamics community the terms stock and level (sometimes also: reservoir) are synonymously used to describe compartments, that store some measurable quantity during a simulation [20]. In general, these compartments can only be filled and drained over time by flows operating at a certain rate. In the Business Simulation Library we will distinguish three basic types of reservoirs:
+Icon | +Class Name | +Description | +
---|---|---|
+ | Information Level | +
+ An InformationLevel stores information and can become negative. It is the most general kind of reservoir. For example, we may use an information level to model a company's assets, liabilities, and shareholders' equity. + |
+
+ | Material Stock | +
+ A MaterialStock will usually contain some form of matter or mass, e.g. living beings and people, raw material, finished goods, capital equipment etc. The plus sign in the upper left corner of the icon indicates, that a material stock can never become negative. If a flow tries to drain a material stock, that does not contain any element, it will be set to zero, as a flow cannot transport \"antimatter\". + |
+
+ | Capacity Restricted Stock | +
+ The CapacityRestrictedStock is a material stock with additional restrictions regarding its capacity. It may have a maximum and a minimum level (≥ 0) which have to be observed and cannot be violated by flows draining or filling the reservoir. + |
+
Stocks—we will continue to use this as a short term for stocks/levels in general—do have an inflow and an outflow port (→StockPort) via which they can receive \"mass\" in- and outflows from connected flow components. This is indicated by the pairs of grey arrows shown within the stock icon. It should be noted though, that this indication and naming is generally only suggestive, as stocks may be filled or drained via both ports. Whenever possible, though, inflows and outflows should primarily be connected to the \"correct\" port of a stock component, as mixing in- and outflows at any port will lead to false stock information reporting by →StockInfoOutputs.
+All stock components report the quantity that currently resides in the component via information outputs (→RealOutput).
+We would often like to keep track of some mean quality for entities contained in a stock: The experience of new employees or their wage level may vary during a simulation. A coflow is typically applied in these cases and can be very compactly modeled using the HinesCoflow.
+Next to the elementary types of stock, there are special kinds of stock which can best be thought of as dynamic stocks. Dynamic stocks have a special stock port (red) on their outflow side (→StockPort_Special). The special stock port indicates, that there is some process working inside the stock, which we will not model in more detail. A dynamic stock will determine the rate of outflow internally (as opposed to regular stocks, where connected flows determine the rate out outflow):
+Icon | +Class Name | +Description | +
---|---|---|
+ | DelayN | +
+ An n-th order exponential delay will delay its inflow so that the actual times of residence will be distributed around the indicated (mean) delay time. The variation for the distribution of residence times will decrease with higher delay orders (a delay of infinite order will behave exactly like a PureDelay). + |
+
+ | Pure Delay | +
+ A material delay with fixed delay time that may change over time. Any changes in the delay time will only affect incoming material, so that new material may flow out earlier than material already in the stock. + |
+
+ | Simple Conveyor | +
+ This stock can be seen as an ideal conveyor belt, i.e. everything that enters is delayed by a fixed amount of time (which cannot change during the simulation). + |
+
+ | Conveyor | +
+ This stock also models an ideal conveyor, but the discretely modeled component allows the delay time to change during the simulation. Unlike a PureDelay, the order of inflow is preserved so that material may leave the belt at the same time, but never ahead of material that has entered earlier. + |
+
+ | Oven | +
+ The Oven (aka batch delay) is an ideal model of a batch production process: Material will flow into the oven until its capacity is reached (or the load time is exceeded). The material will then be processed for some process time and will then be unloaded. During the processing material can neither flow in nor out of the stock. + |
+
All dynamic stocks are material stocks (e.g. there can never be negative amounts inside a process). Dynamic stocks may have additional input ports (or a DataInPort in the case of the Oven) in case process or delay times (and optionally other parameters) are to be variable during the simulation.
+For dynamic stocks the designation of the ports is binding: They can only be filled via the inflow port and can only be drained via the outflow port.
+Unlike regular stocks, dynamic stocks will determine the rate of outflow, so that the rate of outflow is not set independently by the flow component connected to the outflow port of a dynamic stock. Only the →OutflowDynamicStock and the →SplitOutFlowDynamicStock components have a corresponding FlowPort_Special and can be connected to the outflow port of a dynamic stock.
+Flow components are mainly responsible for dynamic behavior as they fill or drain stocks over time. There are three basic types of flows:
+Icon | +Class Name | +Description | +
---|---|---|
+ | Unidirectional | +
+ Unidirectional flows drain the stock connected to their |
+
+ | Bidirectional | +
+ Bidirectional flows are essentially unidirectional flows that may change the direction of flow during a simulation depending on the sign of the rate: A negative rate will transport entities from B to A, while a positive rate will transport entities from A to B. + |
+
+ | Interaction | +
+ Interactions model the general case of two stocks which have a bidrectional flow from/to a cloud (\"netflow\") where the rate of the netflow (a positive rate will fill the respective stock) may depend on the current amount in one or both of the connected stocks. A simple example is the →BrokenTransition, where the inflow to stock B is proportional to the rate of the outflow of stock A, i.e. here some kind of transformation is modeled rather than a mere transition. + |
+
All flow components report their current rate—or rates in the case of interactions—via information outputs (→RealOutput). They may have additional inputs (→RealInput) in the general case where variables determining the rate of flow can change during the simulation.
+Sources or Sinks are compact components that can be used to model processes of growth or decline at a system's boundary in a compact way:
+Icon | +Class Name | +Description | +
---|---|---|
+ | Cloud | +A Cloud simply is a stock that is outside a system's boundary—here we assume that the stock has an infinite capacity. A typical example would be any model of population dynamics, where we will not model where newborns come from or what will happen to the deceased population. A cloud can be either source or sink. |
+
+ | Source | +
+ A Source combines a Cloud with a unidirectional outflow that will then fill the stock connected to the component's |
+
+ | Sink | +
+ A Sink combines a Cloud with a unidirectional inflow that will then drain the stock connected to the component's |
+
+ | Source or Sink | +
+ A SourceOrSink combines a Cloud with a bidirectional flow that may fill or drain the stock connected to the component's |
+
Like flow components, sources or sink components report their current rate via information outputs (→RealOutput). They may have additional inputs (→RealInput) in the general case where variables determining the rate of flow can change during the simulation.
+Converters take one or more
Icon | +Package Name | +Description | +
---|---|---|
+ | Discrete Delay | +
+ DiscreteDelay converters introduce discrete behavior or delays into information processing and typically contain an information level—which is the reason for their boxlike-appearance. + |
+
+ | Logical | +
+ Logical converters have Boolean outputs (→BooleanOutput) and/or inputs (→BooleanInput). + |
+
+ | Lookup | +
+ Lookup converters use tabular or more elaborate parametric functions to model the transformation of information. + |
+
+ | Vector | +
+ Vector converters have vector inputs and/or outputs. + |
+
John Morecroft [7] suggested that diagrams of dynamic systems would be greatly improved, if we used more aggregate diagramming. In this library we are well advised to follow that advice: We can reduce the diagram for a system under management to show the system itself and its observable information output. We then just need two additional, rather aggregated converters:
+Icon | +Package Name | +Description | +
---|---|---|
+ | Information Processing | +
+ Taking the raw information from the system and its environment and bringing it into the form needed for decision making. + |
+
+ | Policy | +
+ Using (preprocessed) information, we will have some decision rule that will give a decision output—usually goals and other regulations to be observed or rates for processes that change the state(s) of the system. + |
+
When we look at complex systems in society or even at individual companies and markets, we are well advised to conquer their complexity by applying a hierarchical modeling approach: We will model the system in focus as a system of systems exchanging information and/or physical entities. Jay Forrester, for example, in his seminal book \"Industrial Dynamics\" [2, Section 6.2] distinguished the \"physical\" flow of material, orders, money, personnel, and capital equipment from that of information.
+Since a closed system, i.e. one that does not exchange anything with other systems, is rather irrelevant, we can usually assume that all subsystems will receive and/or transmit information for managerial control or just for information processing. Accordingly, all subsystems will have connectors for information input and output (typically →DataInPort and →DataOutPort).
+We can thus best distinguish different types of subsystems by looking at the presence of stock and flow ports:
+Icon | +Subsystem Type | +Description | +
---|---|---|
+ | Blocks | +
+ Systems or processes that do not exchange physical entities with other systems vie stock or flow ports—there is only exchange of information via DataIn- and DataOutPorts, e.g. managerial control, government, and/or information processing. + |
+
+ | Incubators | +
+ Systems or processes that receive, store, and provide physical entities via multiple stock ports. There will usually be some kind of transformation during storage. + |
+
+ | Transceivers | +
+ Systems or processes that receive and store physical entities, but also move entities to/from connected systems. This is most general kind of subsystem and will have multiple stock and flow ports. + |
+
+ | Actuators | +
+ Systems or processes that move physical entities to and from connected systems via multiple flow ports. + |
+
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Business process modeling (BPM) has become an ubiquitous activity in support of management decision making and business analytics. While there are different tools and notation for BPM, event-driven process chains (EPC) offer a very general and simple way of modeling business processes. Essentially, processes always start with an event that will lead to one or more activites (functions in EPC-terminology) which again will mount into one or more events, so that in general any activity must always be braced by two events.
+Figure 1 shows an EPC for the idealized production process of ACME, a startup that produces intruder alarm systems specifically designed to meet private home owners’ needs. The diagram is valid for a single unit produced and shows events (red hexagons) and functions (green boxes) in typical notation.
++ |
While this \"discrete-event\" view of production is great for operational process improvement, it is not so well suited for for winning over investors by telling a compelling story about business development or for discussing policy-setting issues with regard to social systems and organizations. In these cases an aggregate strategic view is the better choice.
+To go from the the familiar perspective of BPM to a more strategic one, we will look at what happens in a period. In a month there will be lots of events and actions. We can aggregate the actions and events separately: Individual actions will thus add up to a process that produces tangible results at a certain rate(e.g. assembled units per month). In the general case the rate may be a continuously varying quantity due to external and internal disruptions or policies. Events on the other hand can be collected as the countable results of processes, e.g. finished products can be collected in an inventory.
+Figure 2 shows, how we can move from the event-driven process chain model to a strategic model using the Business Simulation Library. As in the EPC we will start out with its dynamic equivalent, a container—called stock. The very first stock is called a source in the library, which means that we assume infinite capacity indicating our model's boundary (i.e. in our example we do not care for the source of all material, that we need to assemble products).
++ |
The assembly of products in our example has been aggregated to a mere process of transition from the unlimited stock of raw materials to the inventory of finished goods. Shipping products in Figure 2 has also become a mere transition at some given rate, which moves our products to the stock installedBase representing continued use during the product's useful lifetime.
+Stocks (with red color code inherited from events) and flows (with green color code inherited from actions) are atomic systems in the library. As we can see in Figure 2, stocks and flows are connected via acausal connectors (→ StockPort, → FlowPort). Each component reports basic information about what is going on inside using output connectors (white triangles; → RealOutput): A flow will report its current rate at any time during a simulation, whereas a stock will report the amount of entities that are inside at any time during a simulation. The numbers shown inside the stocks indicates the initial amount inside the respective stock.
+Looking at the producing and shipping flows in Figure 2, we find, that they show a stylized pipeline (following System Dyamics conventions) with a stylized paddle wheel pump that is influenced by a variable called rate.
++ |
Since there is no information input to the producing component, the rate of production in this simple case is a constant parameter. Figure 3 shows how—upon selecting the component—the rate
can be set in the General tab in SystemModeler. Note, that there is also a structural parameter hasConstantRate
that allows to instead of a parameter have an variable input for the rate.
This introductory example is continued in the package Examples:
+ +Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+Units and unit checking are central to most modelers in System Dynamics and there are good reasons for this: It is all too easy to come up with nonsensical equations and mixing \"apples and oranges\". Modelica as a cyber-physical modeling language clearly encourages modelers to make use of its rather elaborate unit framework that provides the attributes quantity, unit
, and displayUnit
for any real valued variable in models:
quantity
tells us about what a measurement means: The same unit (say N.m
) may be used for energy as well as for torque—so the quantity is very important.unit
tells us how to compare values obtained in measurements for identical quantities: 10 g
are simply a different magnitude than 10 kg
.displayUnit
finally solves the issue of using a standard unit (typically SI-units), while allowing compatible units for value input and output.While the rigor of physical models cannot be fully transfered to modeling in the social sciences and ecology, there is maybe some middle ground:
+types
with a fixed (e.g. final
) unit, there are too many possibilities and preferences in social science modeling, so we may often leave the choice of unit to the modeler.displayUnit
whenever possible, as using a standard unit for calculations, while compatible units can be used for input and output, takes care of a significant source of error. SystemModeler allows to enter custom unit converions in the Tools>Options
menu.Currently, units are not used for acausal connectors, i.e. the stock and the rate in a →StockPort or in a →FlowPort are simply of the predefined type Real
with quantity = \"\"
and unit = \"1\"
, making them dimensionless.
Quantities and units are used for the information outputs of components. In most elementary classes there is a replaceable type OutputType
which can be conveniently set using a drop down list in SystemModeler. In general, the default will be one of the following types: Types.Reals, Units.Rate
, or Units.Time
.
A modeler may simply stick with say Types.Reals
, which is identical to Modelica's predefined type Real
, for a stock called \"personnel\" and then use the editor to modify the quantity
and unit
attributes:
Types.Reals(quantity = \"HumanPopulation\", unit = \"people\")
+Doing so would correspond with what most dedicated System Dynamics packages allow. Nevertheless, the Business Simulation Library is designed with the following recommendations:
+Modelica does not allow to change the unit for the built-in variable time
. Accordingly, the following types all have unit = \"s\"
and all models will run in seconds so that there can never be any doubt when different models are coupled:
Time, Time_minutes, Time_hours, Time_days, Time_weeks, Time_months, Time_quarters, Time_years+
The type Time_years
, for example, has displayUnit = \"yr\"
and allows to conveniently enter 5 yr
in setting the →ConstantConverterTime usefulLife
in the model Examples.SimpleProductionChain.
Note, that we need to add custom unit conversions for the units wk, mo, qtr, yr
as shown in Figure 1—but we only need to do this once.
+ |
Using displayUnit
for time is very convenient—unfortunately this flexibility is harder to transfer to entering rates: We would need to have lots of unit conversions say one for people/yr
and another one for EUR/yr
.
Given that we are most of the time simply counting some entities (like a chemist is counting different molecules) it should suffice to enter fractional rates (→Units.Rate). Then we only need to add custom unit conversions for 1/wk, 1/mo, 1/qtr, 1/yr
in SystemModeler as shown in Figure 2.
+ |
In the example Examples.SimpleProductionChain we can set the productionRate
in the ConstantConverter by leaving ValueType = Types.Reals
(default) and using timeBaseString
to select \"month\", so that value = 100
is then correctly shown as a fractional rate of 100 per month
. Remember, that the value used in any calculations will be the corresponding rate per second.
Next to fractional rates we can also work with correct rates for some physical flows, e.g. VolumeFlowRate, MassFlowRate, EnergyFlowRate, MomentumFlowRate, AngularMomentumFlowRate, Velocity
, which are defined as follows:
+ type Rate = Types.Reals(quantity = \"Rate\", unit = \"1/s\") \"Fractional rate per unit of time\"; + type VolumeFlowRate = Rate(quantity = \"VolumeFlowRate\", unit = \"m3/s\") \"Volume flow rate measured in m3/s\"; + type MassFlowRate = Rate(quantity = \"MassFlowRate\", unit = \"kg/s\") \"Mass flow rate measured in kg/s\"; + type EnergyFlowRate = Rate(quantity = \"Power\", unit = \"W\") \"Rate of energy transfer (power) usually measured in watt (W) or joule per second (J/s)\"; + type MomentumFlowRate = Rate(quantity = \"MomentumFlowRate\", unit = \"kg.m/s2\") \"Momentum flow rate (aka force) measured in kg.m/s2\"; + type AngularMomentumFlowRate = Rate(quantity = \"AngularMomentumFlowRate\", unit = \"kg.m2/s2\") \"Angular momentum flow rate (aka torque) measured in kg.m2/s2\"; + type Velocity = Rate(quantity = \"Velocity\", unit = \"m/s\") \"Velocity given in m/s\"; ++
Refer to the documentation for ConstantConverterRate for more detail.
+Next to rates and times we will need appropriate units for entities accounted for in stocks and information processing in general. In the Business Simulation Library the available types
, which all extend Types.Reals
, can be grouped as follows:
Strictly speaking, everything in a model might be considered information and thus the following definitions seem rather evident: +
+ type Information = Types.Reals(quantity = \"Information\") \"Information that may have an arbitrary unit (base unit = '1')\"; + type Fraction = Information(min = 0, max = 1) \"Information given as a fraction between zero and one\"; + type Dimensionless = Information(unit = \"1\") \"Information that is dimensionless (e.g. utility)\"; + type Probability = Dimensionless(min = 0, max = 1) \"Probability between zero and one\"; ++
In a model of chemical reactions we will not find unit = \"H2O\"
or other molecules—which could be seen as the analogy to what is common practice in System Dynamics counting amounts of similar entities. So, it may not seem totally implausible to somewhat approach modeling in the social sciences a bit like a chemist and use counting units for some amount of similar entities contained in stocks whose instance name very likely will reflect what is counted inside. As the definition for type Amount
below shows, we may even include a chemist's mol
:
+ type Amount = Types.Reals(quantity = \"Amount\", unit = \"each\") \"Counting amounts of entities or substance (base unit = 'each')\"; ++
Using the custom unit conversions shown in Figure 3 we can use displayUnit
have large values be shown as 2 million
or enter small values as 2.5 percent
. The resulting value will always be a pure number since 1 each = 1
.
+ |
Value in economic models may be either expressed as (dimensionless) utility or in monetary terms. For the latter, the following types
are defined in the Units
package:
+
+ type Money = Types.Reals(quantity = \"Money\", unit = \"CU\") \"Cash and other forms of financial capital accounted for in currency units [CU]\"; + type Money_USD = Money(unit = \"USD\") \"Money accounted for in USD\"; + type Money_EUR = Money(unit = \"EUR\") \"Money accounted for in EUR\"; + type Money_JPY = Money(unit = \"JPY\") \"Money accounted for in JPY\"; + type Money_GBP = Money(unit = \"GBP\") \"Money accounted for in GBP\"; ++
Even though, we may use counting units (see Amount
above), it seems to make a lot of sense to distinguish some essential quantites and their interconnected networks of stocks and flows—similar to the way Forrester did, as mentioned before. In economic and ecological models, the following definitions may suffice for a lot of use cases:
+ type Population = Types.Reals(quantity = \"Population\") \"A population of individuals or organisms belonging to the same group or species\"; + type People = Population(quantity = \"HumanPopulation\") \"Some human population (#people)\"; + type Labor = Types.Reals(quantity = \"Labor\", unit = \"FTE\") \"Labor as production factor measured in FTE\"; + type TangibleAssets = Types.Reals(quantity = \"TangibleAssets\") \"Tangible assets like buildings and structure, machinery and equipment, and cultivated assets\"; + type IntangibleAssets = Types.Reals(quantity = \"IntangibleAssets\") \"Intangible assets like computerized information, R & D, economic competencies, and other innovative properties\"; + type Material = Types.Reals(quantity = \"Material\") \"Primary commodities and unprocessed material\"; + type Goods = Material \"Finished or intermediary goods\"; + type Orders = Types.Reals(quantity = \"Orders\") \"Orders are an operational stock used to model the delay between a stated need and its fulfillment\"; ++
In times of climate change and other questions touching global sustainability the need to combine ecological and economical thinking has led to the realization that humanity and its economic system is tightly embedded in a biological and physical environment. Therefore physical stocks and their in- and outflows have to be accounted for properly [21]. It thus seems appropriate to at least introduce some important conserved physical quantities:
++ type Volume = Types.Reals(quantity = \"Volume\", unit = \"m3\") \"Volume measured in m3\"; + type Mass = Types.Reals(quantity = \"Mass\", unit = \"kg\") \"Mass measured in kg\"; + type Energy = Types.Reals(quantity = \"Energy\", unit = \"J\") \"Energy measured in Joule (W.s)\"; + type Momentum = Types.Reals(quantity = \"Momentum\", unit = \"kg.m/s\") \"Momentum measured in kg.m/s\"; + type AngularMomentum = Types.Reals(quantity = \"AngularMomentum\", unit = \"kg.m2/s\") \"Angular momentum measured in kg.m2/s\"; ++
Next to the physical quantites listed above, we conclude with just these additions:
++ type Angle = Types.Reals(quantity = \"Angle\", unit = \"rad\", displayUnit = \"deg\") \"Angle in rad, entered and displayed in deg)\"; + type Length = Types.Reals(quantity = \"Length\", unit = \"m\") \"Length (or width/breadth, height/depth) measured in m\"; + type Area = Types.Reals(quantity = \"Area\", unit = \"m2\") \"Area measured in m2\"; ++
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This package contains documentation files to guide users in becoming familiar with the library.
++Examples +
+Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+This package contains documentation files to guide users in becoming familiar with the library:
+Content | +
+ Description + |
+
Tutorial | +
+ A comprehensive tutorial introducing the user to the Business Simulation Library. + |
+
References | +
+ List of numbered references that are cited in documentation pages. + |
+
Release Notes | +
+ Release notes and acknowledgements. + |
+
Contact | +
+ Contact info and list of contributors. + |
+
Licence | +
+ Terms and conditions for using and distributing the Business Simulation Library (\"The License\"). + |
+
Copyright © 2020 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the Business Simulation Library (BSL).
+The BUSINESS SIMULATION LIBRARY (BSL) supports modeling & simulation in the social sciences and ecology. Following John Sterman [3] the name \"Busines Simulation\" was chosen in a rather broad sense since ultimately modeling in these domains is concerned with \"control\", \"decision making\", and \"management\".
+The BSL follows the widespread System Dynamics metaphor and modeling approach introduced by Jay W. Forrester [1], [2]. System Dynamics offers a very general, low-level modeling paradigm, that lends itself perfectly to model, simulate, and analyze strategic business or public policy issues.
+Unlike existing aproaches the BSL makes use of Modelica's acausal connectors to better distinguish material/mass flows from instantaneous information signal flows (causal connections). The approach has the additional benefit of allowing the modeler to build rather compact models in a fast and reliable fashion.
+To get started with the library, it is recommended to have a look at:
++ + +
+Copyright © 2020 Guido Wolf Reichert
Licensed unter the European Union Public Licence (EUPL), Version 1.2 or later (the \"License\")
You may not use this work except in compliance with the License. You may obtain a copy of the License at:
https://eur-lex.europa.eu/eli/dec_impl/2017/863/oj (the English text for EUPL-1.2 is included in the UsersGuide)
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 expressed or implied. See the License for the specific language governing permissions and limitations under the License.
+Modelica© is a registered trademark of the Modelica Association.
+"), __Wolfram(itemFlippingEnabled = true), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {76, 112, 136}, fillColor = {113, 166, 201}, pattern = LinePattern.None, fillPattern = FillPattern.HorizontalCylinder, lineThickness = 4, extent = {{-100, -100}, {100, 100}}, radius = 25), Rectangle(visible = true, origin = {0.142, -2.447}, lineColor = {255, 255, 255}, fillColor = {255, 255, 255}, lineThickness = 10, extent = {{-62.191, -62.447}, {62.191, 62.447}}), Text(visible = true, origin = {0, -30}, textColor = {255, 255, 255}, extent = {{-60, -30}, {60, 30}}, textString = "BSL", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Polygon(visible = true, origin = {25.123, 60}, rotation = -990, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, points = {{-10, 10}, {10, 0}, {-10, -10}, {-10, 10}}), Polygon(visible = true, origin = {-23.947, 60}, rotation = -1170, lineColor = {255, 255, 255}, fillColor = {76, 112, 136}, fillPattern = FillPattern.Solid, points = {{-10, 10}, {10, 0}, {-10, -10}, {-10, 10}}), Rectangle(visible = true, origin = {-63.017, -0.581}, lineColor = {76, 112, 136}, fillColor = {255, 255, 255}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-8.5, -9.419}, {8.5, 9.419}}), Rectangle(visible = true, origin = {61.5, 0}, lineColor = {255, 255, 255}, fillColor = {76, 112, 136}, fillPattern = FillPattern.Solid, lineThickness = 3, extent = {{-8.5, -9.419}, {8.5, 9.419}})}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); +end BusinessSimulation; diff --git a/BusinessSimulation/package.order b/BusinessSimulation/package.order new file mode 100644 index 0000000..a5057be --- /dev/null +++ b/BusinessSimulation/package.order @@ -0,0 +1,16 @@ +UsersGuide +ModelSettings +Examples +Stocks +Flows +SourcesOrSinks +Converters +InformationSources +MoleculesOfStructure +Sensors +Interfaces +Functions +Constants +Types +Units +Icons diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..4153cd3 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,287 @@ + EUROPEAN UNION PUBLIC LICENCE v. 1.2 + EUPL © the European Union 2007, 2016 + +This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined +below) which is provided under the terms of this Licence. Any use of the Work, +other than as authorised under this Licence is prohibited (to the extent such +use is covered by a right of the copyright holder of the Work). + +The Work is provided under the terms of this Licence when the Licensor (as +defined below) has placed the following notice immediately following the +copyright notice for the Work: + + Licensed under the EUPL + +or has expressed by any other means his willingness to license under the EUPL. + +1. Definitions + +In this Licence, the following terms have the following meaning: + +- ‘The Licence’: this Licence. + +- ‘The Original Work’: the work or software distributed or communicated by the + Licensor under this Licence, available as Source Code and also as Executable + Code as the case may be. + +- ‘Derivative Works’: the works or software that could be created by the + Licensee, based upon the Original Work or modifications thereof. This Licence + does not define the extent of modification or dependence on the Original Work + required in order to classify a work as a Derivative Work; this extent is + determined by copyright law applicable in the country mentioned in Article 15. + +- ‘The Work’: the Original Work or its Derivative Works. + +- ‘The Source Code’: the human-readable form of the Work which is the most + convenient for people to study and modify. + +- ‘The Executable Code’: any code which has generally been compiled and which is + meant to be interpreted by a computer as a program. + +- ‘The Licensor’: the natural or legal person that distributes or communicates + the Work under the Licence. + +- ‘Contributor(s)’: any natural or legal person who modifies the Work under the + Licence, or otherwise contributes to the creation of a Derivative Work. + +- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of + the Work under the terms of the Licence. + +- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, + renting, distributing, communicating, transmitting, or otherwise making + available, online or offline, copies of the Work or providing access to its + essential functionalities at the disposal of any other natural or legal + person. + +2. Scope of the rights granted by the Licence + +The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +sublicensable licence to do the following, for the duration of copyright vested +in the Original Work: + +- use the Work in any circumstance and for all usage, +- reproduce the Work, +- modify the Work, and make Derivative Works based upon the Work, +- communicate to the public, including the right to make available or display + the Work or copies thereof to the public and perform publicly, as the case may + be, the Work, +- distribute the Work or copies thereof, +- lend and rent the Work or copies thereof, +- sublicense rights in the Work or copies thereof. + +Those rights can be exercised on any media, supports and formats, whether now +known or later invented, as far as the applicable law permits so. + +In the countries where moral rights apply, the Licensor waives his right to +exercise his moral right to the extent allowed by law in order to make effective +the licence of the economic rights here above listed. + +The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to +any patents held by the Licensor, to the extent necessary to make use of the +rights granted on the Work under this Licence. + +3. Communication of the Source Code + +The Licensor may provide the Work either in its Source Code form, or as +Executable Code. If the Work is provided as Executable Code, the Licensor +provides in addition a machine-readable copy of the Source Code of the Work +along with each copy of the Work that the Licensor distributes or indicates, in +a notice following the copyright notice attached to the Work, a repository where +the Source Code is easily and freely accessible for as long as the Licensor +continues to distribute or communicate the Work. + +4. Limitations on copyright + +Nothing in this Licence is intended to deprive the Licensee of the benefits from +any exception or limitation to the exclusive rights of the rights owners in the +Work, of the exhaustion of those rights or of other applicable limitations +thereto. + +5. Obligations of the Licensee + +The grant of the rights mentioned above is subject to some restrictions and +obligations imposed on the Licensee. Those obligations are the following: + +Attribution right: The Licensee shall keep intact all copyright, patent or +trademarks notices and all notices that refer to the Licence and to the +disclaimer of warranties. The Licensee must include a copy of such notices and a +copy of the Licence with every copy of the Work he/she distributes or +communicates. The Licensee must cause any Derivative Work to carry prominent +notices stating that the Work has been modified and the date of modification. + +Copyleft clause: If the Licensee distributes or communicates copies of the +Original Works or Derivative Works, this Distribution or Communication will be +done under the terms of this Licence or of a later version of this Licence +unless the Original Work is expressly distributed only under this version of the +Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee +(becoming Licensor) cannot offer or impose any additional terms or conditions on +the Work or Derivative Work that alter or restrict the terms of the Licence. + +Compatibility clause: If the Licensee Distributes or Communicates Derivative +Works or copies thereof based upon both the Work and another work licensed under +a Compatible Licence, this Distribution or Communication can be done under the +terms of this Compatible Licence. For the sake of this clause, ‘Compatible +Licence’ refers to the licences listed in the appendix attached to this Licence. +Should the Licensee's obligations under the Compatible Licence conflict with +his/her obligations under this Licence, the obligations of the Compatible +Licence shall prevail. + +Provision of Source Code: When distributing or communicating copies of the Work, +the Licensee will provide a machine-readable copy of the Source Code or indicate +a repository where this Source will be easily and freely available for as long +as the Licensee continues to distribute or communicate the Work. + +Legal Protection: This Licence does not grant permission to use the trade names, +trademarks, service marks, or names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the copyright notice. + +6. Chain of Authorship + +The original Licensor warrants that the copyright in the Original Work granted +hereunder is owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each Contributor warrants that the copyright in the modifications he/she brings +to the Work are owned by him/her or licensed to him/her and that he/she has the +power and authority to grant the Licence. + +Each time You accept the Licence, the original Licensor and subsequent +Contributors grant You a licence to their contributions to the Work, under the +terms of this Licence. + +7. Disclaimer of Warranty + +The Work is a work in progress, which is continuously improved by numerous +Contributors. It is not a finished work and may therefore contain defects or +‘bugs’ inherent to this type of development. + +For the above reason, the Work is provided under the Licence on an ‘as is’ basis +and without warranties of any kind concerning the Work, including without +limitation merchantability, fitness for a particular purpose, absence of defects +or errors, accuracy, non-infringement of intellectual property rights other than +copyright as stated in Article 6 of this Licence. + +This disclaimer of warranty is an essential part of the Licence and a condition +for the grant of any rights to the Work. + +8. Disclaimer of Liability + +Except in the cases of wilful misconduct or damages directly caused to natural +persons, the Licensor will in no event be liable for any direct or indirect, +material or moral, damages of any kind, arising out of the Licence or of the use +of the Work, including without limitation, damages for loss of goodwill, work +stoppage, computer failure or malfunction, loss of data or any commercial +damage, even if the Licensor has been advised of the possibility of such damage. +However, the Licensor will be liable under statutory product liability laws as +far such laws apply to the Work. + +9. Additional agreements + +While distributing the Work, You may choose to conclude an additional agreement, +defining obligations or services consistent with this Licence. However, if +accepting obligations, You may act only on your own behalf and on your sole +responsibility, not on behalf of the original Licensor or any other Contributor, +and only if You agree to indemnify, defend, and hold each Contributor harmless +for any liability incurred by, or claims asserted against such Contributor by +the fact You have accepted any warranty or additional liability. + +10. Acceptance of the Licence + +The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ +placed under the bottom of a window displaying the text of this Licence or by +affirming consent in any other similar way, in accordance with the rules of +applicable law. Clicking on that icon indicates your clear and irrevocable +acceptance of this Licence and all of its terms and conditions. + +Similarly, you irrevocably accept this Licence and all of its terms and +conditions by exercising any rights granted to You by Article 2 of this Licence, +such as the use of the Work, the creation by You of a Derivative Work or the +Distribution or Communication by You of the Work or copies thereof. + +11. Information to the public + +In case of any Distribution or Communication of the Work by means of electronic +communication by You (for example, by offering to download the Work from a +remote location) the distribution channel or media (for example, a website) must +at least provide to the public the information requested by the applicable law +regarding the Licensor, the Licence and the way it may be accessible, concluded, +stored and reproduced by the Licensee. + +12. Termination of the Licence + +The Licence and the rights granted hereunder will terminate automatically upon +any breach by the Licensee of the terms of the Licence. + +Such a termination will not terminate the licences of any person who has +received the Work from the Licensee under the Licence, provided such persons +remain in full compliance with the Licence. + +13. Miscellaneous + +Without prejudice of Article 9 above, the Licence represents the complete +agreement between the Parties as to the Work. + +If any provision of the Licence is invalid or unenforceable under applicable +law, this will not affect the validity or enforceability of the Licence as a +whole. Such provision will be construed or reformed so as necessary to make it +valid and enforceable. + +The European Commission may publish other linguistic versions or new versions of +this Licence or updated versions of the Appendix, so far this is required and +reasonable, without reducing the scope of the rights granted by the Licence. New +versions of the Licence will be published with a unique version number. + +All linguistic versions of this Licence, approved by the European Commission, +have identical value. Parties can take advantage of the linguistic version of +their choice. + +14. Jurisdiction + +Without prejudice to specific agreement between parties, + +- any litigation resulting from the interpretation of this License, arising + between the European Union institutions, bodies, offices or agencies, as a + Licensor, and any Licensee, will be subject to the jurisdiction of the Court + of Justice of the European Union, as laid down in article 272 of the Treaty on + the Functioning of the European Union, + +- any litigation arising between other parties and resulting from the + interpretation of this License, will be subject to the exclusive jurisdiction + of the competent court where the Licensor resides or conducts its primary + business. + +15. Applicable Law + +Without prejudice to specific agreement between parties, + +- this Licence shall be governed by the law of the European Union Member State + where the Licensor has his seat, resides or has his registered office, + +- this licence shall be governed by Belgian law if the Licensor has no seat, + residence or registered office inside a European Union Member State. + +Appendix + +‘Compatible Licences’ according to Article 5 EUPL are: + +- GNU General Public License (GPL) v. 2, v. 3 +- GNU Affero General Public License (AGPL) v. 3 +- Open Software License (OSL) v. 2.1, v. 3.0 +- Eclipse Public License (EPL) v. 1.0 +- CeCILL v. 2.0, v. 2.1 +- Mozilla Public Licence (MPL) v. 2 +- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 +- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for + works other than software +- European Union Public Licence (EUPL) v. 1.1, v. 1.2 +- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong + Reciprocity (LiLiQ-R+). + +The European Commission may update this Appendix to later versions of the above +licences without producing a new version of the EUPL, as long as they provide +the rights granted in Article 2 of this Licence and protect the covered Source +Code from exclusive appropriation. + +All other changes or additions to this Appendix require the production of a new +EUPL version. diff --git a/README.md b/README.md new file mode 100644 index 0000000..651c786 --- /dev/null +++ b/README.md @@ -0,0 +1,50 @@ + + +# Business Simulation Library (BSL) +A Modelica library for modeling & simulation of dynamical systems in the social sciences, e.g. business/economics, and ecology using the System Dynamics metaphor. + +## Library Description +System Dynamics offers a very general, low-level modeling paradigm, that lends itself perfectly to model, simulate, and analyze strategic business and policy issues in any kind of organization. Unlike existing aproaches the `BSL` makes use of Modelica's acausal connectors to better distinguish _material/mass_ flows from instantaneous _information_ signal flows (causal connections). The approach has the additional benefit of allowing the modeler to build more compact models in a fast and reliable fashion. + +#### Overview of the Main Classes + +| Icon | Main Class | Description | +| :-------:|:------------------|:------------| +| | __Stocks__ | Containers ("reservoirs") used to represent entities that have been stored in a specific state | +| | __Flows__ | Processes that move entities from one stock to another at a specific rate | +| | __SourcesOrSinks__ | Flows into or out of a stock with infinite capacity at a system's boundary | +| | __Converters__ | Information processing (blocks) | +| | __InformationSources__ | External information input | +| | __MoleculesOfStructure__ | Pre-built components to model _information processing_, _decision making_ and _subsystems_ in general (blocks, incubators, transceivers, and actuators) | + +Using the pre-built components modelers can start to build their own components to eventually arrive at an appropriate representation of the system in focus in a hierarchical fashion. + +## Documentation and Release Notes +You can read the documentation for the library online at: