├── ISDC2022_Workshops ├── Icons │ ├── package.order │ ├── package.mo │ ├── Plane.mo │ ├── People.mo │ └── Passengers.mo ├── UsersGuide │ ├── package.order │ ├── package.mo │ ├── References.mo │ ├── Contact.mo │ └── Licence.mo ├── package.order ├── Components │ ├── package.order │ ├── package.mo │ ├── ServiceQuality.mo │ ├── HiringPolicy.mo │ ├── Fleet.mo │ ├── Staff.mo │ └── Passengers.mo ├── Resources │ ├── PDF │ │ ├── POSTER.pdf │ │ └── ISDC2022_WS231.pdf │ └── Images │ │ ├── UsersGuide │ │ └── Contact │ │ │ ├── bslFullLogo.png │ │ │ └── ContactInformation.png │ │ ├── Examples │ │ └── PeopleExpress │ │ │ └── BaseRun │ │ │ └── ModelSketch.png │ │ └── Icons │ │ ├── Plane │ │ └── Icon.svg │ │ ├── Journal │ │ └── Icon.svg │ │ ├── Stars │ │ └── Icon.svg │ │ ├── Calculator │ │ └── Icon.svg │ │ ├── People │ │ └── Icon.svg │ │ ├── AirMarket │ │ └── Icon.svg │ │ ├── Airline │ │ └── Icon.svg │ │ └── Passengers │ │ └── Icon.svg ├── Interfaces │ ├── package.order │ ├── Staff.mo │ ├── Fleet.mo │ ├── Passengers.mo │ ├── package.mo │ ├── PeopleExpressSimulationRun.mo │ ├── Subsystem.mo │ ├── IO.mo │ └── PeopleExpressParameters.mo ├── Examples │ ├── PeopleExpress │ │ ├── package.order │ │ ├── RunWithExogenousInputs.mo │ │ ├── package.mo │ │ ├── TestPassengers_1.mo │ │ ├── TestStaff_2.mo │ │ ├── TestStaff_1.mo │ │ ├── TestFleet_2.mo │ │ ├── TestFleet_1.mo │ │ ├── BaseRun.mo │ │ ├── WorkingWithUnits.mo │ │ └── LookupFunctions.mo │ ├── package.order │ ├── package.mo │ ├── TeaCupTextual.mo │ ├── TeaCupComponentBased3.mo │ ├── TeaCupPhysical1.mo │ ├── TeaCupComponentBased2S.mo │ ├── TeaCupComponentBased1S.mo │ ├── TeaCupComponentBased1.mo │ ├── TeaCupComponentBased2.mo │ └── TeaCupPhysical2.mo └── package.mo ├── README.md └── LICENSE.md /ISDC2022_Workshops/Icons/package.order: -------------------------------------------------------------------------------- 1 | Passengers 2 | People 3 | Plane 4 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/UsersGuide/package.order: -------------------------------------------------------------------------------- 1 | Licence 2 | References 3 | Contact 4 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/package.order: -------------------------------------------------------------------------------- 1 | UsersGuide 2 | Examples 3 | Components 4 | Interfaces 5 | Icons 6 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Components/package.order: -------------------------------------------------------------------------------- 1 | Fleet 2 | Staff 3 | Passengers 4 | HiringPolicy 5 | ServiceQuality 6 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/PDF/POSTER.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bslMS/isdc-2022-workshops/main/ISDC2022_Workshops/Resources/PDF/POSTER.pdf -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/package.order: -------------------------------------------------------------------------------- 1 | PeopleExpressParameters 2 | IO 3 | Subsystem 4 | Fleet 5 | Staff 6 | Passengers 7 | PeopleExpressSimulationRun 8 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/PDF/ISDC2022_WS231.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bslMS/isdc-2022-workshops/main/ISDC2022_Workshops/Resources/PDF/ISDC2022_WS231.pdf -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/UsersGuide/Contact/bslFullLogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bslMS/isdc-2022-workshops/main/ISDC2022_Workshops/Resources/Images/UsersGuide/Contact/bslFullLogo.png -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/UsersGuide/Contact/ContactInformation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bslMS/isdc-2022-workshops/main/ISDC2022_Workshops/Resources/Images/UsersGuide/Contact/ContactInformation.png -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Examples/PeopleExpress/BaseRun/ModelSketch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bslMS/isdc-2022-workshops/main/ISDC2022_Workshops/Resources/Images/Examples/PeopleExpress/BaseRun/ModelSketch.png -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/package.order: -------------------------------------------------------------------------------- 1 | BaseRun 2 | RunWithExogenousInputs 3 | WorkingWithUnits 4 | LookupFunctions 5 | TestFleet_1 6 | TestFleet_2 7 | TestStaff_1 8 | TestStaff_2 9 | TestPassengers_1 10 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/package.order: -------------------------------------------------------------------------------- 1 | TeaCupTextual 2 | TeaCupComponentBased1 3 | TeaCupComponentBased1S 4 | TeaCupComponentBased2 5 | TeaCupComponentBased2S 6 | TeaCupComponentBased3 7 | TeaCupPhysical1 8 | TeaCupPhysical2 9 | PeopleExpress 10 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/RunWithExogenousInputs.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model RunWithExogenousInputs = BaseRun(hasExogenousPrice = true, hasExogenousTravelFrequency = false) "Base run with price and travel frequency being exogenous"; 4 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/Staff.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Interfaces; 2 | 3 | partial model Staff "People Express staff" 4 | extends Interfaces.Subsystem; 5 | extends Icons.People; 6 | annotation(Documentation(info = " 7 |
This information is part of the ISDC2022 Workshops package.
8 |Partial model for staff subsystem.
9 | ")); 10 | end Staff; 11 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/Fleet.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Interfaces; 2 | 3 | partial model Fleet "Aircraft used in operations" 4 | extends Interfaces.Subsystem; 5 | extends Icons.Plane; 6 | annotation(Documentation(info = " 7 |This information is part of the ISDC2022 Workshops package.
8 |Partial model for fleet subsystem.
9 | ")); 10 | end Fleet; 11 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/Passengers.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Interfaces; 2 | 3 | partial model Passengers "People Express staff" 4 | extends Subsystem; 5 | extends Icons.Passengers; 6 | annotation(Documentation(info = " 7 |This information is part of the ISDC2022 Workshops package.
8 |Partial model for passenger subsystem.
9 | ")); 10 | end Passengers; 11 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/Plane/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/package.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops; 2 | 3 | package Examples "Exemplary models" 4 | extends BusinessSimulation.Icons.ExamplesPackage; 5 | annotation(Documentation(info = " 6 |This information is part of the ISDC2022 Workshops package.
7 |This package contains models used as examples in the workshops.
8 |Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the ISDC2022 Workshops package.
7 |This package contains partial classes for extension providing icons.
8 |Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the ISDC2022 Workshops package.
7 |This package contains partial models and connectors.
8 |Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the ISDC2022 Workshops package.
7 |This package contains subsystems and molecules to be used in models.
8 |Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the ISDC2022 Workshops package.
6 |Partial model providing icon for extension.
7 | "), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Bitmap(visible = true, fileName = "modelica://ISDC2022_Workshops.Icons.Plane/../Resources/Images/Icons/Plane/Icon.svg", imageSource = "", extent = {{-70, -70}, {70, 70}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 8 | end Plane; 9 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Icons/People.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Icons; 2 | 3 | partial model People "Partial model providing icon" 4 | annotation(Documentation(info = " 5 |This information is part of the ISDC2022 Workshops package.
6 |Partial model providing icon for extension.
7 | "), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Bitmap(visible = true, fileName = "modelica://ISDC2022_Workshops.Icons.Plane/../Resources/Images/Icons/People/Icon.svg", imageSource = "", extent = {{-70, -70}, {70, 70}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 8 | end People; 9 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Icons/Passengers.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Icons; 2 | 3 | partial model Passengers "Partial model providing icon" 4 | annotation(Documentation(info = " 5 |This information is part of the ISDC2022 Workshops package.
6 |Partial model providing icon for extension.
7 | "), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Bitmap(visible = true, fileName = "modelica://ISDC2022_Workshops.Icons.Plane/../Resources/Images/Icons/Passengers/Icon.svg", imageSource = "", extent = {{-70, -70}, {70, 70}})}), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 8 | end Passengers; 9 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/UsersGuide/package.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops; 2 | 3 | package UsersGuide "User's guide to the support material for the ISDC 2022 paper on hierarchical modeling" 4 | extends BusinessSimulation.Icons.Info; 5 | annotation(Documentation(info = " 6 |This information is part of the ISDC2022 Workshops package.
7 |This package contains the license (aka licence) and contact information.
8 |Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later
This information is part of the ISDC2022 Workshops package.
7 |This package shows the development of a larger model from subsystem models losely following the stylized example given by John Morecroft [1] [2], which tries to give an endogenous explanation for the spectacular demise of People Express, a US low-cost airline.
8 | "), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, textColor = {255, 255, 255}, extent = {{-87.106, -30}, {87.106, 30}}, textString = "PEX", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); 9 | end PeopleExpress; 10 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/Calculator/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/Subsystem.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Interfaces; 2 | 3 | partial model Subsystem "Partial subsystem model" 4 | import BusinessSimulation.ModelSettings; 5 | extends BusinessSimulation.Icons.SubsystemTransceiver; 6 | IO io "Information exchange" annotation(Placement(visible = true, transformation(origin = {-0, 105}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {0, 100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab annotation(Placement(visible = true, transformation(origin = {10, 97.53}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); 8 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab1 annotation(Placement(visible = true, transformation(origin = {-10, 98.416}, extent = {{-10, -10}, {10, 10}}, rotation = -450))); 9 | // outer ModelSettings modelSettings "Make model settings available in a subsystem"; 10 | annotation(Documentation(info = " 11 |This information is part of the ISDC2022 Workshops package.
12 |Partial subsystem class for extension.
13 | ")); 14 | end Subsystem; 15 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/IO.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Interfaces; 2 | 3 | expandable connector IO "Information exchange between subsystems" 4 | import BusinessSimulation.Units.{Time,Rate,AmountRate,Fraction,Amount}; 5 | extends BusinessSimulation.Interfaces.Connectors.DataBus; 6 | // fleet output 7 | Real aircraft "Planes"; 8 | Rate growthRate(displayUnit = "1/yr") "Growth rate fleet as proxy for company growth rate"; 9 | // staff output 10 | Real totalStaff "Total number of staff employed"; 11 | Fraction serviceQuality "Current quality of service"; 12 | // passengers output 13 | AmountRate potentialPassengerMiles(displayUnit = "billion/yr") "Travel demand"; 14 | AmountRate RPM(displayUnit = "billion/yr") "Revenue passenger miles"; 15 | Real relativeFare "Ratio Peoples' fare to competitors' fare, i.e., less than one is advantageous"; 16 | Amount potentialPassengers(displayUnit = "thousand") "Potential PEX passengers"; 17 | Rate travelFrequency(displayUnit = "1/yr") "Flights per passenger per year"; 18 | Real peoplesFare(unit = "USD/RPM") "USD per revenue passenger mile"; 19 | annotation(Documentation(info = " 20 |This information is part of the ISDC2022 Workshops package.
21 |This is an expandable connector for information exchange between subsystems. All variables that will be exchanged will be predeclared as \"potentially present\".
This information is part of the ISDC2022 Workshops package.
14 |Test example.
15 | ")); 16 | end TestPassengers_1; 17 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/People/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/TestStaff_2.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model TestStaff_2 "6 planes => hiring until staff = 360; 0 RPM => service quality = 1.0" 4 | extends Interfaces.PeopleExpressSimulationRun; 5 | extends BusinessSimulation.Icons.Example; 6 | Interfaces.IO dataExchange "Data bus" annotation(Placement(visible = true, transformation(origin = {0, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {84.449, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.Converters.ConstantConverterRate revenuePassengerMiles(timeBaseString = "year", value(displayUnit = "billion") = 0) "Revenue passenger miles per period" annotation(Placement(visible = true, transformation(origin = {-80, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | Components.Staff staff "Staff subsystem" annotation(Placement(visible = true, transformation(origin = {0, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.ConstantConverter fleetsize(value = 6) "Aircraft in the fleed" annotation(Placement(visible = true, transformation(origin = {-80, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | equation 11 | connect(staff.io, dataExchange) annotation(Line(visible = true, origin = {0, 20}, points = {{0, -20}, {-0, 20}}, color = {0, 0, 128})); 12 | connect(fleetsize.y, dataExchange.aircraft) "input planes" annotation(Line(visible = true, origin = {-38.5, 30}, points = {{-35.5, -10}, {-1.5, -10}, {-1.5, 10}, {38.5, 10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 13 | connect(revenuePassengerMiles.y, dataExchange.RPM) "input RPM" annotation(Line(visible = true, origin = {-43.5, 50}, points = {{-30.5, 10}, {-6.5, 10}, {-6.5, -10}, {43.5, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 14 | annotation(Documentation(info = " 15 |This information is part of the ISDC2022 Workshops package.
16 |Test example.
17 | ")); 18 | end TestStaff_2; 19 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/TestStaff_1.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model TestStaff_1 "No Planes => no hiring; very large RPM => almost zero service quality" 4 | extends Interfaces.PeopleExpressSimulationRun; 5 | extends BusinessSimulation.Icons.Example; 6 | Interfaces.IO dataExchange "Data bus" annotation(Placement(visible = true, transformation(origin = {0, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {84.449, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.Converters.ConstantConverterRate revenuePassengerMiles(redeclare replaceable type ValueType = BusinessSimulation.Units.Amount, timeBaseString = "year", value(displayUnit = "billion") = 10000000000) "Revenue passenger miles per period" annotation(Placement(visible = true, transformation(origin = {-80, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | Components.Staff staff "Staff subsystem" annotation(Placement(visible = true, transformation(origin = {0, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.ConstantConverter fleetsize(value = 0) "Aircraft in the fleed" annotation(Placement(visible = true, transformation(origin = {-80, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | equation 11 | connect(staff.io, dataExchange) annotation(Line(visible = true, origin = {0, 20}, points = {{0, -20}, {-0, 20}}, color = {0, 0, 128})); 12 | connect(fleetsize.y, dataExchange.aircraft) "input planes" annotation(Line(visible = true, origin = {-38.5, 30}, points = {{-35.5, -10}, {-1.5, -10}, {-1.5, 10}, {38.5, 10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 13 | connect(revenuePassengerMiles.y, dataExchange.RPM) "input RPM" annotation(Line(visible = true, origin = {-43.5, 50}, points = {{-30.5, 10}, {-6.5, 10}, {-6.5, -10}, {43.5, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 14 | annotation(Documentation(info = " 15 |This information is part of the ISDC2022 Workshops package.
16 |Test example.
17 | ")); 18 | end TestStaff_1; 19 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupTextual.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupTextual "Textual model for cooling cup" 4 | import BusinessSimulation.Units.{Time,Rate}; 5 | extends BusinessSimulation.Icons.Example; 6 | // parameters 7 | parameter Real initTempCup(unit = "degC") = 90 "Initial temperature in the cup"; 8 | parameter Real tempRoom(unit = "degC") = 20 "Temperature in the room"; 9 | parameter Time adjTime(displayUnit = "min") = 600 "Time constant for adjustment process"; 10 | // stock & flow variables 11 | Real tempCup(start = initTempCup, unit = "degC") "Temperature in the cup is modeled as a stock"; 12 | Rate heatFlow(displayUnit = "1/min") "Outflow of heat from the cup"; 13 | equation 14 | heatFlow = (tempRoom - tempCup) / adjTime; 15 | der(tempCup) = heatFlow; 16 | annotation(Documentation(info = " 17 |This information is part of the ISDC2022 Workshops package.
18 |19 | This is a stylized model of heat loss for a cup of tea. The model given here is textual only, e.g., there are no components with connections. 20 |
21 |
22 | The temperature in the cup is modeled as a stock (tempCup) with a flow (heatFlow). The outflow of heat, i.e., a negative flow of heat, can be obtained as (tempRoom - tempCup)/adjTime.
23 |
This information is part of the ISDC2022 Workshops package.
6 || [1] | 10 |
11 | J.D.W. Morecroft, \"System Dynamics, RBV and Behavioural Theories of Firm Performance: 12 | Lessons from People Express,\" Proceedings of the 26th International Conference of the System Dynamics Society, 2008. Available: https://wolfr.am/15Pmnbc8j 13 | |
14 |
| [2] | 17 |
18 | J.D.W. Morecroft, Strategic modelling and business dynamics: A feedback systems approach, 2nd ed. Chichester, UK: John Wiley & Sons, 2008. 19 | |
20 |
This information is part of the ISDC 2022 Workshops package.
5 |This package contains material for workshops #231 and #232 at the 40th International System Dynamics Conference (ISDC 2022) in Frankfurt, Germany.
6 |
10 |
11 |
12 |
Copyright © 2022 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.
18 |Modelica© is a registered trademark of the Modelica Association.
19 | "), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, origin = {0, 20}, textColor = {255, 255, 255}, extent = {{-87.106, -30}, {87.106, 30}}, textString = "ISDC", fontName = "Lato Black", textStyle = {TextStyle.Bold}), Text(visible = true, origin = {0, -30}, textColor = {255, 255, 255}, extent = {{-87.106, -20}, {87.106, 25}}, textString = "2022", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); 20 | end ISDC2022_Workshops; 21 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/UsersGuide/Contact.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.UsersGuide; 2 | 3 | final class Contact "Contact Information" 4 | annotation(Documentation(info = " 5 |This information is part of the ISDC 2022 Workshops package.
6 |This page contains the contact information for the package's main author.
11 |
| Name 21 | | Guido Wolf Reichert | 22 |
| Address |
25 |
26 |
27 | Schauenburgerstr. 116
28 | |
33 |
| Phone | 36 |+49 431 90898902 | 37 |
| Fax | 40 |+49 431 90898903 | 41 |
| gwr@bsl-support.de | 45 ||
| Web | 48 |https://www.bsl-support.de | 49 |
This information is part of the ISDC2022 Workshops package.
21 |If there are no passengers, then the fleet size should remain at its initial value.
22 | ")); 23 | end TestFleet_2; 24 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupComponentBased3.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupComponentBased3 "Component-based version of the tea cup model (smooth)" 4 | extends BusinessSimulation.Icons.Example; 5 | inner BusinessSimulation.ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.minutes, modelTimeHorizon(displayUnit = "min") = 3600, dt(displayUnit = "min") = 15) annotation(Placement(visible = true, transformation(origin = {-40, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 6 | BusinessSimulation.Converters.ConstantConverter tempRoom(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), value = 20) "Room temperature" annotation(Placement(visible = true, transformation(origin = {-40, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.Converters.ConstantConverterTime adjTime(value(displayUnit = "min") = 1200) "Time constant for the cooling process" annotation(Placement(visible = true, transformation(origin = {-20, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | BusinessSimulation.Converters.DiscreteDelay.Smooth tempCup(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), initialValue = 90, hasConstantDelayTime = false) "Temperature of tea in the cup" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | equation 10 | connect(adjTime.y, tempCup.u_delayTime) annotation(Line(visible = true, origin = {-4.667, 15}, points = {{-9.333, 5}, {4.667, 5}, {4.667, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 11 | connect(tempRoom.y, tempCup.u) annotation(Line(visible = true, origin = {-21.681, 0}, points = {{-12.319, 0}, {12.319, 0}}, color = {1, 37, 163})); 12 | annotation(Documentation(info = " 13 |This information is part of the ISDC2022 Workshops package.
14 |
15 | In this component-based version of the TeaCup model we are modeling the cooling process rather compactly as a first-order exponential smooth. All we need is the room temperature (tempRoom) and the adjustment time (adjTime).
16 |
19 | TeaCupTextual 20 |
21 | ", figures = {Figure(title = "Temperature", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup.y)}, __Wolfram_markerAppearances = {MarkerAppearance(marker = "d3d94"), MarkerAppearance(marker = "e4da3")})}, caption = "Tea cup cooling down to room temperature", __Wolfram_markers = {Marker(identifier = "e4da3", position = MarkerPosition(x = 300, xUnit = "s")), Marker(identifier = "d3d94", position = MarkerPosition(x = 600, xUnit = "s"))}, __Wolfram_intervals = {Interval(identifier = "556e0", startMarker = "e4da3", endMarker = "d3d94")})}), experiment(StopTime = 3600, __Wolfram_DisplayTimeUnit = "min"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 22 | end TeaCupComponentBased3; 23 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/Airline/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/Passengers/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/TestFleet_1.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model TestFleet_1 "Full planes at all times means we see unrestricted exponential growth" 4 | extends Interfaces.PeopleExpressSimulationRun; 5 | extends BusinessSimulation.Icons.Example; 6 | parameter BusinessSimulation.Units.TangibleAssets initAC = 3 "Initial number of aircraft (fleet.initAC)"; 7 | parameter BusinessSimulation.Units.Rate growthTarget(displayUnit = "1/yr") = 3.17097919837646e-09 "Growth rate envisoned by Don Burr (fleet.growthTarget)"; 8 | BusinessSimulation.Interfaces.Connectors.RealOutput y "Model output: aircraft" annotation(Placement(visible = true, transformation(origin = {90, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {61.898, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.Interfaces.Connectors.RealOutput y_ctrl "Control output: aircraft" annotation(Placement(visible = true, transformation(origin = {90, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {60, -50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | protected 11 | Components.Fleet fleet(initAC = initAC, growthTarget = growthTarget) "The fleet subsystem" annotation(Placement(visible = true, transformation(origin = {0, 10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 12 | Interfaces.IO dataExchange "Data bus" annotation(Placement(visible = true, transformation(origin = {0, 40}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {84.449, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 13 | BusinessSimulation.Converters.ConstantConverterRate potentialPassengerMiles(redeclare replaceable type ValueType = BusinessSimulation.Units.Amount, timeBaseString = "year", value(displayUnit = "billion") = 10000000000) "Have very large number, so that loadFactor is always one" annotation(Placement(visible = true, transformation(origin = {-40, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 14 | BusinessSimulation.Stocks.InformationLevel ctrlAircraft(initialValue = initAC) "control stock" annotation(Placement(visible = true, transformation(origin = {0, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 15 | BusinessSimulation.SourcesOrSinks.ExponentialGrowth ctrlPurchasing(hasConstantRate = true, fractionalRate = growthTarget) "Control flow" annotation(Placement(visible = true, transformation(origin = {-40, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 16 | equation 17 | connect(fleet.io, dataExchange) annotation(Line(visible = true, origin = {0, 30}, points = {{0, -10}, {0, 10}}, color = {0, 0, 128})); 18 | connect(potentialPassengerMiles.y, dataExchange.potentialPassengerMiles) annotation(Line(visible = true, origin = {-17, 40}, points = {{-17, 0}, {17, 0}}, color = {1, 37, 163})); 19 | connect(ctrlPurchasing.massPort, ctrlAircraft.inflow) annotation(Line(visible = true, origin = {-20, -40}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 20 | connect(ctrlAircraft.y, y_ctrl) annotation(Line(visible = true, origin = {33.333, -23.2}, points = {{-28.333, -6.4}, {-28.333, 3.2}, {56.667, 3.2}}, color = {1, 37, 163})); 21 | connect(dataExchange.aircraft, y) "output aircraft" annotation(Line(visible = true, origin = {42.5, 30}, points = {{-42.5, 10}, {-2.5, 10}, {-2.5, 10}, {47.5, 10}}, color = {0, 0, 128})); 22 | annotation(Documentation(info = " 23 |This information is part of the ISDC2022 Workshops package.
24 |This test should show, that in the case of loadFactor being 1.0 the fleet should simply show exponential growth at the rate envision by the CEO.
This information is part of the ISDC2022 Workshops package.
20 |Given a comfortable capacity of revenue passenger miles that can be serviced by the available staff, the ratio of the service capacity to the actual revenue passenger miles is clipped to the unit interval, so that a value of one indicates optimal quality, while zero means no service capability whatsoever.
21 |23 | Staff 24 |
25 | "), 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 = "QUALITY", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); 26 | end ServiceQuality; 27 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupPhysical1.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupPhysical1 "Physical version of the tea cup model (conductive heat transfer only)" 4 | import Modelica.SIunits.{Mass,SpecificHeatCapacity,Length,ThermalConductivity,ThermalConductance}; 5 | import Modelica.Constants.pi; 6 | extends BusinessSimulation.Icons.Example; 7 | // parameters 8 | parameter Mass m(displayUnit = "g") = 0.25 "Mass of tea in the cup" annotation(Dialog(group = "Specification for hot liquid in the cup")); 9 | parameter SpecificHeatCapacity c_p = 4181 "Specific heat capacity for liquid water/tea" annotation(Dialog(group = "Specification for hot liquid in the cup")); 10 | parameter Length d(displayUnit = "cm") = 0.07 "Outer diameter of cup" annotation(Dialog(group = "Specification of cup")); 11 | parameter Length h(displayUnit = "cm") = 0.09 "Height of cup" annotation(Dialog(group = "Specification of cup")); 12 | parameter Length t(displayUnit = "mm") = 0.003 "Thickness of cup" annotation(Dialog(group = "Specification of cup")); 13 | parameter ThermalConductivity k = 1.5 "Thermal conductivity of cup material (e.g., porcelain = 1.5 [W/m.k])" annotation(Dialog(group = "Specification of cup")); 14 | // components 15 | Modelica.Thermal.HeatTransfer.Components.HeatCapacitor teaCup(T.start = 363.15, C = m * c_p, der_T.start = 0) "Tea cup model" annotation(Placement(visible = true, transformation(origin = {-40, 20}, extent = {{-10, -10}, {10, 10}}, rotation = -360))); 16 | Modelica.Thermal.HeatTransfer.Celsius.FixedTemperature tempRoom(T = 20) "Room temperature" annotation(Placement(visible = true, transformation(origin = {50, -30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 17 | Modelica.Thermal.HeatTransfer.Celsius.TemperatureSensor tempCup "Temperature of tea in the cup" annotation(Placement(visible = true, transformation(origin = {27.866, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 18 | Modelica.Thermal.HeatTransfer.Components.ThermalConductor conduction(G = G_cup) "Conductive heatflow according to the surface, thickness, and conductivity of the cup" annotation(Placement(visible = true, transformation(origin = {0, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 19 | protected 20 | parameter ThermalConductance G_cup = 2 * pi * k * h / log(d / (d - 2 * t)) "Thermal conductance of cup" annotation(Dialog(group = "Specification of cup", enable = false)); 21 | equation 22 | connect(teaCup.port, tempCup.port) annotation(Line(visible = true, origin = {-24.583, 14.386}, points = {{-15.417, -4.386}, {-15.417, -14.386}, {24.583, -14.386}, {24.583, 15.614}, {42.449, 15.614}}, color = {191, 0, 0})); 23 | connect(teaCup.port, conduction.port_a) annotation(Line(visible = true, origin = {-30, -16.667}, points = {{-10, 26.667}, {-10, -13.333}, {20, -13.333}}, color = {191, 0, 0})); 24 | connect(conduction.port_b, tempRoom.port) annotation(Line(visible = true, origin = {25, -30}, points = {{-15, 0}, {15, 0}}, color = {191, 0, 0})); 25 | annotation(experiment(StopTime = 3600, __Wolfram_DisplayTimeUnit = "min"), Documentation(info = " 26 |This information is part of the ISDC2022 Workshops package.
27 |
28 | In this component-based version of the TeaCup model we are using components from the Thermal package of the Modelica Standard Library (MSL) to come up with a rather simplified model of a heat capacitator, i.e., the tea in the cup, which is losing heat via conduction to the air in the room. The rate of the heat flow is implicitly determined by the thermal conductance of the cup, which is calculated from elementary properties of the cup. In a physical model we typically need sensors to report quantities and in this model we are using a thermometer to report the intensive quantity tempCup.
29 |
32 | TeaCupTextual, 33 | TeaCupComponentBased5 34 |
35 | ", figures = {Figure(title = "Temperature", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup.T)})}, caption = "The temperature in the cup.")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 36 | end TeaCupPhysical1; 37 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupComponentBased2S.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupComponentBased2S "Component-based version of the tea cup model (bidirectional sink)" 4 | extends BusinessSimulation.Icons.Example; 5 | inner BusinessSimulation.ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.minutes, modelTimeHorizon(displayUnit = "min") = 3600, dt(displayUnit = "min") = 15) annotation(Placement(visible = true, transformation(origin = {-40, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 6 | BusinessSimulation.Stocks.InformationLevel tempCup(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), initialValue = 90) "Temperature of tea in a cup" annotation(Placement(visible = true, transformation(origin = {0, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.Converters.ConstantConverter tempRoom(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), value = 20) "Room temperature" annotation(Placement(visible = true, transformation(origin = {-60, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | BusinessSimulation.Converters.Gap tempDifference "Room temperature minus the temperature of the tea" annotation(Placement(visible = true, transformation(origin = {-20, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.Division heatFlow "Heatflow rate" annotation(Placement(visible = true, transformation(origin = {15, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | BusinessSimulation.Converters.ConstantConverterTime adjTime(value(displayUnit = "min") = 1200) "Time constant for the cooling process" annotation(Placement(visible = true, transformation(origin = {-20, -18.283}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 11 | BusinessSimulation.SourcesOrSinks.ExogenousChange changing "Flow of heat to or from the cup" annotation(Placement(visible = true, transformation(origin = {40, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 12 | equation 13 | connect(tempDifference.y, heatFlow.u1) annotation(Line(visible = true, origin = {-3.75, 12.5}, points = {{-8.25, 7.5}, {-1.25, 7.5}, {-1.25, -7.5}, {10.75, -7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 14 | connect(adjTime.y, heatFlow.u2) annotation(Line(visible = true, origin = {-4.25, -11.642}, points = {{-9.75, -6.642}, {-0.75, -6.642}, {-0.75, 6.642}, {11.25, 6.642}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 15 | connect(tempRoom.y, tempDifference.u1) annotation(Line(visible = true, origin = {-43, 32.5}, points = {{-11, 7.5}, {-2, 7.5}, {-2, -7.5}, {15, -7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 16 | connect(tempCup.y2, tempDifference.u2) annotation(Line(visible = true, origin = {-39.625, -15}, points = {{29.125, -30}, {-20.375, -30}, {-20.375, 30}, {11.625, 30}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 17 | connect(heatFlow.y, changing.u) annotation(Line(visible = true, origin = {37.667, -10}, points = {{-14.667, 10}, {7.333, 10}, {7.333, -20}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 18 | connect(tempCup.outflow, changing.massPort) annotation(Line(visible = true, origin = {20, -40}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 19 | annotation(Documentation(info = " 20 |This information is part of the ISDC2022 Workshops package.
21 |
22 | In this component-based version of the TeaCup model we are modeling the outflow from the cup as a biflow (changing) and can thus have all formulae match up with the textual model. This variant combines flow and cloud into a single SourceOrSink component.
23 |
26 | TeaCupTextual, 27 | TeaCupComponentBased2 28 |
29 | ", figures = {Figure(title = "Temperature", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup.y)}, __Wolfram_markerAppearances = {MarkerAppearance(marker = "d3d94"), MarkerAppearance(marker = "e4da3")})}, caption = "Tea cup cooling down to room temperature", __Wolfram_markers = {Marker(identifier = "e4da3", position = MarkerPosition(x = 300, xUnit = "s")), Marker(identifier = "d3d94", position = MarkerPosition(x = 600, xUnit = "s"))}, __Wolfram_intervals = {Interval(identifier = "556e0", startMarker = "e4da3", endMarker = "d3d94")})}), experiment(StopTime = 3600, __Wolfram_DisplayTimeUnit = "min"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 30 | end TeaCupComponentBased2S; 31 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupComponentBased1S.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupComponentBased1S "Component-based version of the tea cup model (unidirectional sink)" 4 | extends BusinessSimulation.Icons.Example; 5 | inner BusinessSimulation.ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.minutes, modelTimeHorizon(displayUnit = "min") = 3600, dt(displayUnit = "min") = 15) annotation(Placement(visible = true, transformation(origin = {-40, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 6 | BusinessSimulation.Stocks.InformationLevel tempCup(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), initialValue = 90) "Temperature of tea in a cup" annotation(Placement(visible = true, transformation(origin = {0, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.Converters.ConstantConverter tempRoom(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), value = 20) "Room temperature" annotation(Placement(visible = true, transformation(origin = {-50, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | BusinessSimulation.Converters.Gap tempDifference "Room temperature minus the temperature of the tea" annotation(Placement(visible = true, transformation(origin = {-20, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.Division heatLoss "Rate for the outflow of heat" annotation(Placement(visible = true, transformation(origin = {15, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | BusinessSimulation.Converters.ConstantConverterTime adjTime(value(displayUnit = "min") = 1200) "Time constant for the cooling process" annotation(Placement(visible = true, transformation(origin = {-20, 1.717}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 11 | BusinessSimulation.SourcesOrSinks.Decline losingHeat "Heatflow from the cup" annotation(Placement(visible = true, transformation(origin = {40, -20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 12 | equation 13 | connect(tempDifference.y, heatLoss.u1) annotation(Line(visible = true, origin = {-3.75, 32.5}, points = {{-8.25, 7.5}, {-1.25, 7.5}, {-1.25, -7.5}, {10.75, -7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 14 | connect(adjTime.y, heatLoss.u2) annotation(Line(visible = true, origin = {-4.25, 8.358}, points = {{-9.75, -6.642}, {-0.75, -6.642}, {-0.75, 6.642}, {11.25, 6.642}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 15 | connect(tempRoom.y, tempDifference.u2) annotation(Line(visible = true, origin = {-35.5, 27.5}, points = {{-8.5, -7.5}, {0.5, -7.5}, {0.5, 7.5}, {7.5, 7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 16 | connect(tempCup.y2, tempDifference.u1) annotation(Line(visible = true, origin = {-45.109, 10}, points = {{34.609, -35}, {-24.891, -35}, {-24.891, 35}, {17.109, 35}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 17 | connect(tempCup.outflow, losingHeat.massPort) annotation(Line(visible = true, origin = {20, -20}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 18 | connect(heatLoss.y, losingHeat.u) annotation(Line(visible = true, origin = {37.667, 10}, points = {{-14.667, 10}, {7.333, 10}, {7.333, -20}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 19 | annotation(Documentation(info = " 20 |This information is part of the ISDC2022 Workshops package.
21 |
22 | In this component-based version of the TeaCup model we are modeling the outflow from the cup as a unidirectional flow (losingHeat). Since in this case the flow is an explicit outflow, we need to modify the equation for heatFlow in the textual model and determine its postive rate as (tempCup - tempRoom)/adjTime. This variant combines flow and cloud into a single SourceOrSink component.
23 |
26 | TeaCupTextual, 27 | TeaCupComponentBased1 28 |
29 | ", figures = {Figure(title = "Temperature", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup.y)}, __Wolfram_markerAppearances = {MarkerAppearance(marker = "d3d94"), MarkerAppearance(marker = "e4da3")})}, caption = "Tea cup cooling down to room temperature", __Wolfram_markers = {Marker(identifier = "e4da3", position = MarkerPosition(x = 300, xUnit = "s")), Marker(identifier = "d3d94", position = MarkerPosition(x = 600, xUnit = "s"))}, __Wolfram_intervals = {Interval(identifier = "556e0", startMarker = "e4da3", endMarker = "d3d94")})}), experiment(StopTime = 3600, __Wolfram_DisplayTimeUnit = "min"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 30 | end TeaCupComponentBased1S; 31 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupComponentBased1.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupComponentBased1 "Component-based version of the tea cup model (unidirectional flow)" 4 | extends BusinessSimulation.Icons.Example; 5 | inner BusinessSimulation.ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.minutes, modelTimeHorizon(displayUnit = "min") = 3600, dt(displayUnit = "min") = 15) annotation(Placement(visible = true, transformation(origin = {-40, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 6 | BusinessSimulation.Stocks.InformationLevel tempCup(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), initialValue = 90) "Temperature of tea in a cup" annotation(Placement(visible = true, transformation(origin = {0, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.Flows.Unidirectional.Transition losingHeat "Heat flow from the cup" annotation(Placement(visible = true, transformation(origin = {40, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | BusinessSimulation.SourcesOrSinks.Cloud cloud "Unlimited heat capacity of ambient" annotation(Placement(visible = true, transformation(origin = {85, -20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.ConstantConverter tempRoom(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), value = 20) "Room temperature" annotation(Placement(visible = true, transformation(origin = {-50, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | BusinessSimulation.Converters.Gap tempDifference "Room temperature minus the temperature of the tea" annotation(Placement(visible = true, transformation(origin = {-20, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 11 | BusinessSimulation.Converters.Division heatLoss "Rate for the outflow of heat" annotation(Placement(visible = true, transformation(origin = {15, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 12 | BusinessSimulation.Converters.ConstantConverterTime adjTime(value(displayUnit = "min") = 1200) "Time constant for the cooling process" annotation(Placement(visible = true, transformation(origin = {-20, 1.717}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 13 | equation 14 | connect(tempCup.outflow, losingHeat.portA) annotation(Line(visible = true, origin = {20, -20}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 15 | connect(losingHeat.portB, cloud.massPort) annotation(Line(visible = true, origin = {62.5, -20}, points = {{-12.5, 0}, {12.5, 0}}, color = {128, 0, 128})); 16 | connect(tempDifference.y, heatLoss.u1) annotation(Line(visible = true, origin = {-3.75, 32.5}, points = {{-8.25, 7.5}, {-1.25, 7.5}, {-1.25, -7.5}, {10.75, -7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 17 | connect(adjTime.y, heatLoss.u2) annotation(Line(visible = true, origin = {-4.25, 8.358}, points = {{-9.75, -6.642}, {-0.75, -6.642}, {-0.75, 6.642}, {11.25, 6.642}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 18 | connect(heatLoss.y, losingHeat.u) annotation(Line(visible = true, origin = {31, 10}, points = {{-8, 10}, {4, 10}, {4, -20}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 19 | connect(tempRoom.y, tempDifference.u2) annotation(Line(visible = true, origin = {-35.5, 27.5}, points = {{-8.5, -7.5}, {0.5, -7.5}, {0.5, 7.5}, {7.5, 7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 20 | connect(tempCup.y2, tempDifference.u1) annotation(Line(visible = true, origin = {-45.109, 10}, points = {{34.609, -35}, {-24.891, -35}, {-24.891, 35}, {17.109, 35}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 21 | annotation(Documentation(info = " 22 |This information is part of the ISDC2022 Workshops package.
23 |
24 | In this component-based version of the TeaCup model we are modeling the outflow from the cup as a unidirectional flow (losingHeat). Since in this case the flow is an explicit outflow, we need to modify the equation for heatFlow in the textual model and determine its postive rate as (tempCup - tempRoom)/adjTime.
25 |
28 | TeaCupTextual, 29 | TeaCupComponentBased1S 30 |
31 | ", figures = {Figure(title = "Temperature", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup.y)}, __Wolfram_markerAppearances = {MarkerAppearance(marker = "d3d94"), MarkerAppearance(marker = "e4da3")})}, caption = "Tea cup cooling down to room temperature", __Wolfram_markers = {Marker(identifier = "e4da3", position = MarkerPosition(x = 300, xUnit = "s")), Marker(identifier = "d3d94", position = MarkerPosition(x = 600, xUnit = "s"))}, __Wolfram_intervals = {Interval(identifier = "556e0", startMarker = "e4da3", endMarker = "d3d94")})}), experiment(StopTime = 3600, __Wolfram_DisplayTimeUnit = "min"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 32 | end TeaCupComponentBased1; 33 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupComponentBased2.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupComponentBased2 "Component-based version of the tea cup model (bidirectional flow)" 4 | extends BusinessSimulation.Icons.Example; 5 | inner BusinessSimulation.ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.minutes, modelTimeHorizon(displayUnit = "min") = 3600, dt(displayUnit = "min") = 15) annotation(Placement(visible = true, transformation(origin = {-40, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 6 | BusinessSimulation.Stocks.InformationLevel tempCup(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), initialValue = 90) "Temperature of tea in a cup" annotation(Placement(visible = true, transformation(origin = {0, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.SourcesOrSinks.Cloud cloud "Unlimited heat capacity of ambient" annotation(Placement(visible = true, transformation(origin = {85, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 8 | BusinessSimulation.Converters.ConstantConverter tempRoom(redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "degC"), value = 20) "Room temperature" annotation(Placement(visible = true, transformation(origin = {-60, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.Gap tempDifference "Room temperature minus the temperature of the tea" annotation(Placement(visible = true, transformation(origin = {-20, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | BusinessSimulation.Converters.Division heatFlow "Heatflow rate" annotation(Placement(visible = true, transformation(origin = {15, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 11 | BusinessSimulation.Converters.ConstantConverterTime adjTime(value(displayUnit = "min") = 1200) "Time constant for the cooling process" annotation(Placement(visible = true, transformation(origin = {-20, -18.283}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 12 | BusinessSimulation.Flows.Bidirectional.Switching changing "Flow of heat to or from the cup" annotation(Placement(visible = true, transformation(origin = {40, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 13 | equation 14 | connect(tempDifference.y, heatFlow.u1) annotation(Line(visible = true, origin = {-3.75, 12.5}, points = {{-8.25, 7.5}, {-1.25, 7.5}, {-1.25, -7.5}, {10.75, -7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 15 | connect(adjTime.y, heatFlow.u2) annotation(Line(visible = true, origin = {-4.25, -11.642}, points = {{-9.75, -6.642}, {-0.75, -6.642}, {-0.75, 6.642}, {11.25, 6.642}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 16 | connect(tempRoom.y, tempDifference.u1) annotation(Line(visible = true, origin = {-43, 32.5}, points = {{-11, 7.5}, {-2, 7.5}, {-2, -7.5}, {15, -7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 17 | connect(tempCup.y2, tempDifference.u2) annotation(Line(visible = true, origin = {-39.625, 5}, points = {{29.125, -50}, {-20.375, -50}, {-20.375, 10}, {11.625, 10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 18 | connect(heatFlow.y, changing.u) annotation(Line(visible = true, origin = {37.667, -10}, points = {{-14.667, 10}, {7.333, 10}, {7.333, -20}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 19 | connect(tempCup.outflow, changing.portB) annotation(Line(visible = true, origin = {20, -40}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 20 | connect(changing.portA, cloud.massPort) annotation(Line(visible = true, origin = {62.5, -40}, points = {{-12.5, 0}, {12.5, 0}}, color = {128, 0, 128})); 21 | annotation(Documentation(info = " 22 |This information is part of the ISDC2022 Workshops package.
23 |
24 | In this component-based version of the TeaCup model we are modeling the outflow from the cup as a biflow (changing) and can thus have all formulae match up with the textual model.
25 |
28 | TeaCupTextual, 29 | TeaCupComponentBased2S 30 |
31 | ", figures = {Figure(title = "Temperature", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup.y)}, __Wolfram_markerAppearances = {MarkerAppearance(marker = "d3d94"), MarkerAppearance(marker = "e4da3")})}, caption = "Tea cup cooling down to room temperature", __Wolfram_markers = {Marker(identifier = "e4da3", position = MarkerPosition(x = 300, xUnit = "s")), Marker(identifier = "d3d94", position = MarkerPosition(x = 600, xUnit = "s"))}, __Wolfram_intervals = {Interval(identifier = "556e0", startMarker = "e4da3", endMarker = "d3d94")})}), experiment(StopTime = 3600, __Wolfram_DisplayTimeUnit = "min"), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, 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 = "... using biflow", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); 32 | end TeaCupComponentBased2; 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
55 |
--------------------------------------------------------------------------------
/ISDC2022_Workshops/Interfaces/PeopleExpressParameters.mo:
--------------------------------------------------------------------------------
1 | within ISDC2022_Workshops.Interfaces;
2 |
3 | encapsulated partial model PeopleExpressParameters "Model parameters"
4 | import BusinessSimulation.Interfaces.Connectors;
5 | import BusinessSimulation.Units.{Rate,AmountRate,Time,Fraction,Amount};
6 | // structural parameters
7 | parameter Boolean hasExogenousPrice = false "= true, if Peoples' fare is given exogenously" annotation(Evaluate = true, Dialog(group = "Structural Parameters"));
8 | parameter Boolean hasExogenousTravelFrequency = false "= true, if travel frequency is to be an exogenous input" annotation(Evaluate = true, Dialog(group = "Structural Parameters"));
9 | // fleet parameters
10 | parameter Rate growthTarget(displayUnit = "1/yr") = 2.21968543886352e-08 "Growth rate envisoned by Don Burr" annotation(Dialog(tab = "Fleet Parameters"));
11 | final parameter Real initialAircraft = 3 "Initial number of aircraft (initAC)" annotation(Dialog(enable = false, tab = "Fleet Parameters"));
12 | // staff parameters: hiring policy
13 | parameter Real maxCapacityMultiple(unit = "staff/plane") = 80 "Maximum capapcity multiplier (MCM), i.e., max #staff per plane" annotation(Dialog(tab = "Staff Parameters", group = "Recruitment"));
14 | parameter Rate recruitingIntensity(displayUnit = "1/yr") = 9.51293759512938e-07 "Recruiting intensity (RI), i.e., job interviews per recruiter per year" annotation(Dialog(tab = "Staff Parameters", group = "Recruitment"));
15 | parameter Amount acceptanceRatio(displayUnit = "percent") = 0.03 "Fraction of applicants accepted (AR)" annotation(Dialog(tab = "Staff Parameters", group = "Recruitment"));
16 | parameter Real fractionInvolvedHiring = 0.15 "Fraction of experienced staff fully involved in hiring (FHI)" annotation(Dialog(tab = "Staff Parameters", group = "Recruitment"));
17 | parameter Real trainingRatio = 0.03 "Experienced staff fully involved in training per recruit (EPR)" annotation(Dialog(tab = "Staff Parameters", group = "Recruitment"));
18 | // staff parameters: service quality
19 | parameter AmountRate serviceProductivity(displayUnit = "million/yr") = 0.0475646879756469 "Service productivity (SP), i.e., revenue passenger miles per service staff and year" annotation(Dialog(tab = "Staff Parameters", group = "Service Quality"));
20 | // staff parameters: stocks
21 | parameter Real initialNewStaff = 0 "Initial number of new staff (initNS)" annotation(Dialog(enable = false, tab = "Staff Parameters", group = "Initial Values Stocks"));
22 | parameter Real initialExperiencedStaff = 200 " Initial number of experienced staff (initES)" annotation(Dialog(enable = false, tab = "Staff Parameters", group = "Initial Values Stocks"));
23 | // passengers parameters
24 | parameter Real initialFareCompetition(unit = "USD/RPM") = 0.25 "Initial fare for competition (ICF)" annotation(Dialog(tab = "PAX Parameters", group = "Winning Passengers"));
25 | parameter Real initialPeoplesFare(unit = "USD/RPM") = 0.09 "Initial peoples' fare (IPF)" annotation(Dialog(enable = not hasExogenousPrice, tab = "PAX Parameters", group = "Winning Passengers"));
26 | parameter Real finalPeoplesFare(unit = "USD/RPM") = 0.09 "Final peoples' fare (FPF)" annotation(Dialog(enable = not hasExogenousPrice, tab = "PAX Parameters", group = "Winning Passengers"));
27 | parameter Time pricePolicyStartTime(displayUnit = "yr") = 62472816000 "Start time for ramping up or down fares (PPST)" annotation(Dialog(enable = not hasExogenousPrice, tab = "PAX Parameters", group = "Winning Passengers"));
28 | parameter Time pricePolicyDuration(displayUnit = "yr") = 0 "Duration of price adaptation (PPD)" annotation(Dialog(enable = not hasExogenousPrice, tab = "PAX Parameters", group = "Winning Passengers"));
29 | parameter Time adjustmentTimePrice(displayUnit = "yr") = 126144000 "Time to adjust costs and fare to peoples (ATP)" annotation(Dialog(tab = "PAX Parameters", group = "Winning Passengers"));
30 | parameter Time timeToPerceiveServiceQuality(displayUnit = "yr") = 31536000 "Time to perceive service quality (TTP)" annotation(Dialog(tab = "PAX Parameters", group = "Losing Passengers"));
31 | parameter Real milesPerFlight(unit = "miles") = 800 "Average distance travelled per passenger and flight (MPF)" annotation(Dialog(tab = "PAX Parameters", group = "Utilization"));
32 | parameter Rate flightsPerYear(displayUnit = "1/yr") = 1.26839167935058e-07 "Average number of flights per passenger and year (FPY)" annotation(Dialog(enable = not hasExogenousTravelFrequency, tab = "PAX Parameters", group = "Utilization"));
33 | parameter Amount initialPotentialPassengers(displayUnit = "thousand") = 180e3 "Initial number of potential passengers (initPP)" annotation(Dialog(enable = false, tab = "PAX Parameters", group = "Initial Value Stocks"));
34 | Connectors.RealInput u_peoplesFare if hasExogenousPrice "USD per revenue passenger mile" 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)));
35 | Connectors.RealInput u_travelFrequency if hasExogenousTravelFrequency "Flights per passenger per year" 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 = -90)));
36 | annotation(experiment(StartTime = 62472816000, StopTime = 62693568000, __Wolfram_DisplayTimeUnit = "yr"), 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, fillColor = {255, 255, 255}, pattern = LinePattern.None, extent = {{-100, -100}, {100, 100}})}));
37 | end PeopleExpressParameters;
38 |
--------------------------------------------------------------------------------
/ISDC2022_Workshops/Components/HiringPolicy.mo:
--------------------------------------------------------------------------------
1 | within ISDC2022_Workshops.Components;
2 |
3 | block HiringPolicy "Setting the hiring rate"
4 | extends BusinessSimulation.Interfaces.PartialConverters.Policy_SO;
5 | parameter Real MCM(unit = "people") = 60 "Maximum capapcity multiplier, i.e., max staff per plane";
6 | parameter BusinessSimulation.Units.Rate RI(displayUnit = "1/yr") = 9.51293759512938e-07 "Recruiting intensity, i.e., job interviews per recruiter per year";
7 | parameter BusinessSimulation.Units.Amount AR(displayUnit = "percent") = 0.03 "Fraction of applicants accepted";
8 | BusinessSimulation.Interfaces.Connectors.RealInput planes "Number of aircraft in the fleet" 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)));
9 | BusinessSimulation.Interfaces.Connectors.RealInput recruiters "Staff available for screening candidates" 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)));
10 | BusinessSimulation.Interfaces.Connectors.RealInput totalStaff "Total staff currently employed" 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)));
11 | BusinessSimulation.Converters.Product_2 maxCapacity "Maximum capacity for staff" annotation(Placement(visible = true, transformation(origin = {-60, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
12 | BusinessSimulation.Converters.ConstantConverter maxStaffPerPlane(value = MCM) "Maximum staff per plane" annotation(Placement(visible = true, transformation(origin = {-110, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
13 | BusinessSimulation.Converters.Logical.Less belowLimitQ "True, if total staff below limit on staff" annotation(Placement(visible = true, transformation(origin = {40, 20}, extent = {{-10, 10}, {10, -10}}, rotation = 0)));
14 | BusinessSimulation.Converters.ConstantConverterRate noHiring(timeBaseString = "year", value = 0) "Zero hiring rate" annotation(Placement(visible = true, transformation(origin = {40, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
15 | BusinessSimulation.Converters.Logical.Switch hiringRate(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate) annotation(Placement(visible = true, transformation(origin = {80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = -360)));
16 | BusinessSimulation.Converters.ConstantConverter recruitingLoad(value = RI) "Job interview rate per recruiter" annotation(Placement(visible = true, transformation(origin = {-120, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
17 | BusinessSimulation.Converters.Product_2 interviewRate(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate) "Job interviews per period" annotation(Placement(visible = true, transformation(origin = {-80, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
18 | BusinessSimulation.Converters.ConstantConverter acceptedFraction(value = AR) "Fraction of applicants accepted" annotation(Placement(visible = true, transformation(origin = {-70, 15}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
19 | BusinessSimulation.Converters.Product_2 unrestrictedHiringRate(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate) "Hiring rate before taking capacity restrictions into account" annotation(Placement(visible = true, transformation(origin = {-32.465, 5}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
20 | equation
21 | connect(planes, maxCapacity.u1) annotation(Line(visible = true, origin = {-118.494, 50}, points = {{-26.506, 10}, {15.636, 10}, {15.636, -5}, {50.494, -5}}, color = {0, 0, 128}, smooth = Smooth.Bezier));
22 | connect(maxStaffPerPlane.y, maxCapacity.u2) annotation(Line(visible = true, origin = {-90.045, 27.5}, points = {{-13.955, -7.5}, {5.045, -7.5}, {5.045, 7.5}, {22.045, 7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier));
23 | connect(totalStaff, belowLimitQ.u1) annotation(Line(visible = true, origin = {-18.25, -12.5}, points = {{-126.75, -47.5}, {5.103, -47.5}, {5.103, 27.5}, {50.25, 27.5}}, color = {0, 0, 128}, smooth = Smooth.Bezier));
24 | connect(maxCapacity.y, belowLimitQ.u2) annotation(Line(visible = true, origin = {-5, 32.5}, points = {{-47, 7.5}, {5, 7.5}, {5, -7.5}, {37, -7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier));
25 | connect(hiringRate.y, y) annotation(Line(visible = true, origin = {124, 0}, points = {{-36, 0}, {36, -0}}, color = {1, 37, 163}));
26 | connect(belowLimitQ.y, hiringRate.u_cond) annotation(Line(visible = true, origin = {69.341, 15.996}, points = {{-21.341, 4.004}, {10.671, 4.004}, {10.671, -8.008}}, color = {190, 52, 178}, smooth = Smooth.Bezier));
27 | connect(noHiring.y, hiringRate.u2) annotation(Line(visible = true, origin = {62, -17.5}, points = {{-16, -12.5}, {-2, -12.5}, {-2, 12.5}, {10, 12.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier));
28 | connect(recruiters, interviewRate.u1) annotation(Line(visible = true, origin = {-113.25, -7.5}, points = {{-31.75, 7.5}, {3.25, 7.5}, {3.25, -7.5}, {25.25, -7.5}}, color = {0, 0, 128}, smooth = Smooth.Bezier));
29 | connect(recruitingLoad.y, interviewRate.u2) annotation(Line(visible = true, origin = {-103, -32.5}, points = {{-11, -7.5}, {-2, -7.5}, {-2, 7.5}, {15, 7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier));
30 | connect(acceptedFraction.y, unrestrictedHiringRate.u1) annotation(Line(visible = true, origin = {-53.616, 12.5}, points = {{-10.384, 2.5}, {-1.384, 2.5}, {-1.384, -2.5}, {13.151, -2.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier));
31 | connect(interviewRate.y, unrestrictedHiringRate.u2) annotation(Line(visible = true, origin = {-59.609, -12.5}, points = {{-12.391, -7.5}, {-0.391, -7.5}, {-0.391, 12.5}, {19.144, 12.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier));
32 | connect(unrestrictedHiringRate.y, hiringRate.u1) annotation(Line(visible = true, origin = {22.5, 2.5}, points = {{-46.965, 2.5}, {-2.5, 2.5}, {-2.5, 2.5}, {49.5, 2.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier));
33 | annotation(Documentation(info = "
34 |
This information is part of the ISDC2022 Workshops package.
35 |Hiring in People Express is almost entirely driven by the size of the experienced workforce, which needs to interview candidates. PEX prides itself not to fire staff—unless proven incompetent—and will not hire more than needed, which here is checked with regard to a multiple of the current fleet size.
36 |38 | Staff 39 |
40 | "), 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 = "RECRUITING", fontName = "Lato Black", textStyle = {TextStyle.Bold})})); 41 | end HiringPolicy; 42 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/BaseRun.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model BaseRun "Basic model for PEX dynamics" 4 | extends Interfaces.PeopleExpressSimulationRun; 5 | extends Interfaces.PeopleExpressParameters(hasExogenousPrice = false, hasExogenousTravelFrequency = false); 6 | extends BusinessSimulation.Icons.SimulationModel; 7 | Interfaces.IO dataExchange "Hub for exchanging information between subsystems" annotation(Placement(visible = true, transformation(origin = {-3.037, 82.915}, extent = {{-20, -20}, {20, 20}}, rotation = 0), iconTransformation(origin = {0, 100}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | protected 9 | Components.Fleet fleet(growthTarget = growthTarget, initAC = initialAircraft) "PEX fleet subsystem" annotation(Placement(visible = true, transformation(origin = {-92.639, 65}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | Components.Staff staff(initNS = initialNewStaff, initES = initialExperiencedStaff, SP = serviceProductivity, MCM = maxCapacityMultiple, RI = recruitingIntensity, AR = acceptanceRatio, FHI = fractionInvolvedHiring, EPR = trainingRatio) "PEX staff subsystem" annotation(Placement(visible = true, transformation(origin = {-3.037, -6.963}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 11 | Components.Passengers passengers(initPP = initialPotentialPassengers, TTP = timeToPerceiveServiceQuality, ATP = adjustmentTimePrice, ICF = initialFareCompetition, IPF = initialPeoplesFare, FPF = finalPeoplesFare, PPST = pricePolicyStartTime, PPD = pricePolicyDuration, MPF = milesPerFlight, FPY = flightsPerYear, hasExogenousPrice = hasExogenousPrice, hasExogenousTravelFrequency = hasExogenousTravelFrequency) "PEX passenger subsystem" annotation(Placement(visible = true, transformation(origin = {95, 66.902}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 12 | equation 13 | connect(dataExchange, staff.io) annotation(Line(visible = true, origin = {-3.037, 42.976}, points = {{0, 39.939}, {0, -39.939}}, color = {0, 0, 128})); 14 | connect(dataExchange, passengers.io) annotation(Line(visible = true, origin = {62.321, 80.911}, points = {{-65.358, 2.004}, {32.679, 2.004}, {32.679, -4.009}}, color = {0, 0, 128})); 15 | connect(dataExchange, fleet.io) annotation(Line(visible = true, origin = {-62.772, 80.277}, points = {{59.735, 2.638}, {-29.867, 2.638}, {-29.867, -5.277}}, color = {0, 0, 128})); 16 | connect(u_peoplesFare, dataExchange.peoplesFare) annotation(Line(visible = true, origin = {-102.585, 71.457}, points = {{-42.415, -11.458}, {-25.842, -11.458}, {-25.842, 11.458}, {99.548, 11.458}}, color = {0, 0, 128})); 17 | connect(u_travelFrequency, dataExchange.travelFrequency) annotation(Line(visible = true, origin = {-102.663, 61.458}, points = {{-42.337, -21.458}, {-25.764, -21.458}, {-25.764, 21.457}, {99.626, 21.457}}, color = {0, 0, 128})); 18 | annotation(Documentation(info = " 19 |This information is part of the ISDC2022 Workshops package.
20 |21 | This stylized interpretation of the People Express model by John Morecroft [1] [2] consists of three subsystems: a fleet, a staff, and a passengers subsystem. 22 |
23 |
25 | Unlike the subsystem-diagram shown in the background, the model uses a central expandable connector as a hub or data bus for information exchange between subsystems. Unlike typical subsystem diagrams there are accordingly no dircted edges used in any connections. There are some reasons to prefer this structure in building large models:
26 |
n (n - 1) connections. This is clearly not advantageous and using a central hub means that we simply have to draw as many connections as there are subsystems and all subsystems will be connected to each other.35 | The background image cpoyright © 1983 by Eduart Marmet shows a People Express Boing 747 at London Gatwick in June 1983 and is licensed CC BY-SA 3.0. 36 |
37 | ", figures = {Figure(title = "Revenue Passenger Miles (RPM)", identifier = "rpm", preferred = true, plots = {Plot(curves = {Curve(y = dataExchange.RPM, legend = "RPM")})}, caption = "People Express Revenue Passenger Miles p.a."), Figure(title = "Fleet Size", identifier = "fleet", plots = {Plot(curves = {Curve(y = dataExchange.aircraft, legend = "aircraft")})}, caption = "The number of planes in the fleet."), Figure(title = "Service Quality", identifier = "quality", plots = {Plot(curves = {Curve(y = dataExchange.serviceQuality, legend = "serviceQuality")})}, caption = "Service quality measured on the unit scale."), Figure(title = "Relative Fare", identifier = "pricing", plots = {Plot(curves = {Curve(y = dataExchange.relativeFare, legend = "relativeFare")})}, caption = "People Express has a price advantage for values below 1."), Figure(title = "Total Staff", identifier = "staff", plots = {Plot(curves = {Curve(y = dataExchange.totalStaff, legend = "totalStaff")})}, caption = "The number of new and experienced staff.")}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Diagram(coordinateSystem(extent = {{-147.5, -83}, {147.5, 83}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Bitmap(visible = true, fileName = "modelica://ISDC2022_Workshops/Resources/Images/Examples/PeopleExpress/BaseRun/ModelSketch.png", imageSource = "", extent = {{-147.5, -83}, {147.5, 83}})})); 38 | end BaseRun; 39 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/WorkingWithUnits.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model WorkingWithUnits "Best practices to work with units in Modelica models" 4 | extends BusinessSimulation.Icons.Example; 5 | inner BusinessSimulation.ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.years, modelTimeHorizon(displayUnit = "yr") = 315360000, dt(displayUnit = "yr") = 7884000) annotation(Placement(visible = true, transformation(origin = {-90, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 6 | BusinessSimulation.Stocks.MaterialStock aircraft(initialValue = 3) "Aircraft of norm size in the fleet" annotation(Placement(visible = true, transformation(origin = {0, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 7 | BusinessSimulation.SourcesOrSinks.ExponentialGrowth growing(hasConstantRate = true, fractionalRate(displayUnit = "1/yr") = 3.17097919837646e-09) annotation(Placement(visible = true, transformation(origin = {-40, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | BusinessSimulation.Converters.Product_3 ASM(redeclare replaceable type OutputType = BusinessSimulation.Units.AmountRate) "Available seat miles" annotation(Placement(visible = true, transformation(origin = {75, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.ConstantConverterRate opDaysPerYear(redeclare replaceable type ValueType = BusinessSimulation.Units.Time_days, value = 31104000, timeBaseString = "year") "Operational days per year" annotation(Placement(visible = true, transformation(origin = {120, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 10 | BusinessSimulation.Converters.ConstantConverterRate carrierCapacity(value = 360e3, timeBaseString = "day", redeclare replaceable type ValueType = BusinessSimulation.Types.Reals(unit = "ASM")) "ASM per plane per day" annotation(Placement(visible = true, transformation(origin = {120, 60}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 11 | BusinessSimulation.Converters.ConstantConverter carrierCapacityReal(value = 360e3, redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "ASM/d")) "Carrier capacity given as Real with explicit units" annotation(Placement(visible = true, transformation(origin = {-90, 85}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 12 | BusinessSimulation.Converters.ConstantConverter opDaysPerYearReal(value = 360, redeclare replaceable type OutputType = BusinessSimulation.Types.Reals(unit = "d/yr")) "Operational days per year given as Real with units" annotation(Placement(visible = true, transformation(origin = {-90, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 13 | BusinessSimulation.Converters.Product_3 ASMReal(redeclare replaceable type OutputType = BusinessSimulation.Units.AmountRate) "Available seat miles" annotation(Placement(visible = true, transformation(origin = {-40, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 14 | equation 15 | connect(growing.massPort, aircraft.inflow) annotation(Line(visible = true, origin = {-20, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 16 | connect(aircraft.y1, ASM.u3) annotation(Line(visible = true, origin = {71.321, -10}, points = {{-60.821, -25}, {28.679, -25}, {28.679, 25}, {11.679, 25}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 17 | connect(opDaysPerYear.y, ASM.u2) annotation(Line(visible = true, origin = {98.5, 20}, points = {{15.5, 0}, {-15.5, 0}}, color = {1, 37, 163})); 18 | connect(carrierCapacity.y, ASM.u1) annotation(Line(visible = true, origin = {100.252, 42.5}, points = {{13.748, 17.5}, {-0.252, 17.5}, {-0.252, -17.5}, {-17.252, -17.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 19 | connect(aircraft.y, ASMReal.u3) annotation(Line(visible = true, origin = {-35.6, 25.721}, points = {{40.6, -45.321}, {40.6, -29.605}, {50.6, -29.605}, {50.6, 2.495}, {-34.4, 2.495}, {-34.4, 29.279}, {-12.4, 29.279}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 20 | connect(opDaysPerYearReal.y, ASMReal.u2) annotation(Line(visible = true, origin = {-66, 60}, points = {{-18, 0}, {18, -0}}, color = {1, 37, 163})); 21 | connect(carrierCapacityReal.y, ASMReal.u1) annotation(Line(visible = true, origin = {-69.878, 75}, points = {{-14.122, 10}, {-0.122, 10}, {-0.122, -10}, {21.878, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 22 | annotation(Documentation(info = " 23 |This information is part of the ISDC2022 Workshops package.
24 |
25 | This example is taken from the Fleet component in the People Express model and nicely shows some intricacies with regard to working with units in Modelica models.
26 |
28 | When we start out to build a model, we can never quite be sure how a variable will eventually be used. While we may work with the following declaration for the variable opDaysPerYear doing so is not robust:
29 |
31 | Real opDaysPerYear(unit = \"days/year\") 32 |33 |
34 | First of all, this is a ratio and it behaves like a rate. Should we use the value later to come up with a rate to be used to set the rate of a flow we may run into difficulties. 35 |
36 |
37 | Modelica allows us to work with different choices for displayUnit doing automatic conversions, while working internally with a consistent canonical unit. For rates the internal unit should always be [1/s] which allows us to enter rates in any derived unit there is, e.g., as [1/mo].
38 |
40 | The ratio opDaysPerYear has a further complication: Dimensionality analysis should quickly convince us that dividing a unit of time by a different unit of time must necessarily result in a dimensionless scalar. Modelica's unit framework will do this for us only, if we explicitly tell it that the nominator has quantity = \"Time\".
41 |
44 | Components.Fleet#diagram 45 |
46 | "), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {55, 64}, textColor = {255, 0, 0}, extent = {{-18.018, -6}, {18.018, 6}}, textString = "Rates", fontName = "Lato"), Line(visible = true, origin = {85.708, 59.92}, points = {{-12.591, 2.275}, {12.591, -2.275}}, color = {255, 0, 0}, arrow = {Arrow.None, Arrow.Filled}), Line(visible = true, origin = {63.974, 42.475}, points = {{-6.026, 14.259}, {6.026, -14.259}}, color = {255, 0, 0}, arrow = {Arrow.None, Arrow.Filled}), Line(visible = true, origin = {88.135, 43.974}, points = {{-20.176, 13.974}, {20.176, -13.974}}, color = {255, 0, 0}, arrow = {Arrow.None, Arrow.Filled}), Text(visible = true, origin = {-71.323, 20}, textColor = {255, 0, 0}, extent = {{-68.677, -6}, {68.677, 6}}, textString = "Work with displayUnit", fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {-33.266, 6}, textColor = {255, 0, 0}, extent = {{-106.734, -6}, {106.734, 6}}, textString = "and keep rates internally consistant at [1/s]", fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {30, -66}, textColor = {255, 0, 0}, extent = {{-110, -6}, {110, 6}}, textString = "Time per Time should give a dimensionless scalar", fontName = "Lato", horizontalAlignment = TextAlignment.Right), Line(visible = true, origin = {120, -25}, points = {{-0, -35}, {0, 35}}, color = {255, 0, 0}, arrow = {Arrow.None, Arrow.Filled}), Polygon(visible = true, origin = {-1.709, 76.877}, rotation = -12.49, lineColor = {255, 0, 0}, fillColor = {255, 0, 0}, fillPattern = FillPattern.Solid, points = {{-8.001, 3.447}, {-20.034, -19.627}, {-9.533, -15.693}, {-14.718, -30.789}, {-0.975, -11.981}, {-12.073, -13.579}, {-4.041, 3.027}})}), experiment(StopTime = 315360000, __Wolfram_DisplayTimeUnit = "yr")); 47 | end WorkingWithUnits; 48 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Components/Fleet.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Components; 2 | 3 | model Fleet "People express fleet" 4 | extends Interfaces.Fleet; 5 | parameter BusinessSimulation.Units.Rate growthTarget(displayUnit = "1/yr") = 3.17097919837646e-09 "Growth rate envisoned by Don Burr"; 6 | parameter BusinessSimulation.Units.TangibleAssets initAC = 3 "Initial number of aircraft"; 7 | protected 8 | BusinessSimulation.Stocks.MaterialStock aircraft(initialValue = initAC) "Aircraft of norm size in the fleet" annotation(Placement(visible = true, transformation(origin = {0, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.SourcesOrSinks.ExponentialChange growing annotation(Placement(visible = true, transformation(origin = {-40, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | BusinessSimulation.Converters.ConstantConverter targetGrowth(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate, value = growthTarget) "Envisioned growth" annotation(Placement(visible = true, transformation(origin = {-120, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 11 | BusinessSimulation.Converters.Product_3 availableSeatMiles(redeclare replaceable type OutputType = BusinessSimulation.Units.AmountRate) "Available seat miles" annotation(Placement(visible = true, transformation(origin = {75, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 12 | BusinessSimulation.Converters.Min revenuePassengerMiles "Revenue passenger miles (RPM)" annotation(Placement(visible = true, transformation(origin = {30, 40}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 13 | BusinessSimulation.Converters.Division_Guarded loadFactor(redeclare replaceable type OutputType = BusinessSimulation.Units.Fraction) "Utilization of seat capacity" annotation(Placement(visible = true, transformation(origin = {-10, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 14 | BusinessSimulation.Converters.ConstantConverterRate opDaysPerYear(redeclare replaceable type ValueType = BusinessSimulation.Units.Time_days, value = 31104000, timeBaseString = "year") "Operational days per year" annotation(Placement(visible = true, transformation(origin = {125, 15}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 15 | BusinessSimulation.Converters.ConstantConverterRate dailyCapacityPerPlane(value(displayUnit = "thousand") = 360000, timeBaseString = "day", redeclare replaceable type ValueType = BusinessSimulation.Units.Amount) "Operational days per ye" annotation(Placement(visible = true, transformation(origin = {115, 48.013}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 16 | BusinessSimulation.Converters.DiscreteDelay.Smooth perceivedLoadFactor(delayTime(displayUnit = "mo") = 7884000, init = BusinessSimulation.Types.InitializationOptions.SteadyState) annotation(Placement(visible = true, transformation(origin = {-40, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 17 | BusinessSimulation.Converters.Lookup.ConcaveLookupPositive adjFactor(y0 = 0, s = 0.2) "Adjustment factor for growth rate" annotation(Placement(visible = true, transformation(origin = {-80, 30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 18 | BusinessSimulation.Converters.Product_2 fracGrowthRate "Fractional growth rate fleet" annotation(Placement(visible = true, transformation(origin = {-80, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 19 | // illustration 20 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab2 annotation(Placement(visible = true, transformation(origin = {-32.37, 62.633}, extent = {{-10, -10}, {10, 10}}, rotation = -360))); 21 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab3 annotation(Placement(visible = true, transformation(origin = {8.394, 50}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); 22 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab4 annotation(Placement(visible = true, transformation(origin = {27.782, 75}, extent = {{-10, -10}, {10, 10}}, rotation = -720))); 23 | equation 24 | connect(growing.massPort, aircraft.inflow) annotation(Line(visible = true, origin = {-20, -30}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 25 | connect(aircraft.y1, availableSeatMiles.u3) annotation(Line(visible = true, origin = {75.029, -15}, points = {{-64.529, -20}, {23.356, -20}, {23.356, 30}, {7.971, 30}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 26 | connect(revenuePassengerMiles.u2, availableSeatMiles.y) annotation(Line(visible = true, origin = {49.127, 27.5}, points = {{-11.127, 7.5}, {2.384, 7.5}, {2.384, -7.5}, {17.873, -7.5}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 27 | connect(revenuePassengerMiles.y, loadFactor.u1) annotation(Line(visible = true, origin = {12.5, 37.5}, points = {{9.5, 2.5}, {2.5, 2.5}, {2.5, -2.5}, {-14.5, -2.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 28 | connect(availableSeatMiles.y, loadFactor.u2) annotation(Line(visible = true, origin = {45.801, 22.5}, points = {{21.199, -2.5}, {-25.801, -2.5}, {-25.801, 2.5}, {-47.801, 2.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 29 | connect(opDaysPerYear.y, availableSeatMiles.u2) annotation(Line(visible = true, origin = {104.699, 17.5}, points = {{14.301, -2.5}, {0.301, -2.5}, {0.301, 2.5}, {-21.699, 2.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 30 | connect(io.potentialPassengerMiles, revenuePassengerMiles.u1) "input potentialPassengerMiles (Rate)" annotation(Line(visible = true, origin = {32, 71}, points = {{-32, 34}, {-32, 9}, {28, 9}, {28, -26}, {6, -26}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 31 | connect(dailyCapacityPerPlane.y, availableSeatMiles.u1) annotation(Line(visible = true, origin = {98, 36.507}, points = {{11, 11.506}, {-3, 11.506}, {-3, -11.507}, {-15, -11.507}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 32 | connect(perceivedLoadFactor.u, loadFactor.y) annotation(Line(visible = true, origin = {-24.319, 30}, points = {{-6.319, 0}, {6.319, 0}}, color = {0, 0, 128})); 33 | connect(perceivedLoadFactor.y, adjFactor.u) annotation(Line(visible = true, origin = {-65.227, 29.203}, points = {{15.227, 0.797}, {-7.613, 0.797}, {-6.773, 0.797}}, color = {1, 37, 163})); 34 | connect(targetGrowth.y, fracGrowthRate.u2) annotation(Line(visible = true, origin = {-102.523, -12.5}, points = {{-11.477, -7.5}, {2.523, -7.5}, {2.523, 7.5}, {14.523, 7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 35 | connect(adjFactor.y, fracGrowthRate.u1) annotation(Line(visible = true, origin = {-94, 17.5}, points = {{6, 12.5}, {-6, 12.5}, {-6, -12.5}, {6, -12.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 36 | connect(fracGrowthRate.y, growing.u) annotation(Line(visible = true, origin = {-54, -6.667}, points = {{-18, 6.667}, {9, 6.667}, {9, -13.333}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 37 | connect(fracGrowthRate.y, io.growthRate) "output fractional growth rate" annotation(Line(visible = true, origin = {-38.4, 45}, points = {{-33.6, -45}, {-21.6, -45}, {-21.6, 15}, {38.4, 15}, {38.4, 60}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 38 | connect(aircraft.y, io.aircraft) annotation(Line(visible = true, origin = {2.083, 51.35}, points = {{2.917, -70.95}, {2.917, 12.02}, {-2.083, 12.02}, {-2.083, 53.65}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 39 | connect(revenuePassengerMiles.y, io.RPM) "output revenue passenger miles (RPM)" annotation(Line(visible = true, origin = {7.333, 61.667}, points = {{14.667, -21.667}, {4.34, -21.667}, {4.34, 10.833}, {-7.333, 10.833}, {-7.333, 43.333}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 40 | annotation(Documentation(info = " 41 |This information is part of the ISDC2022 Workshops package.
42 |The fleet of planes will grow (or decline) at a fractional rate that is determined by CEO Burr's vision, which is modulated by the perceived loadFactor.
This information is part of the ISDC2022 Workshops package.
63 |
64 | In this component-based version of the TeaCup model we are using components from the Thermal package of the Modelica Standard Library (MSL) to come up with a more elaborate model of a heat capacitator, i.e., the tea in the cup, which is losing heat via convective and conductive heat transfer to the air in the room.
65 |
67 | The model uses structural parameters to switch on/off model components, i.e., convective heat flow in the cup, convective heat flow at the top, and body radiation may be accounted for. 68 |
69 |71 | TeaCupTextual, 72 | TeaCupComponentBased4 73 |
74 | ", figures = {Figure(title = "tempCup.T", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup.T)})}, caption = "The temperature in the cup.")}), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 75 | end TeaCupPhysical2; 76 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/LookupFunctions.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model LookupFunctions "Sandbox for lookup-functions" 4 | extends BusinessSimulation.Icons.Example; 5 | ModelOutput modelOutput "The main model output" annotation(Placement(visible = true, transformation(origin = {120, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {80, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 6 | parameter Real slope1To50(min = 1, max = 50) = 2 "Slope parameter (general)"; 7 | parameter Real slope(min = 0) = slope1To50 "Determines the gradient of the curve (Janoschek and S-Shaped)"; 8 | parameter Real slopeUpTo1(min = 0, max = 1) = 0.5 "Slope parameter (0< slope <= 1) (concaveLookupPosisitve)"; 9 | parameter Real interceptUpward(min = 0, max = 1) = 0. "Value of y when input is zero or less (y0) for upward sloping functions"; 10 | parameter Real interceptDownward(min = 1) = 2. "Value of y when input is zero or less (y0) for downward sloping functions"; 11 | parameter Real upperBound = 1 "Upper asymptote for u <= 0 (upperBound > lowerBound) (Janoschek and S-Shaped)"; 12 | parameter Real lowerBound = 0 "Lower asymptote for u -> infinity (Janoschek)"; 13 | parameter Real x_ref(min = 0) = 0.5 "x-value for point of inflection(>0) (Janoschek)"; 14 | parameter Real y_ref = 0.5 "y-value for point of inflection(lowerBound < y_ref < upperBound) (Janoschek)"; 15 | 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)"; 16 | parameter Modelica.Blocks.Types.Smoothness smoothness = Modelica.Blocks.Types.Smoothness.LinearSegments "Smoothness of table interpolation (tableFunction.smoothness)"; 17 | parameter Modelica.Blocks.Types.Extrapolation extrapolation = Modelica.Blocks.Types.Extrapolation.HoldLastPoint "Extrapolation of data outside the definition range (combiTable.extrapolation) (tableFunction.extrapolation)"; 18 | inner BusinessSimulation.ModelSettings modelSettings(modelTimeHorizon = 10) annotation(Placement(visible = true, transformation(origin = {-110, -75}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 19 | BusinessSimulation.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))); 20 | BusinessSimulation.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))); 21 | 22 | expandable connector ModelOutput "Main Output" 23 | extends BusinessSimulation.Icons.DataOutPort; 24 | end ModelOutput; 25 | protected 26 | BusinessSimulation.Converters.Lookup.ConcaveLookupNegative concaveLookupNegative(s = slope1To50, y0 = interceptDownward) annotation(Placement(visible = true, transformation(origin = {-50, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 27 | BusinessSimulation.Converters.Lookup.ConcaveLookupPositive concaveLookupPositive(s = slopeUpTo1, y0 = interceptUpward) annotation(Placement(visible = true, transformation(origin = {-50, 55}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 28 | BusinessSimulation.Converters.Lookup.ConvexLookupNegative convexLookupNegative(y0 = interceptDownward) annotation(Placement(visible = true, transformation(origin = {-50, 25}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 29 | BusinessSimulation.Converters.Lookup.ConvexLookupPositive convexLookupPositive(s = slope1To50, y0 = interceptUpward) annotation(Placement(visible = true, transformation(origin = {-50, -5}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 30 | BusinessSimulation.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))); 31 | BusinessSimulation.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))); 32 | BusinessSimulation.Converters.Lookup.SShapedNegative sShapedNegative_origin(s = slope, upperBound = upperBound) annotation(Placement(visible = true, transformation(origin = {70, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 33 | BusinessSimulation.Converters.Lookup.SShapedPositive sShapedPositive_origin(s = slope, upperBound = upperBound) annotation(Placement(visible = true, transformation(origin = {70, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 34 | BusinessSimulation.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))); 35 | equation 36 | 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})); 37 | 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})); 38 | 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})); 39 | 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})); 40 | 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})); 41 | 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})); 42 | 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})); 43 | 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})); 44 | 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})); 45 | 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})); 46 | 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})); 47 | 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})); 48 | 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})); 49 | 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})); 50 | 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})); 51 | 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})); 52 | 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})); 53 | 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})); 54 | annotation(preferredView = "diagram", Documentation(info = " 55 |This information is part of the Business Simulation Library (BSL).
56 |This example demonstrates the use of parametric lookup and table functions in models and may serve as a showcase. 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.
57 |59 | Converters.Lookup 60 |
61 | ", figures = {Figure(title = "Concave Lookup", identifier = "concave", preferred = true, plots = {Plot(title = "Negative", identifier = "neg", curves = {Curve(y = modelOutput.concaveLookupNegative, legend = "concaveLookupNegative")}), Plot(title = "Positive", identifier = "pos", curves = {Curve(y = modelOutput.concaveLookupPositive, legend = "concaveLookupPositive")})}, caption = "Concave lookup with positive and negative slopes."), Figure(title = "Convex Lookup", identifier = "convex", plots = {Plot(title = "Negative", identifier = "neg", curves = {Curve(y = modelOutput.convexLookupNegative, legend = "convexLookupNegative")}), Plot(title = "Positive", curves = {Curve(y = modelOutput.convexLookupPositive, legend = "convexLookupPositive")})}, caption = "Convex lookups with positive and negative slopes."), Figure(title = "Table Function", identifier = "table", plots = {Plot(curves = {Curve(y = modelOutput.tableFunction, legend = "tableFunction")})}, caption = "Classical table function lookup."), Figure(title = "Janosckek's Growth Function", identifier = "janoschek", plots = {Plot(title = "Positive", identifier = "pos", curves = {Curve(y = modelOutput.janoschekPositive, legend = "janoschekPositive")}), Plot(title = "Negative", identifier = "neg", curves = {Curve(y = modelOutput.janoschekNegative, legend = "janoschekNegative")})}, caption = "Janoschek's growth function with positive and negative slopes."), Figure(title = "S-shaped Lookup", identifier = "sshaped", plots = {Plot(title = "Positive", identifier = "pos", curves = {Curve(x = '-5..5'.y, y = modelOutput.sShapedPositive, legend = "sShapedPositive vs '-5..5'.y")}), Plot(title = "Negative", identifier = "neg", curves = {Curve(x = '-5..5'.y, y = modelOutput.sShapedNegative, legend = "sShapedNegative vs '-5..5'.y")})}, caption = "S-shaped Lookup with positive and negative slope")}, revisions = " 62 |This information is part of the ISDC2022 Workshops package.
62 |PEX has two types of employees in this model: newly hired staff and experienced staff. The latter is also responsible for recruiting, e.g., interviewing candidates. Assuming sufficient numbers of applicants at all times, the growth of staff is completely dependent upon the number of experienced staff (→hiringPolicy). During the simulation period we will make the simplifying assumption that there is no staff turnover as all are excited to be part of this exciting startup.
64 | The effective number of service staff is calculated from the number of experienced staff after deducing those, that are involved in recruitment and coaching of newly hired personnell. The number of effective service staff and its service productivity are main drivers for →serviceQuality.
65 |
This information is part of the ISDC2022 Workshops package.
63 |64 | Following John Morecroft's interpretation [1], in this stylized model PEX wins and loses passengers by processes of exponential growth and decline, which can be justified by word-of-mouth-like processes in reality. 65 |
66 |
67 | PEX can be seen as a price setter, that is followed by the rest of the industry. Accordingly the fare of competitors' can be modeled as a smooth of Peoples' fare. Relative fare can then be used as an input to a—negatively sloped—s-shaped look-up function (→JanoschekNegative) to arrive at a fractional rate of winning new passengers (conversionRate). Conversely, existing passengers perceive serviceQuality—again modeled by a smooth—and will decide to abandon PEX. This decision is also modeled using a negatively sloping s-shaped look-up function (churnRate).
68 |
8 |
EUPL © the European Union 2007, 20169 | ")); 10 | end Licence; 11 | --------------------------------------------------------------------------------
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.