├── 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 |
9 |
10 |

Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later

11 | ")); 12 | end Examples; 13 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Icons/package.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops; 2 | 3 | package Icons "Partial classes for extension" 4 | extends BusinessSimulation.Icons.IconsPackage; 5 | annotation(Documentation(info = " 6 |

This information is part of the ISDC2022 Workshops package.

7 |

This package contains partial classes for extension providing icons.

8 |
9 |
10 |

Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later

11 | ")); 12 | end Icons; 13 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/package.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops; 2 | 3 | package Interfaces "Partial models and connectors" 4 | extends BusinessSimulation.Icons.InterfacesPackage; 5 | annotation(Documentation(info = " 6 |

This information is part of the ISDC2022 Workshops package.

7 |

This package contains partial models and connectors.

8 |
9 |
10 |

Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later

11 | ")); 12 | end Interfaces; 13 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/Journal/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Components/package.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops; 2 | 3 | package Components "Subsystems and molecules for models" 4 | extends BusinessSimulation.Icons.BasesPackage; 5 | annotation(Documentation(info = " 6 |

This information is part of the ISDC2022 Workshops package.

7 |

This package contains subsystems and molecules to be used in models.

8 |
9 |
10 |

Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later

11 | ")); 12 | end Components; 13 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Icons/Plane.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Icons; 2 | 3 | partial model Plane "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/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 |
9 |
10 |

Copyright © 2022 Guido Wolf Reichert
Licensed under the EUPL-1.2 or later

11 | "), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}))); 12 | end UsersGuide; 13 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Interfaces/PeopleExpressSimulationRun.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Interfaces; 2 | 3 | partial model PeopleExpressSimulationRun "Model settings and experiement annotation for basic run" 4 | inner BusinessSimulation.ModelSettings modelSettings(modelDisplayTimeBase = BusinessSimulation.Types.TimeBases.years, modelTimeHorizon(displayUnit = "yr") = 220752000, dt(displayUnit = "yr") = 7884000) annotation(Placement(visible = true, transformation(origin = {-110, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 5 | 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}})})); 6 | end PeopleExpressSimulationRun; 7 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/Stars/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/package.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | package PeopleExpress "Simplified model of boom and bust dynamics for PEX" 4 | extends BusinessSimulation.Icons.Package; 5 | annotation(Documentation(info = " 6 |

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\".

22 | ")); 23 | end IO; 24 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/TestPassengers_1.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model TestPassengers_1 "Service quality = 1 => neglectible churnRate (<< 0.001 p.a.)" 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.ConstantConverter serviceQuality(value = 1) "Service quality" annotation(Placement(visible = true, transformation(origin = {-80, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | Components.Passengers passengers(competitorFare.init = BusinessSimulation.Types.InitializationOptions.FixedValue, serviceReputation.init = BusinessSimulation.Types.InitializationOptions.SteadyState) "Passenger subsystem" annotation(Placement(visible = true, transformation(origin = {0, -10}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | equation 10 | connect(passengers.io, dataExchange) annotation(Line(visible = true, origin = {0, 20}, points = {{0, -20}, {-0, 20}}, color = {0, 0, 128})); 11 | connect(serviceQuality.y, dataExchange.serviceQuality) "input service quality" annotation(Line(visible = true, origin = {-37, 40}, points = {{-37, 0}, {37, 0}}, color = {1, 37, 163})); 12 | annotation(Documentation(info = " 13 |

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 |

24 | ", figures = {Figure(title = "Temperature", identifier = "temp", preferred = true, plots = {Plot(curves = {Curve(y = tempCup)}, __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 = {3.28, 10}, rotation = 33.802, textColor = {76, 112, 136}, extent = {{-86.72, -12}, {86.72, 12}}, textString = "textual model only", fontName = "Lato Black")})); 25 | end TeaCupTextual; 26 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/UsersGuide/References.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.UsersGuide; 2 | 3 | final class References "Bibliography" 4 | annotation(Documentation(info = " 5 |

This information is part of the ISDC2022 Workshops package.

6 | 7 | 8 | 9 | 10 | 14 | 15 | 16 | 17 | 20 | 21 | 22 |
[1] 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 |
[2] 18 |

J.D.W. Morecroft, Strategic modelling and business dynamics: A feedback systems approach, 2nd ed. Chichester, UK: John Wiley & Sons, 2008.

19 |
23 | "), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Polygon(visible = true, origin = {-20, -28}, lineColor = {56, 56, 56}, fillColor = {128, 128, 128}, fillPattern = FillPattern.Solid, points = {{-70, 108}, {-80, 98}, {-80, -72}, {110, -72}, {120, -62}}), Polygon(visible = true, origin = {-60, -5}, lineColor = {56, 56, 56}, fillColor = {179, 179, 179}, fillPattern = FillPattern.Solid, points = {{0, 85}, {-30, 85}, {-30, -85}, {60, -85}}), Rectangle(visible = true, origin = {50, -5}, lineColor = {56, 56, 56}, fillColor = {244, 244, 244}, fillPattern = FillPattern.Solid, extent = {{-50, -85}, {50, 85}}), Polygon(visible = true, origin = {-20.603, -3.83}, lineColor = {56, 56, 56}, fillColor = {230, 230, 230}, fillPattern = FillPattern.Solid, points = {{20.603, 83.83}, {0.603, 103.83}, {-59.397, 103.83}, {-59.397, 103.83}, {-59.397, -66.17}, {-59.397, -66.17}, {0.603, -66.17}, {20.603, -86.17}, {20.603, -86.17}, {20.603, 83.83}}, smooth = Smooth.Bezier), Line(visible = true, origin = {50, 15}, points = {{-35, 0}, {35, 0}}, color = {56, 56, 56}), Line(visible = true, origin = {50, -20}, points = {{-35, 0}, {35, 0}}, color = {56, 56, 56}), Line(visible = true, origin = {50, -55}, points = {{-35, 0}, {35, 0}}, color = {56, 56, 56}), Line(visible = true, origin = {50, 50}, points = {{-35, 0}, {35, 0}}, color = {56, 56, 56})})); 24 | end References; 25 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Resources/Images/Icons/AirMarket/Icon.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/package.mo: -------------------------------------------------------------------------------- 1 | package ISDC2022_Workshops "Support material for workshops #231 and #232 at the International System Dynamics Conference 2022 in Frankfurt, Germany" 2 | extends BusinessSimulation.Icons.Package; 3 | annotation(version = "1.0.0", versionDate = "2022-07-22", revisionId = "", uses(Modelica(version = "3.2.3"), BusinessSimulation(version = "2.0.0")), Documentation(info = " 4 |

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 |
7 |
8 |

Corresponding Author

9 |

10 | 11 | \"ContactInformation.png\" 12 |

13 |
14 |
15 |

Copyright © 2022 Guido Wolf Reichert
Licensed unter the European Union Public Licence (EUPL), Version 1.2 or later (the \"License\")

16 |

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)

17 |

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 |
7 |
8 |
9 |
10 |

This page contains the contact information for the package's main author.

11 |

Main Author

12 |

\"bslFullLogo.png\"

13 |
14 |
15 |
16 |
17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 |
Name 21 | Guido Wolf Reichert
Address 

26 |

27 | Schauenburgerstr. 116 28 |
29 | 24118 Kiel  30 |
31 | Germany 

32 |
Phone+49 431 90898902
Fax+49 431 90898903
E-Mailgwr@bsl-support.de
Webhttps://www.bsl-support.de
52 |
53 |
54 |
55 |
56 | "), Diagram(coordinateSystem(extent = {{-150, -90}, {150, 90}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5})), Icon(coordinateSystem(preserveAspectRatio = false, extent = {{-100, -100}, {100, 100}}, initialScale = 0.1, grid = {10, 10}), graphics = {Rectangle(visible = true, lineColor = {56, 56, 56}, fillColor = {230, 230, 230}, fillPattern = FillPattern.Solid, extent = {{-100, -72}, {100, 70}}), Polygon(visible = true, lineColor = {56, 56, 56}, fillColor = {230, 230, 230}, fillPattern = FillPattern.Solid, points = {{-100, -72}, {100, -72}, {0, 20}, {-100, -72}}), Polygon(visible = true, lineColor = {64, 64, 64}, fillColor = {244, 244, 244}, fillPattern = FillPattern.Solid, points = {{-100, 70}, {100, 70}, {0, -20}, {-100, 70}})})); 57 | end Contact; 58 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/PeopleExpress/TestFleet_2.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples.PeopleExpress; 2 | 3 | model TestFleet_2 "No passengers means no growth" 4 | extends Interfaces.PeopleExpressSimulationRun; 5 | extends BusinessSimulation.Icons.Example; 6 | parameter BusinessSimulation.Units.TangibleAssets initAC = 3 "Initial number of aircraft (fleet.initAC)"; 7 | 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.608, 50}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | 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))); 9 | BusinessSimulation.Converters.ConstantConverter ctrlAircraft(value = initAC) annotation(Placement(visible = true, transformation(origin = {40, -20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | protected 11 | Components.Fleet fleet(initAC = initAC) "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") = 0) "Have very large number, so that loadFactor is always one" annotation(Placement(visible = true, transformation(origin = {-45, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 14 | equation 15 | connect(fleet.io, dataExchange) annotation(Line(visible = true, origin = {0, 30}, points = {{0, -10}, {0, 10}}, color = {0, 0, 128})); 16 | connect(potentialPassengerMiles.y, dataExchange.potentialPassengerMiles) annotation(Line(visible = true, origin = {-19.5, 40}, points = {{-19.5, 0}, {19.5, 0}}, color = {1, 37, 163})); 17 | connect(dataExchange.aircraft, y) "model output aircraft" annotation(Line(visible = true, origin = {45, 40}, points = {{-45, 0}, {45, 0}}, color = {0, 0, 128})); 18 | connect(ctrlAircraft.y, y_ctrl) annotation(Line(visible = true, origin = {68, -20}, points = {{-22, 0}, {22, 0}}, color = {1, 37, 163})); 19 | annotation(Documentation(info = " 20 |

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 |

17 |

See also

18 |

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.

25 | ")); 26 | end TestFleet_1; 27 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Components/ServiceQuality.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Components; 2 | 3 | model ServiceQuality "Measuring service reputation onto the unit interval" 4 | extends BusinessSimulation.Interfaces.PartialConverters.InformationProcessing_SO; 5 | BusinessSimulation.Interfaces.Connectors.RealInput serviceStaff "Effective number of service staff" 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))); 6 | BusinessSimulation.Interfaces.Connectors.RealInput SP "Service productivity" 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))); 7 | BusinessSimulation.Interfaces.Connectors.RealInput RPM "Revenue passenger miles per period" annotation(Placement(visible = true, transformation(origin = {-145, -5}, extent = {{-10, -10}, {10, 10}}, rotation = 0), iconTransformation(origin = {-110, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 8 | BusinessSimulation.Converters.Product_2 serviceCapacity(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate) "Revenue passenger miles per year that can be served without stretch" annotation(Placement(visible = true, transformation(origin = {-80, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 9 | BusinessSimulation.Converters.Division_Guarded serviceRatio(outputIfZero = 1) "Ratio of RPM that can be serviced comfortably to actual RPM" annotation(Placement(visible = true, transformation(origin = {-25, -0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 10 | BusinessSimulation.Converters.Clip serviceQuality(minValue = 0, maxValue = 1) "Service quality measured on the unit inveral, i.e., a value of 1 is best" annotation(Placement(visible = true, transformation(origin = {10, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 11 | equation 12 | connect(SP, serviceCapacity.u2) annotation(Line(visible = true, origin = {-118.25, -12.5}, points = {{-26.75, -47.5}, {-1.75, -47.5}, {-1.75, 47.5}, {30.25, 47.5}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 13 | connect(serviceStaff, serviceCapacity.u1) annotation(Line(visible = true, origin = {-118.25, 52.5}, points = {{-26.75, 7.5}, {-1.75, 7.5}, {-1.75, -7.5}, {30.25, -7.5}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 14 | connect(RPM, serviceRatio.u2) annotation(Line(visible = true, origin = {-68.25, -2.5}, points = {{-76.75, -2.5}, {13.25, -2.5}, {13.25, -2.5}, {35.25, -2.5}}, color = {0, 0, 128})); 15 | connect(serviceCapacity.y, serviceRatio.u1) annotation(Line(visible = true, origin = {-54.454, 22.5}, points = {{-17.546, 17.5}, {4.454, 17.5}, {4.454, -17.5}, {21.454, -17.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 16 | connect(serviceRatio.y, serviceQuality.u) annotation(Line(visible = true, origin = {-7.5, -0}, points = {{-9.5, -0}, {9.5, 0}}, color = {1, 37, 163})); 17 | connect(serviceQuality.y, y) annotation(Line(visible = true, origin = {89, 0}, points = {{-71, 0}, {71, 0}}, color = {1, 37, 163})); 18 | annotation(Documentation(info = " 19 |

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 |

See also

22 |

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 |

30 |

See also

31 |

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 |

24 |

See also

25 |

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 |

24 |

See also

25 |

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 |

26 |

See also

27 |

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 |

26 |

See also

27 |

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 |

2 | 3 | # ISDC 2022 Workshops 4 | Support material for workshops __#231__ (2022-07-22T08:30+02:00) and __#232__ (2022-07-22T10:30+02:00) at the International System Dynamics Conference 2022 in Frankfurt, Germany. 5 | 6 | ## Workshop #231: Introducing Object-Oriented Modeling Using Pre-Built Components 7 | 8 | In this workshop, we want to introduce object-oriented modeling using pre-build components for System Dynamics. The participant will start by creating a simple System Dynamics model similar to building structures using LEGO blocks. They will learn to plot the variables from different components and quickly iterate over various designs by changing the model parameters. They will then document their plots(results) by adding plot markers, captions, and plot labels. Finally, they will learn to store the plot in the model for future reference. 9 | 10 | Business Simulation Library developed by Guido Wolf Reichert will be used for this workshop. This free library supports modeling & simulation in the social sciences and ecology. It follows the widespread System Dynamics metaphor and modeling approach introduced by Jay W. Forrester. Unlike existing approaches, it makes use of Modelica's acausal connectors to better distinguish material/mass flows from instantaneous information signal flows (causal connections). The approach has the additional benefit of allowing the modeler to build rather compact models in a fast and reliable fashion. 11 | 12 | The participants will then expand their simple model by adding pre-built components. This will make them appreciate the importance of using reusable components. They will learn to read the documentation of these pre-built components and understand how to use them. Finally, they will learn to document their own models. 13 | 14 | Participants will use Wolfram System Modeler for this workshop. Wolfram System Modeler is an easy-to-use, next-generation modeling and simulation environment for cyber-physical systems. It is based on the Modelica language which is an open standard language. The participants will receive a 6-month trial so that they can create and test models at their leisure. 15 | Participants should bring a laptop. 16 | 17 | [Workshop Presentation](/ISDC2022_Workshops/Resources/PDF/ISDC2022_WS231.pdf) 18 | 19 | ## Workshop #232: Data Wrangling, Model Testing and Model Analysis for Object-Oriented Models in the Wolfram Language 20 | 21 | This workshop is designed to follow the workshop on "Introduction to object-oriented hierarchical modeling using pre-built components". The participants will learn to do custom analysis on their models using the Wolfram Language. 22 | 23 | The Wolfram Language is a general multi-paradigm programming language developed by Wolfram Research. It emphasizes symbolic computation, functional programming, and rule-based programming and can employ arbitrary structures and data. 24 | 25 | The participants will start by plotting the results of their object-oriented models (which they would have created in the previous workshop) in the Wolfram Language. They will then create a simulation object that can be queried to obtain values of the variables for the entire simulation. These values can then be passed to the relevant Wolfram language functions for analysis such as optimization, calibration, control design and many more. The participant will also learn to simulate multiple scenarios in parallel and understand the parameter sensitivities. 26 | 27 | This will be followed by a session where the participants will learn to create automated tests using the Wolfram Language to keep their models updated. They will follow a step-by-step process to set up the test infrastructure for their simple models and learn the best practices. 28 | 29 | Finally, they will learn to create custom dashboards. They will learn how to create custom plots and document the model parameters with relevant descriptions. They will learn about different control objects that can be used to improve the user experience. Some common mistakes and tips-and-tricks will also be covered. 30 | 31 | They will then deploy the dashboard in the free Wolfram cloud. Through this process, they learn how to collaborate with others and learn how to publish the dashboard on the web for public access. 32 | Participants should bring a laptop. 33 | 34 | [Workshop Notebook](/ISDC2022_Workshops/Resources/Notebooks/ISDC2022_Workshop232.nb) 35 | 36 | ## License 37 | Copyright © 2022 Guido Wolf Reichert 38 | Licensed under the European Union Public Licence (EUPL), Version 1.2 or later (the "License") 39 | 40 | You may not use this work except in compliance with the License. You may obtain a copy of the License at:
41 | [https://eur-lex.europa.eu/eli/dec_impl/2017/863/oj](https://eur-lex.europa.eu/eli/dec_impl/2017/863/oj) 42 | 43 | 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. 44 | 45 | 46 | __Modelica©__ is a registered trademark of the Modelica Association.
47 | __Wolfram System Modeler™__ is a trademark of Wolfram Research, Inc.
48 | __Wolfram Mathematica and Mathematica™__ are registered trademarks of Wolfram Research, Inc. 49 | 50 | ## Contribution 51 | You may report bugs and other issues or simply make suggestions for future enhancements by using the Issues button. 52 | 53 | ## Corresponding Author 54 |

ContactInformation.png 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 |

See also

37 |

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 |

Notes

24 |

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 |

27 | 33 |

Acknowledgements

34 |

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 |

27 |

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 |

30 |
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 |

39 |

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 |

42 |

See also

43 |

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.

43 | "), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {-55, 98.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "potentialPassengerMiles", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Right), Text(visible = true, origin = {54.511, 98.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "aircraft", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {54.511, 93.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "growthRate", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {54.511, 88.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "revenuePassengerMiles", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left)})); 44 | end Fleet; 45 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Examples/TeaCupPhysical2.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Examples; 2 | 3 | model TeaCupPhysical2 "More elaborate physical version of the tea cup model" 4 | import Modelica.SIunits.{Mass,SpecificHeatCapacity,Length,ThermalConductivity,ThermalConductance,CoefficientOfHeatTransfer}; 5 | import Modelica.Constants.pi; 6 | extends BusinessSimulation.Icons.Example; 7 | // parameters 8 | parameter Boolean hasInsideConvection = false "= true, if convective heat flow is to be assumed for the liquid in the cup" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); 9 | parameter Boolean hasTopConvection = true "= true, if convective heat flow is to be assumed for the liquid at the top" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); 10 | parameter Boolean hasBodyRadiation = true "= true, if body radiation is to be accounted for" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); 11 | parameter Mass m(displayUnit = "g") = 0.25 "Mass of tea in the cup" annotation(Dialog(group = "Specification for hot liquid in the cup")); 12 | parameter SpecificHeatCapacity c_p = 4181 "Specific heat capacity for liquid water/tea" annotation(Dialog(group = "Specification for hot liquid in the cup")); 13 | parameter Length d(displayUnit = "cm") = 0.07 "Outer diameter of cup" annotation(Dialog(group = "Specification of cup")); 14 | parameter Length h(displayUnit = "cm") = 0.09 "Height of cup" annotation(Dialog(group = "Specification of cup")); 15 | parameter Length t(displayUnit = "mm") = 0.003 "Thickness of cup" annotation(Dialog(group = "Specification of cup")); 16 | parameter ThermalConductivity k = 1.5 "Thermal conductivity of cup material (e.g., porcelain = 1.5 [W/m.k])" annotation(Dialog(group = "Specification of cup")); 17 | parameter CoefficientOfHeatTransfer h_tea = 750 "Convective heat transfer coefficient for tea" annotation(Dialog(group = "Specficiation of convective heat transfer")); 18 | parameter CoefficientOfHeatTransfer h_air = 10 "Convective heat transfer coefficient for free air, i.e., not forced" annotation(Dialog(group = "Specficiation of convective heat transfer")); 19 | parameter Real epsilon = 0.9 "Emission value for cup material" annotation(Dialog(group = "Specficiation of body radiation")); 20 | // components 21 | 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 = {-60, 20}, extent = {{-10, -10}, {10, 10}}, rotation = -360))); 22 | Modelica.Thermal.HeatTransfer.Celsius.FixedTemperature tempRoom(T = 20) "Room temperature" annotation(Placement(visible = true, transformation(origin = {100, 20}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 23 | Modelica.Thermal.HeatTransfer.Celsius.TemperatureSensor tempCup "Temperature of tea in the cup" annotation(Placement(visible = true, transformation(origin = {-100, -10}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 24 | Modelica.Thermal.HeatTransfer.Components.ThermalResistor conduction_cup(R = 1 / G_cup) "Condictive resistance of cup walls" annotation(Placement(visible = true, transformation(origin = {10, -30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 25 | Modelica.Thermal.HeatTransfer.Components.ConvectiveResistor convection_tea if hasInsideConvection "Convective resistance of tea" annotation(Placement(visible = true, transformation(origin = {-30, -30}, extent = {{10, 10}, {-10, -10}}, rotation = 0))); 26 | Modelica.Thermal.HeatTransfer.Components.ConvectiveResistor convection_air "Convective resistance of air" annotation(Placement(visible = true, transformation(origin = {50, -30}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); 27 | Modelica.Blocks.Sources.Constant Rc_tea(k = 1 / Gc_tea) if hasInsideConvection "Thermal resistance for hot liquid" annotation(Placement(visible = true, transformation(origin = {-60, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 28 | Modelica.Blocks.Sources.Constant Rc_air(k = 1 / Gc_air) "Thermal resistance for air" annotation(Placement(visible = true, transformation(origin = {20, -70}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 29 | ZeroResistanceConductor zeroResistanceConduction if not hasInsideConvection "Simple connection for heat conduction without resistance" annotation(Placement(visible = true, transformation(origin = {-30, -30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 30 | Modelica.Thermal.HeatTransfer.Components.ConvectiveResistor convection_air_from_top if hasTopConvection "Convective resistance of air" annotation(Placement(visible = true, transformation(origin = {10, 20}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 31 | Modelica.Blocks.Sources.Constant Rc_air_top(k = 1 / Gc_air_top) if hasTopConvection "Thermal resistance for air at top" annotation(Placement(visible = true, transformation(origin = {50, 50}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 32 | Modelica.Thermal.HeatTransfer.Components.BodyRadiation bodyRadiation(Gr = Gr) if hasBodyRadiation "Heat loss due to body radiation" annotation(Placement(visible = true, transformation(origin = {10, 80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 33 | protected 34 | 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)); 35 | parameter ThermalConductance Gc_tea = pi * (d - 2 * t) * h * h_tea "Convective thermal conductance of tea" annotation(Dialog(enable = false, group = "Specficiation of convective heat transfer")); 36 | parameter ThermalConductance Gc_air = pi * d * h * h_air "Convective thermal conductance of air" annotation(Dialog(enable = false, group = "Specficiation of convective heat transfer")); 37 | parameter ThermalConductance Gc_air_top = pi * d ^ 2 * 0.25 * h_air "Convective thermal conductance at top" annotation(Dialog(enable = false, group = "Specficiation of convective heat transfer")); 38 | parameter ThermalConductance Gr = epsilon * pi * (d / 2) ^ 2 "Thermal conductance for body radiation" annotation(Dialog(enable = false, group = "Specficiation of body radiation")); 39 | 40 | model ZeroResistanceConductor "Dummy element to establish a switchable connection" 41 | extends Modelica.Thermal.HeatTransfer.Interfaces.Element1D; 42 | equation 43 | dT = 0; 44 | annotation(Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Line(visible = true, points = {{-100, 0}, {100, 0}}, color = {255, 0, 0}, thickness = 3)})); 45 | end ZeroResistanceConductor; 46 | equation 47 | connect(teaCup.port, convection_tea.fluid) annotation(Line(visible = true, origin = {-53.333, -16.667}, points = {{-6.667, 26.667}, {-6.667, -13.333}, {13.333, -13.333}}, color = {191, 0, 0})); 48 | connect(convection_tea.solid, conduction_cup.port_a) annotation(Line(visible = true, origin = {-10, -30}, points = {{-10, 0}, {10, 0}}, color = {191, 0, 0})); 49 | connect(tempRoom.port, convection_air.fluid) annotation(Line(visible = true, origin = {79.526, -5}, points = {{10.474, 25}, {0.474, 25}, {0.474, -25}, {-19.526, -25}}, color = {191, 0, 0})); 50 | connect(conduction_cup.port_b, convection_air.solid) annotation(Line(visible = true, origin = {30, -30}, points = {{-10, 0}, {10, 0}}, color = {191, 0, 0})); 51 | connect(Rc_tea.y, convection_tea.Rc) annotation(Line(visible = true, origin = {-36.333, -60}, points = {{-12.667, -10}, {6.333, -10}, {6.333, 20}}, color = {1, 37, 163})); 52 | connect(Rc_air.y, convection_air.Rc) annotation(Line(visible = true, origin = {43.667, -60}, points = {{-12.667, -10}, {6.333, -10}, {6.333, 20}}, color = {1, 37, 163})); 53 | connect(teaCup.port, zeroResistanceConduction.port_b) annotation(Line(visible = true, origin = {-53.333, -16.667}, points = {{-6.667, 26.667}, {-6.667, -13.333}, {13.333, -13.333}}, color = {191, 0, 0})); 54 | connect(zeroResistanceConduction.port_a, conduction_cup.port_a) annotation(Line(visible = true, origin = {-10, -30}, points = {{-10, 0}, {10, 0}}, color = {191, 0, 0})); 55 | connect(tempCup.port, teaCup.port) annotation(Line(visible = true, origin = {-70, -3.333}, points = {{-20, -6.667}, {10, -6.667}, {10, 13.333}}, color = {191, 0, 0})); 56 | connect(Rc_air_top.y, convection_air_from_top.Rc) annotation(Line(visible = true, origin = {19.667, 43.333}, points = {{19.333, 6.667}, {-9.667, 6.667}, {-9.667, -13.333}}, color = {1, 37, 163})); 57 | connect(convection_air_from_top.fluid, tempRoom.port) annotation(Line(visible = true, origin = {55, 20}, points = {{-35, 0}, {35, 0}}, color = {191, 0, 0})); 58 | connect(teaCup.port, convection_air_from_top.solid) annotation(Line(visible = true, origin = {-37.074, 8}, points = {{-22.926, 2}, {-22.926, -18}, {2.074, -18}, {2.074, 12}, {37.074, 12}}, color = {191, 0, 0})); 59 | connect(bodyRadiation.port_b, tempRoom.port) annotation(Line(visible = true, origin = {65.852, 50}, points = {{-45.852, 30}, {14.148, 30}, {14.148, -30}, {24.148, -30}}, color = {191, 0, 0})); 60 | connect(teaCup.port, bodyRadiation.port_a) annotation(Line(visible = true, origin = {-31.667, 39.643}, points = {{-28.333, -29.643}, {-28.333, -49.643}, {-3.333, -49.643}, {-3.333, 40.357}, {31.667, 40.357}}, color = {191, 0, 0})); 61 | annotation(experiment(StopTime = 3600, __Wolfram_DisplayTimeUnit = "min"), Documentation(info = " 62 |

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 |

66 |

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 |

See also

70 |

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 |

See also

58 |

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 | 65 | "), experiment(StartTime = 0, StopTime = 10, NumberOfIntervals = 10000, __Wolfram_Algorithm = "dassl", __Wolfram_SynchronizeWithRealTime = false), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {60, 80}, textColor = {76, 112, 136}, extent = {{-50, -6}, {50, 6}}, textString = "Lookup Converters", fontName = "Lato Black", textStyle = {TextStyle.Bold}, horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {60, 70}, textColor = {128, 128, 128}, extent = {{-50, -3}, {50, 3}}, textString = "Parametric- and Interpolating-Functions", fontName = "Lato", textStyle = {TextStyle.Bold}, horizontalAlignment = TextAlignment.Left)})); 66 | end LookupFunctions; 67 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Components/Staff.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Components; 2 | 3 | model Staff "People express staff" 4 | extends Interfaces.Staff; 5 | // parameters 6 | parameter Real initNS = 0 "Initial number of new staff"; 7 | parameter Real initES = 200 "Initial number of experienced staff"; 8 | parameter BusinessSimulation.Units.AmountRate SP(displayUnit = "million/yr") = 0.0475646879756469 "Service productivity, i.e., revenue passenger miles per service staff and year"; 9 | parameter Real MCM(unit = "people") = 60 "Maximum capapcity multiplier, i.e., max staff per plane (hiringPolicy.MCM)"; 10 | parameter BusinessSimulation.Units.Rate RI(displayUnit = "1/yr") = 9.51293759512938e-07 "Recruiting intensity, i.e., job interviews per recruiter per year (hiringPolicy.RI)"; 11 | parameter BusinessSimulation.Units.Amount AR(displayUnit = "percent") = 0.03 "Fraction of applicants accepted (hiringPolicy.AR)"; 12 | parameter Real FHI = 0.1 "Fraction of experienced staff fully involved in hiring"; 13 | parameter Real EPR = 0.03 "Experienced staff fully involved in training per recruit"; 14 | protected 15 | BusinessSimulation.Stocks.MaterialStock experiencedStaff(initialValue = initES) "Experienced personnel" annotation(Placement(visible = true, transformation(origin = {40, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 16 | BusinessSimulation.Stocks.DelayN newStaff(hasConstantDelayTime = false, initialValue = initNS) "Freshly recruited personnel" annotation(Placement(visible = true, transformation(origin = {-40, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 17 | BusinessSimulation.Flows.Unidirectional.OutflowDynamicStock advancing "New staff becoming experienced" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 18 | BusinessSimulation.SourcesOrSinks.ExponentialDecline leaving "Personnel leaving the company" annotation(Placement(visible = true, transformation(origin = {80, 0}, extent = {{10, 10}, {-10, -10}}, rotation = 0))); 19 | BusinessSimulation.SourcesOrSinks.Growth hiring "Recruiting new personnel" annotation(Placement(visible = true, transformation(origin = {-80, 0}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); 20 | BusinessSimulation.Converters.ConstantConverterTime timeToGainExperience(value(displayUnit = "yr") = 31536000) "Average time to become experienced staff member" annotation(Placement(visible = true, transformation(origin = {-67.206, 35}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 21 | BusinessSimulation.Converters.ConstantConverterRate turnover(timeBaseString = "year", value(displayUnit = "percent") = 0, redeclare replaceable type ValueType = BusinessSimulation.Units.Amount) "Fractional rate of staff leaving, which is not an option in \"the firm\" ;-)" annotation(Placement(visible = true, transformation(origin = {110, -30}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 22 | HiringPolicy hiringPolicy(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate, MCM = MCM, RI = RI, AR = AR) "Setting the rate of hiring" annotation(Placement(visible = true, transformation(origin = {-60, -40}, extent = {{10, 10}, {-10, -10}}, rotation = 0))); 23 | BusinessSimulation.Converters.Vector.Total totalStaff "Sum of new and experienced staff" annotation(Placement(visible = true, transformation(origin = {-26.713, -25}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 24 | BusinessSimulation.Converters.Gain recruiters(c = FHI) "Experienced staff available for hiring" annotation(Placement(visible = true, transformation(origin = {30, -40}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 25 | BusinessSimulation.Converters.Gain hiddenCoaching(c = EPR) "Experienced staff involved in coaching" annotation(Placement(visible = true, transformation(origin = {-7.231, 28.217}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 26 | BusinessSimulation.Converters.Vector.Total unavailableStaff "Experienced staff involved in hiring and training" annotation(Placement(visible = true, transformation(origin = {40, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 27 | BusinessSimulation.Converters.Gap effectiveServiceStaff "Experienced staff effictively serving passengers" annotation(Placement(visible = true, transformation(origin = {80, 30}, extent = {{-10, 10}, {10, -10}}, rotation = 0))); 28 | BusinessSimulation.Converters.ConstantConverter serviceProductivity(value = SP) "Revenue passenger miles per service staff per year" annotation(Placement(visible = true, transformation(origin = {110, 90}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 29 | ServiceQuality serviceQuality "Service quality" annotation(Placement(visible = true, transformation(origin = {70, 65}, extent = {{10, 10}, {-10, -10}}, rotation = 0))); 30 | // illustration 31 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab2 annotation(Placement(visible = true, transformation(origin = {-2.041, 55}, extent = {{-10, -10}, {10, 10}}, rotation = -450))); 32 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab3 annotation(Placement(visible = true, transformation(origin = {-23.013, 55}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); 33 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab4 annotation(Placement(visible = true, transformation(origin = {20, 10}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); 34 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab5 annotation(Placement(visible = true, transformation(origin = {30, 68.007}, extent = {{-10, -10}, {10, 10}}, rotation = -540))); 35 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab6 annotation(Placement(visible = true, transformation(origin = {47.85, 52.195}, extent = {{10, -10}, {-10, 10}}, rotation = 540))); 36 | equation 37 | connect(hiring.massPort, newStaff.inflow) annotation(Line(visible = true, origin = {-60, 0}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 38 | connect(newStaff.outflow, advancing.portA) annotation(Line(visible = true, origin = {-20, 0}, points = {{-10, 0}, {10, 0}}, color = {255, 0, 0})); 39 | connect(advancing.portB, experiencedStaff.inflow) annotation(Line(visible = true, origin = {20, 0}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 40 | connect(experiencedStaff.outflow, leaving.massPort) annotation(Line(visible = true, origin = {60, 0}, points = {{-10, 0}, {10, 0}}, color = {128, 0, 128})); 41 | connect(timeToGainExperience.y, newStaff.u) annotation(Line(visible = true, origin = {-50.402, 26.667}, points = {{-10.804, 8.333}, {5.402, 8.333}, {5.402, -16.667}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 42 | connect(leaving.u, turnover.y) annotation(Line(visible = true, origin = {91.333, -23.333}, points = {{-6.333, 13.333}, {-6.333, -6.667}, {12.667, -6.667}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 43 | connect(hiringPolicy.y, hiring.u) annotation(Line(visible = true, origin = {-80.333, -30}, points = {{9.333, -10}, {-4.667, -10}, {-4.667, 20}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 44 | connect(newStaff.y1, totalStaff.u[1]) "input new staff" annotation(Line(visible = true, origin = {-19.16, -15}, points = {{-10.34, 10}, {4.947, 10}, {4.947, -10}, {0.447, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 45 | connect(experiencedStaff.y2, totalStaff.u[2]) "input experienced staff" annotation(Line(visible = true, origin = {9.375, -22.5}, points = {{20.125, 17.5}, {10.625, 17.5}, {10.625, -2.5}, {-28.088, -2.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 46 | connect(totalStaff.y, hiringPolicy.totalStaff) annotation(Line(visible = true, origin = {-41.785, -30}, points = {{7.072, 5}, {0.072, 5}, {0.072, -5}, {-7.215, -5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 47 | connect(io.aircraft, hiringPolicy.planes) "input planes" annotation(Line(visible = true, origin = {-3.8, 19}, points = {{3.8, 86}, {3.8, 21}, {18.8, 21}, {18.8, -64}, {-45.2, -64}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 48 | connect(recruiters.u, experiencedStaff.y1) annotation(Line(visible = true, origin = {49.875, -22.5}, points = {{-11.875, -17.5}, {5.625, -17.5}, {5.625, 17.5}, {0.625, 17.5}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 49 | connect(recruiters.y, hiringPolicy.recruiters) annotation(Line(visible = true, origin = {-13.5, -40}, points = {{35.5, 0}, {-35.5, 0}}, color = {1, 37, 163})); 50 | connect(totalStaff.y, io.totalStaff) "output total staff" annotation(Line(visible = true, origin = {-27.816, 36.429}, points = {{-6.897, -61.429}, {-30.524, -61.429}, {-30.524, -7.999}, {7.816, -7.999}, {7.816, 43.571}, {27.816, 43.571}, {27.816, 68.571}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 51 | connect(newStaff.y, hiddenCoaching.u) annotation(Line(visible = true, origin = {-28.41, 22.278}, points = {{-6.59, -11.878}, {-6.59, 5.939}, {13.179, 5.939}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 52 | connect(hiddenCoaching.y, unavailableStaff.u[1]) annotation(Line(visible = true, origin = {12.077, 34.108}, points = {{-11.308, -5.892}, {-4.308, -5.892}, {-4.308, 5.892}, {19.923, 5.892}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 53 | connect(recruiters.y, unavailableStaff.u[2]) annotation(Line(visible = true, origin = {21.4, 0}, points = {{0.6, -40}, {-4.801, -40}, {-4.801, 40}, {10.6, 40}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 54 | connect(unavailableStaff.y, effectiveServiceStaff.u2) annotation(Line(visible = true, origin = {57.879, 37.5}, points = {{-9.879, 2.5}, {2.121, 2.5}, {2.121, -2.5}, {14.121, -2.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 55 | connect(experiencedStaff.y, effectiveServiceStaff.u1) annotation(Line(visible = true, origin = {54, 20.133}, points = {{-9, -9.733}, {-9, 4.867}, {18, 4.867}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 56 | connect(serviceProductivity.y, serviceQuality.SP) annotation(Line(visible = true, origin = {93.347, 80}, points = {{10.653, 10}, {0.041, 10}, {0.041, -10}, {-12.347, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 57 | connect(serviceQuality.y, io.serviceQuality) "output service quality" annotation(Line(visible = true, origin = {19.667, 78.333}, points = {{39.333, -13.333}, {-19.667, -13.333}, {-19.667, 26.667}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 58 | connect(io.RPM, serviceQuality.RPM) "input revenue passenger miles" annotation(Line(visible = true, origin = {56.2, 67}, points = {{-56.2, 38}, {-56.2, -17}, {43.8, -17}, {43.8, -2}, {24.8, -2}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 59 | connect(effectiveServiceStaff.y, serviceQuality.serviceStaff) annotation(Line(visible = true, origin = {90.134, 45}, points = {{-2.134, -15}, {14.866, -15}, {14.866, 15}, {-9.134, 15}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 60 | annotation(Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {-54.511, 98.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "planes", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Right), Text(visible = true, origin = {54.511, 98.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "totalStaff", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {54.511, 93.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "serviceQuality", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {-54.511, 93.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "revenuePassengerMiles", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Right)}), Documentation(info = " 61 |

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.

63 |

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 |

66 | ")); 67 | end Staff; 68 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/Components/Passengers.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.Components; 2 | 3 | model Passengers "Passenger and market subsystem" 4 | extends Interfaces.Passengers; 5 | parameter Boolean hasExogenousPrice = false "= true, if Peoples' fare is given exogenously" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); 6 | parameter Boolean hasExogenousTravelFrequency = false "= true, if travel frequency is to be an exogenous input" annotation(Evaluate = true, Dialog(group = "Structural Parameters")); 7 | parameter BusinessSimulation.Units.Amount initPP(displayUnit = "thousand") = 180e3 "Initial number of potential passengers"; 8 | parameter BusinessSimulation.Units.Time TTP(displayUnit = "yr") = 31536000 "Time to perceive service quality"; 9 | parameter BusinessSimulation.Units.Time ATP(displayUnit = "yr") = 126144000 "Time to adjust costs and fare to peoples"; 10 | parameter Real ICF(unit = "USD/RPM") = 0.25 "Initial fare for competition"; 11 | parameter Real IPF(unit = "USD/RPM") = 0.09 "Initial peoples' fare"; 12 | parameter Real FPF(unit = "USD/RPM") = 0.09 "Final peoples' fare"; 13 | parameter BusinessSimulation.Units.Time PPST(displayUnit = "yr") = 62472816000 "Start time for ramping up or down fares"; 14 | parameter BusinessSimulation.Units.Time PPD(displayUnit = "yr") = 0 "Duration of price adaptation"; 15 | parameter Real MPF(unit = "miles") = 800 "Average distance travelled per passenger and flight"; 16 | parameter BusinessSimulation.Units.Rate FPY(displayUnit = "1/yr") = 1.26839167935058e-07 "Average number of flights per passenger and year"; 17 | //protected 18 | BusinessSimulation.Stocks.MaterialStock potentialPassengers(redeclare replaceable type OutputType = BusinessSimulation.Units.Amount, initialValue(displayUnit = "thousand") = initPP) "Maximum number of passengers for PEX flights" annotation(Placement(visible = true, transformation(origin = {0, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 19 | BusinessSimulation.SourcesOrSinks.ExponentialChange winning "Increase of potential passengers" annotation(Placement(visible = true, transformation(origin = {-60, 0}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 20 | BusinessSimulation.SourcesOrSinks.ExponentialDecline losing "Losing potential passengers" annotation(Placement(visible = true, transformation(origin = {60, 0}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 21 | BusinessSimulation.Converters.DiscreteDelay.Smooth serviceReputation(hasConstantDelayTime = false) "Service quality perceived by passengers" annotation(Placement(visible = true, transformation(origin = {20, 60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 22 | BusinessSimulation.Converters.ConstantConverter perceptionTime(value = TTP, redeclare replaceable type OutputType = BusinessSimulation.Units.Time) "Time constant for perception delay" annotation(Placement(visible = true, transformation(origin = {50, 80}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 23 | BusinessSimulation.Converters.Lookup.JanoschekNegative churnRate(convertOutput = true, outputIsRate = true, timeBaseTableOut = BusinessSimulation.Types.TimeBases.years, lowerBound = 0, upperBound = 1, x_ref = 0.5, y_ref = 0.5, growthRate = 6) "Rate of losing passengers to competitors" annotation(Placement(visible = true, transformation(origin = {50, 40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 24 | BusinessSimulation.CausalLoop.InputControl peoplesFare(initialInput = IPF, finalInput = FPF, startTime(displayUnit = "yr") = PPST, duration(displayUnit = "yr") = PPD) if not hasExogenousPrice "Setting the price per passenger mile" annotation(Placement(visible = true, transformation(origin = {-122.946, 55}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 25 | BusinessSimulation.Converters.DiscreteDelay.Smooth competitorFare(hasConstantDelayTime = false, initialValue = ICF) "Average fare for the competition" annotation(Placement(visible = true, transformation(origin = {-97.946, 55}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 26 | BusinessSimulation.Converters.ConstantConverterTime adjustmentTimePrice(value(displayUnit = "yr") = ATP) "Time constant for adapting to peoples express fare" annotation(Placement(visible = true, transformation(origin = {-80, 80}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 27 | BusinessSimulation.Converters.Division relativeFare "Ratio of Peoples' fare to competitors'fare, i.e., less than one is advantageous" annotation(Placement(visible = true, transformation(origin = {-65, 47.73}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 28 | BusinessSimulation.Converters.Lookup.JanoschekNegative conversionRate(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate, upperBound = 3, lowerBound = -0.2, growthRate = 3, x_ref = 0.4, y_ref = 1.8, convertOutput = true, outputIsRate = true, timeBaseTableOut = BusinessSimulation.Types.TimeBases.years) "A nonlinear function of the relative fare" annotation(Placement(visible = true, transformation(origin = {-43.102, 26.603}, extent = {{10, -10}, {-10, 10}}, rotation = 0))); 29 | BusinessSimulation.Converters.ConstantConverter avgDistanceTraveled(value = MPF) "Miles traveled per passenger and flight" annotation(Placement(visible = true, transformation(origin = {-40, -40}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 30 | BusinessSimulation.Converters.ConstantConverter travelFrequency(value = FPY, redeclare replaceable type OutputType = BusinessSimulation.Units.Rate) if not hasExogenousTravelFrequency "Flights per passenger and year" annotation(Placement(visible = true, transformation(origin = {-40, -80}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 31 | BusinessSimulation.Converters.Product_3 potentialPassengerMiles(redeclare replaceable type OutputType = BusinessSimulation.Units.Rate) "Potential demand size per year" annotation(Placement(visible = true, transformation(origin = {40, -60}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 32 | // illustration 33 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab2 annotation(Placement(visible = true, transformation(origin = {-35, 52.192}, extent = {{-10, -10}, {10, 10}}, rotation = -360))); 34 | BusinessSimulation.CausalLoop.InfoFlowIndicator lab3 annotation(Placement(visible = true, transformation(origin = {2.318, 36.51}, extent = {{-10, -10}, {10, 10}}, rotation = -270))); 35 | BusinessSimulation.Converters.PassThrough exogenousTravelFrequency if hasExogenousTravelFrequency "Flights per passenger per year" annotation(Placement(visible = true, transformation(origin = {-70, -65}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 36 | BusinessSimulation.Converters.PassThrough exogenousPeoplesFare if hasExogenousPrice "USD per RPM" annotation(Placement(visible = true, transformation(origin = {-130, 30}, extent = {{-10, -10}, {10, 10}}, rotation = 0))); 37 | equation 38 | connect(winning.massPort, potentialPassengers.inflow) annotation(Line(visible = true, origin = {-30, 0}, points = {{-20, 0}, {20, 0}}, color = {128, 0, 128})); 39 | connect(potentialPassengers.outflow, losing.massPort) annotation(Line(visible = true, origin = {30, 0}, points = {{-20, 0}, {20, 0}}, color = {128, 0, 128})); 40 | connect(io.serviceQuality, serviceReputation.u) "input service quality" annotation(Line(visible = true, origin = {3.546, 75}, points = {{-3.546, 30}, {-3.546, -15}, {7.092, -15}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 41 | connect(perceptionTime.y, serviceReputation.u_delayTime) annotation(Line(visible = true, origin = {28, 75}, points = {{16, 5}, {-8, 5}, {-8, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 42 | connect(churnRate.y, losing.u) annotation(Line(visible = true, origin = {62.667, 30}, points = {{-4.667, 10}, {2.333, 10}, {2.333, -20}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 43 | connect(serviceReputation.y, churnRate.u) annotation(Line(visible = true, origin = {35.5, 50}, points = {{-5.5, 10}, {-0.5, 10}, {-0.5, -10}, {6.5, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 44 | connect(peoplesFare.y, competitorFare.u) annotation(Line(visible = true, origin = {-115.127, 55}, points = {{-7.819, 0}, {7.819, 0}}, color = {1, 37, 163})); 45 | connect(adjustmentTimePrice.y, competitorFare.u_delayTime) annotation(Line(visible = true, origin = {-93.964, 73.333}, points = {{7.964, 6.667}, {-3.982, 6.667}, {-3.982, -13.333}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 46 | connect(competitorFare.y, relativeFare.u2) annotation(Line(visible = true, origin = {-81.71, 48.865}, points = {{-6.236, 6.135}, {-1.237, 6.135}, {-1.237, -6.135}, {8.71, -6.135}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 47 | connect(peoplesFare.y, relativeFare.u1) annotation(Line(visible = true, origin = {-94.135, 49.205}, points = {{-28.811, 5.795}, {-20.865, 5.795}, {-20.865, -9.205}, {14.135, -9.205}, {14.135, 3.525}, {21.135, 3.525}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 48 | connect(relativeFare.y, io.relativeFare) "output relative fare" annotation(Line(visible = true, origin = {-19, 66.82}, points = {{-38, -19.09}, {19, -19.09}, {19, 38.18}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 49 | connect(conversionRate.y, winning.u) annotation(Line(visible = true, origin = {-60.367, 21.069}, points = {{9.265, 5.534}, {-4.633, 5.534}, {-4.633, -11.069}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 50 | connect(relativeFare.y, conversionRate.u) annotation(Line(visible = true, origin = {-33.026, 37.166}, points = {{-23.974, 10.564}, {13.026, 10.564}, {13.026, -10.564}, {-2.077, -10.564}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 51 | connect(travelFrequency.y, potentialPassengerMiles.u3) annotation(Line(visible = true, origin = {-12.482, -72.5}, points = {{-21.518, -7.5}, {12.482, -7.5}, {12.482, 7.5}, {44.482, 7.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 52 | connect(avgDistanceTraveled.y, potentialPassengerMiles.u2) annotation(Line(visible = true, origin = {-12.131, -50}, points = {{-21.869, 10}, {0.199, 10}, {0.199, -10}, {44.131, -10}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 53 | connect(potentialPassengers.y1, potentialPassengerMiles.u1) annotation(Line(visible = true, origin = {19.004, -30}, points = {{-8.504, 25}, {0.996, 25}, {0.996, -25}, {12.996, -25}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 54 | connect(potentialPassengerMiles.y, io.potentialPassengerMiles) "output potential passenger miles" annotation(Line(visible = true, origin = {49.6, 5}, points = {{-1.6, -65}, {50.4, -65}, {50.4, 15}, {-49.6, 15}, {-49.6, 100}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 55 | connect(potentialPassengers.y2, io.potentialPassengers) "output potential passengers" annotation(Line(visible = true, origin = {-10.1, 27.31}, points = {{-0.4, -32.31}, {-9.9, -32.31}, {-9.9, -9.128}, {10.1, -9.128}, {10.1, 77.69}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 56 | connect(exogenousTravelFrequency.y, potentialPassengerMiles.u3) annotation(Line(visible = true, origin = {-15, -65}, points = {{-47, 0}, {47, 0}}, color = {1, 37, 163})); 57 | connect(exogenousTravelFrequency.u, io.travelFrequency) "input travel frequency (conditional)" annotation(Line(visible = true, origin = {-62.485, 20}, points = {{-15.515, -85}, {-80.65, -85}, {-80.65, 85}, {62.485, 85}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 58 | connect(exogenousPeoplesFare.y, competitorFare.u) annotation(Line(visible = true, origin = {-114.827, 42.5}, points = {{-7.173, -12.5}, {-0.173, -12.5}, {-0.173, 12.5}, {7.519, 12.5}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 59 | connect(exogenousPeoplesFare.y, relativeFare.u1) annotation(Line(visible = true, origin = {-89.163, 41.365}, points = {{-32.837, -11.365}, {9.163, -11.365}, {9.163, 11.365}, {16.163, 11.365}}, color = {1, 37, 163}, smooth = Smooth.Bezier)); 60 | connect(exogenousPeoplesFare.u, io.peoplesFare) "input peoples fare (conditional)" annotation(Line(visible = true, origin = {-107.611, 67.5}, points = {{-30.389, -37.5}, {-37.389, -37.5}, {-37.389, 22.5}, {107.611, 22.5}, {107.611, 37.5}}, color = {0, 0, 128}, smooth = Smooth.Bezier)); 61 | annotation(Documentation(info = " 62 |

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 |

69 | "), Diagram(coordinateSystem(extent = {{-148.5, -105}, {148.5, 105}}, preserveAspectRatio = true, initialScale = 0.1, grid = {5, 5}), graphics = {Text(visible = true, origin = {55, 98.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "relativeFare", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {55, 93.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "potentialPassengerMiles", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left), Text(visible = true, origin = {-54.511, 98.848}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "serviceQuality", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Right), Text(visible = true, origin = {107.507, 100}, textColor = {0, 0, 128}, extent = {{-34.511, -3.848}, {34.511, 3.848}}, textString = "potentialPassengers", fontSize = 12, fontName = "Lato", horizontalAlignment = TextAlignment.Left)})); 70 | end Passengers; 71 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | EUROPEAN UNION PUBLIC LICENCE v. 1.2 2 | EUPL © the European Union 2007, 2016 3 | 4 | This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined 5 | below) which is provided under the terms of this Licence. Any use of the Work, 6 | other than as authorised under this Licence is prohibited (to the extent such 7 | use is covered by a right of the copyright holder of the Work). 8 | 9 | The Work is provided under the terms of this Licence when the Licensor (as 10 | defined below) has placed the following notice immediately following the 11 | copyright notice for the Work: 12 | 13 | Licensed under the EUPL 14 | 15 | or has expressed by any other means his willingness to license under the EUPL. 16 | 17 | 1. Definitions 18 | 19 | In this Licence, the following terms have the following meaning: 20 | 21 | - ‘The Licence’: this Licence. 22 | 23 | - ‘The Original Work’: the work or software distributed or communicated by the 24 | Licensor under this Licence, available as Source Code and also as Executable 25 | Code as the case may be. 26 | 27 | - ‘Derivative Works’: the works or software that could be created by the 28 | Licensee, based upon the Original Work or modifications thereof. This Licence 29 | does not define the extent of modification or dependence on the Original Work 30 | required in order to classify a work as a Derivative Work; this extent is 31 | determined by copyright law applicable in the country mentioned in Article 15. 32 | 33 | - ‘The Work’: the Original Work or its Derivative Works. 34 | 35 | - ‘The Source Code’: the human-readable form of the Work which is the most 36 | convenient for people to study and modify. 37 | 38 | - ‘The Executable Code’: any code which has generally been compiled and which is 39 | meant to be interpreted by a computer as a program. 40 | 41 | - ‘The Licensor’: the natural or legal person that distributes or communicates 42 | the Work under the Licence. 43 | 44 | - ‘Contributor(s)’: any natural or legal person who modifies the Work under the 45 | Licence, or otherwise contributes to the creation of a Derivative Work. 46 | 47 | - ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of 48 | the Work under the terms of the Licence. 49 | 50 | - ‘Distribution’ or ‘Communication’: any act of selling, giving, lending, 51 | renting, distributing, communicating, transmitting, or otherwise making 52 | available, online or offline, copies of the Work or providing access to its 53 | essential functionalities at the disposal of any other natural or legal 54 | person. 55 | 56 | 2. Scope of the rights granted by the Licence 57 | 58 | The Licensor hereby grants You a worldwide, royalty-free, non-exclusive, 59 | sublicensable licence to do the following, for the duration of copyright vested 60 | in the Original Work: 61 | 62 | - use the Work in any circumstance and for all usage, 63 | - reproduce the Work, 64 | - modify the Work, and make Derivative Works based upon the Work, 65 | - communicate to the public, including the right to make available or display 66 | the Work or copies thereof to the public and perform publicly, as the case may 67 | be, the Work, 68 | - distribute the Work or copies thereof, 69 | - lend and rent the Work or copies thereof, 70 | - sublicense rights in the Work or copies thereof. 71 | 72 | Those rights can be exercised on any media, supports and formats, whether now 73 | known or later invented, as far as the applicable law permits so. 74 | 75 | In the countries where moral rights apply, the Licensor waives his right to 76 | exercise his moral right to the extent allowed by law in order to make effective 77 | the licence of the economic rights here above listed. 78 | 79 | The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to 80 | any patents held by the Licensor, to the extent necessary to make use of the 81 | rights granted on the Work under this Licence. 82 | 83 | 3. Communication of the Source Code 84 | 85 | The Licensor may provide the Work either in its Source Code form, or as 86 | Executable Code. If the Work is provided as Executable Code, the Licensor 87 | provides in addition a machine-readable copy of the Source Code of the Work 88 | along with each copy of the Work that the Licensor distributes or indicates, in 89 | a notice following the copyright notice attached to the Work, a repository where 90 | the Source Code is easily and freely accessible for as long as the Licensor 91 | continues to distribute or communicate the Work. 92 | 93 | 4. Limitations on copyright 94 | 95 | Nothing in this Licence is intended to deprive the Licensee of the benefits from 96 | any exception or limitation to the exclusive rights of the rights owners in the 97 | Work, of the exhaustion of those rights or of other applicable limitations 98 | thereto. 99 | 100 | 5. Obligations of the Licensee 101 | 102 | The grant of the rights mentioned above is subject to some restrictions and 103 | obligations imposed on the Licensee. Those obligations are the following: 104 | 105 | Attribution right: The Licensee shall keep intact all copyright, patent or 106 | trademarks notices and all notices that refer to the Licence and to the 107 | disclaimer of warranties. The Licensee must include a copy of such notices and a 108 | copy of the Licence with every copy of the Work he/she distributes or 109 | communicates. The Licensee must cause any Derivative Work to carry prominent 110 | notices stating that the Work has been modified and the date of modification. 111 | 112 | Copyleft clause: If the Licensee distributes or communicates copies of the 113 | Original Works or Derivative Works, this Distribution or Communication will be 114 | done under the terms of this Licence or of a later version of this Licence 115 | unless the Original Work is expressly distributed only under this version of the 116 | Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee 117 | (becoming Licensor) cannot offer or impose any additional terms or conditions on 118 | the Work or Derivative Work that alter or restrict the terms of the Licence. 119 | 120 | Compatibility clause: If the Licensee Distributes or Communicates Derivative 121 | Works or copies thereof based upon both the Work and another work licensed under 122 | a Compatible Licence, this Distribution or Communication can be done under the 123 | terms of this Compatible Licence. For the sake of this clause, ‘Compatible 124 | Licence’ refers to the licences listed in the appendix attached to this Licence. 125 | Should the Licensee's obligations under the Compatible Licence conflict with 126 | his/her obligations under this Licence, the obligations of the Compatible 127 | Licence shall prevail. 128 | 129 | Provision of Source Code: When distributing or communicating copies of the Work, 130 | the Licensee will provide a machine-readable copy of the Source Code or indicate 131 | a repository where this Source will be easily and freely available for as long 132 | as the Licensee continues to distribute or communicate the Work. 133 | 134 | Legal Protection: This Licence does not grant permission to use the trade names, 135 | trademarks, service marks, or names of the Licensor, except as required for 136 | reasonable and customary use in describing the origin of the Work and 137 | reproducing the content of the copyright notice. 138 | 139 | 6. Chain of Authorship 140 | 141 | The original Licensor warrants that the copyright in the Original Work granted 142 | hereunder is owned by him/her or licensed to him/her and that he/she has the 143 | power and authority to grant the Licence. 144 | 145 | Each Contributor warrants that the copyright in the modifications he/she brings 146 | to the Work are owned by him/her or licensed to him/her and that he/she has the 147 | power and authority to grant the Licence. 148 | 149 | Each time You accept the Licence, the original Licensor and subsequent 150 | Contributors grant You a licence to their contributions to the Work, under the 151 | terms of this Licence. 152 | 153 | 7. Disclaimer of Warranty 154 | 155 | The Work is a work in progress, which is continuously improved by numerous 156 | Contributors. It is not a finished work and may therefore contain defects or 157 | ‘bugs’ inherent to this type of development. 158 | 159 | For the above reason, the Work is provided under the Licence on an ‘as is’ basis 160 | and without warranties of any kind concerning the Work, including without 161 | limitation merchantability, fitness for a particular purpose, absence of defects 162 | or errors, accuracy, non-infringement of intellectual property rights other than 163 | copyright as stated in Article 6 of this Licence. 164 | 165 | This disclaimer of warranty is an essential part of the Licence and a condition 166 | for the grant of any rights to the Work. 167 | 168 | 8. Disclaimer of Liability 169 | 170 | Except in the cases of wilful misconduct or damages directly caused to natural 171 | persons, the Licensor will in no event be liable for any direct or indirect, 172 | material or moral, damages of any kind, arising out of the Licence or of the use 173 | of the Work, including without limitation, damages for loss of goodwill, work 174 | stoppage, computer failure or malfunction, loss of data or any commercial 175 | damage, even if the Licensor has been advised of the possibility of such damage. 176 | However, the Licensor will be liable under statutory product liability laws as 177 | far such laws apply to the Work. 178 | 179 | 9. Additional agreements 180 | 181 | While distributing the Work, You may choose to conclude an additional agreement, 182 | defining obligations or services consistent with this Licence. However, if 183 | accepting obligations, You may act only on your own behalf and on your sole 184 | responsibility, not on behalf of the original Licensor or any other Contributor, 185 | and only if You agree to indemnify, defend, and hold each Contributor harmless 186 | for any liability incurred by, or claims asserted against such Contributor by 187 | the fact You have accepted any warranty or additional liability. 188 | 189 | 10. Acceptance of the Licence 190 | 191 | The provisions of this Licence can be accepted by clicking on an icon ‘I agree’ 192 | placed under the bottom of a window displaying the text of this Licence or by 193 | affirming consent in any other similar way, in accordance with the rules of 194 | applicable law. Clicking on that icon indicates your clear and irrevocable 195 | acceptance of this Licence and all of its terms and conditions. 196 | 197 | Similarly, you irrevocably accept this Licence and all of its terms and 198 | conditions by exercising any rights granted to You by Article 2 of this Licence, 199 | such as the use of the Work, the creation by You of a Derivative Work or the 200 | Distribution or Communication by You of the Work or copies thereof. 201 | 202 | 11. Information to the public 203 | 204 | In case of any Distribution or Communication of the Work by means of electronic 205 | communication by You (for example, by offering to download the Work from a 206 | remote location) the distribution channel or media (for example, a website) must 207 | at least provide to the public the information requested by the applicable law 208 | regarding the Licensor, the Licence and the way it may be accessible, concluded, 209 | stored and reproduced by the Licensee. 210 | 211 | 12. Termination of the Licence 212 | 213 | The Licence and the rights granted hereunder will terminate automatically upon 214 | any breach by the Licensee of the terms of the Licence. 215 | 216 | Such a termination will not terminate the licences of any person who has 217 | received the Work from the Licensee under the Licence, provided such persons 218 | remain in full compliance with the Licence. 219 | 220 | 13. Miscellaneous 221 | 222 | Without prejudice of Article 9 above, the Licence represents the complete 223 | agreement between the Parties as to the Work. 224 | 225 | If any provision of the Licence is invalid or unenforceable under applicable 226 | law, this will not affect the validity or enforceability of the Licence as a 227 | whole. Such provision will be construed or reformed so as necessary to make it 228 | valid and enforceable. 229 | 230 | The European Commission may publish other linguistic versions or new versions of 231 | this Licence or updated versions of the Appendix, so far this is required and 232 | reasonable, without reducing the scope of the rights granted by the Licence. New 233 | versions of the Licence will be published with a unique version number. 234 | 235 | All linguistic versions of this Licence, approved by the European Commission, 236 | have identical value. Parties can take advantage of the linguistic version of 237 | their choice. 238 | 239 | 14. Jurisdiction 240 | 241 | Without prejudice to specific agreement between parties, 242 | 243 | - any litigation resulting from the interpretation of this License, arising 244 | between the European Union institutions, bodies, offices or agencies, as a 245 | Licensor, and any Licensee, will be subject to the jurisdiction of the Court 246 | of Justice of the European Union, as laid down in article 272 of the Treaty on 247 | the Functioning of the European Union, 248 | 249 | - any litigation arising between other parties and resulting from the 250 | interpretation of this License, will be subject to the exclusive jurisdiction 251 | of the competent court where the Licensor resides or conducts its primary 252 | business. 253 | 254 | 15. Applicable Law 255 | 256 | Without prejudice to specific agreement between parties, 257 | 258 | - this Licence shall be governed by the law of the European Union Member State 259 | where the Licensor has his seat, resides or has his registered office, 260 | 261 | - this licence shall be governed by Belgian law if the Licensor has no seat, 262 | residence or registered office inside a European Union Member State. 263 | 264 | Appendix 265 | 266 | ‘Compatible Licences’ according to Article 5 EUPL are: 267 | 268 | - GNU General Public License (GPL) v. 2, v. 3 269 | - GNU Affero General Public License (AGPL) v. 3 270 | - Open Software License (OSL) v. 2.1, v. 3.0 271 | - Eclipse Public License (EPL) v. 1.0 272 | - CeCILL v. 2.0, v. 2.1 273 | - Mozilla Public Licence (MPL) v. 2 274 | - GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3 275 | - Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for 276 | works other than software 277 | - European Union Public Licence (EUPL) v. 1.1, v. 1.2 278 | - Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong 279 | Reciprocity (LiLiQ-R+). 280 | 281 | The European Commission may update this Appendix to later versions of the above 282 | licences without producing a new version of the EUPL, as long as they provide 283 | the rights granted in Article 2 of this Licence and protect the covered Source 284 | Code from exclusive appropriation. 285 | 286 | All other changes or additions to this Appendix require the production of a new 287 | EUPL version. 288 | -------------------------------------------------------------------------------- /ISDC2022_Workshops/UsersGuide/Licence.mo: -------------------------------------------------------------------------------- 1 | within ISDC2022_Workshops.UsersGuide; 2 | 3 | final class Licence "European Union Public Licence v. 1.2 (EUPL-1.2)" 4 | extends BusinessSimulation.Icons.Info; 5 | annotation(Diagram(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10}), graphics = {Text(visible = true, extent = {{-44.9, -12}, {44.9, 12}}, textString = "LICENCE → DOCUMENTATION ", fontName = "Lato Black")}), Icon(coordinateSystem(extent = {{-100, -100}, {100, 100}}, preserveAspectRatio = true, initialScale = 0.1, grid = {10, 10})), Documentation(info = " 6 |

EUROPEAN UNION PUBLIC LICENCE v. 1.2

7 |

 

8 |
EUPL © the European Union 2007, 2016

This European Union Public Licence (the ‘EUPL’) applies to the Work (as defined
below) which is provided under the terms of this Licence. Any use of the Work,
other than as authorised under this Licence is prohibited (to the extent such
use is covered by a right of the copyright holder of the Work).

The Work is provided under the terms of this Licence when the Licensor (as
defined below) has placed the following notice immediately following the
copyright notice for the Work:

Licensed under the EUPL

or has expressed by any other means his willingness to license under the EUPL.

1. Definitions

In this Licence, the following terms have the following meaning:

- ‘The Licence’: this Licence.

- ‘The Original Work’: the work or software distributed or communicated by the
Licensor under this Licence, available as Source Code and also as Executable
Code as the case may be.

- ‘Derivative Works’: the works or software that could be created by the
Licensee, based upon the Original Work or modifications thereof. This Licence
does not define the extent of modification or dependence on the Original Work
required in order to classify a work as a Derivative Work; this extent is
determined by copyright law applicable in the country mentioned in Article 15.

- ‘The Work’: the Original Work or its Derivative Works.

- ‘The Source Code’: the human-readable form of the Work which is the most
convenient for people to study and modify.

- ‘The Executable Code’: any code which has generally been compiled and which is
meant to be interpreted by a computer as a program.

- ‘The Licensor’: the natural or legal person that distributes or communicates
the Work under the Licence.

- ‘Contributor(s)’: any natural or legal person who modifies the Work under the
Licence, or otherwise contributes to the creation of a Derivative Work.

- ‘The Licensee’ or ‘You’: any natural or legal person who makes any usage of
the Work under the terms of the Licence.

- ‘Distribution’ or ‘Communication’: any act of selling, giving, lending,
renting, distributing, communicating, transmitting, or otherwise making
available, online or offline, copies of the Work or providing access to its
essential functionalities at the disposal of any other natural or legal
person.

2. Scope of the rights granted by the Licence

The Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
sublicensable licence to do the following, for the duration of copyright vested
in the Original Work:

- use the Work in any circumstance and for all usage,
- reproduce the Work,
- modify the Work, and make Derivative Works based upon the Work,
- communicate to the public, including the right to make available or display
the Work or copies thereof to the public and perform publicly, as the case may
be, the Work,
- distribute the Work or copies thereof,
- lend and rent the Work or copies thereof,
- sublicense rights in the Work or copies thereof.

Those rights can be exercised on any media, supports and formats, whether now
known or later invented, as far as the applicable law permits so.

In the countries where moral rights apply, the Licensor waives his right to
exercise his moral right to the extent allowed by law in order to make effective
the licence of the economic rights here above listed.

The Licensor grants to the Licensee royalty-free, non-exclusive usage rights to
any patents held by the Licensor, to the extent necessary to make use of the
rights granted on the Work under this Licence.

3. Communication of the Source Code

The Licensor may provide the Work either in its Source Code form, or as
Executable Code. If the Work is provided as Executable Code, the Licensor
provides in addition a machine-readable copy of the Source Code of the Work
along with each copy of the Work that the Licensor distributes or indicates, in
a notice following the copyright notice attached to the Work, a repository where
the Source Code is easily and freely accessible for as long as the Licensor
continues to distribute or communicate the Work.

4. Limitations on copyright

Nothing in this Licence is intended to deprive the Licensee of the benefits from
any exception or limitation to the exclusive rights of the rights owners in the
Work, of the exhaustion of those rights or of other applicable limitations
thereto.

5. Obligations of the Licensee

The grant of the rights mentioned above is subject to some restrictions and
obligations imposed on the Licensee. Those obligations are the following:

Attribution right: The Licensee shall keep intact all copyright, patent or
trademarks notices and all notices that refer to the Licence and to the
disclaimer of warranties. The Licensee must include a copy of such notices and a
copy of the Licence with every copy of the Work he/she distributes or
communicates. The Licensee must cause any Derivative Work to carry prominent
notices stating that the Work has been modified and the date of modification.

Copyleft clause: If the Licensee distributes or communicates copies of the
Original Works or Derivative Works, this Distribution or Communication will be
done under the terms of this Licence or of a later version of this Licence
unless the Original Work is expressly distributed only under this version of the
Licence — for example by communicating ‘EUPL v. 1.2 only’. The Licensee
(becoming Licensor) cannot offer or impose any additional terms or conditions on
the Work or Derivative Work that alter or restrict the terms of the Licence.

Compatibility clause: If the Licensee Distributes or Communicates Derivative
Works or copies thereof based upon both the Work and another work licensed under
a Compatible Licence, this Distribution or Communication can be done under the
terms of this Compatible Licence. For the sake of this clause, ‘Compatible
Licence’ refers to the licences listed in the appendix attached to this Licence.
Should the Licensee's obligations under the Compatible Licence conflict with
his/her obligations under this Licence, the obligations of the Compatible
Licence shall prevail.

Provision of Source Code: When distributing or communicating copies of the Work,
the Licensee will provide a machine-readable copy of the Source Code or indicate
a repository where this Source will be easily and freely available for as long
as the Licensee continues to distribute or communicate the Work.

Legal Protection: This Licence does not grant permission to use the trade names,
trademarks, service marks, or names of the Licensor, except as required for
reasonable and customary use in describing the origin of the Work and
reproducing the content of the copyright notice.

6. Chain of Authorship

The original Licensor warrants that the copyright in the Original Work granted
hereunder is owned by him/her or licensed to him/her and that he/she has the
power and authority to grant the Licence.

Each Contributor warrants that the copyright in the modifications he/she brings
to the Work are owned by him/her or licensed to him/her and that he/she has the
power and authority to grant the Licence.

Each time You accept the Licence, the original Licensor and subsequent
Contributors grant You a licence to their contributions to the Work, under the
terms of this Licence.

7. Disclaimer of Warranty

The Work is a work in progress, which is continuously improved by numerous
Contributors. It is not a finished work and may therefore contain defects or
‘bugs’ inherent to this type of development.

For the above reason, the Work is provided under the Licence on an ‘as is’ basis
and without warranties of any kind concerning the Work, including without
limitation merchantability, fitness for a particular purpose, absence of defects
or errors, accuracy, non-infringement of intellectual property rights other than
copyright as stated in Article 6 of this Licence.

This disclaimer of warranty is an essential part of the Licence and a condition
for the grant of any rights to the Work.

8. Disclaimer of Liability

Except in the cases of wilful misconduct or damages directly caused to natural
persons, the Licensor will in no event be liable for any direct or indirect,
material or moral, damages of any kind, arising out of the Licence or of the use
of the Work, including without limitation, damages for loss of goodwill, work
stoppage, computer failure or malfunction, loss of data or any commercial
damage, even if the Licensor has been advised of the possibility of such damage.
However, the Licensor will be liable under statutory product liability laws as
far such laws apply to the Work.

9. Additional agreements

While distributing the Work, You may choose to conclude an additional agreement,
defining obligations or services consistent with this Licence. However, if
accepting obligations, You may act only on your own behalf and on your sole
responsibility, not on behalf of the original Licensor or any other Contributor,
and only if You agree to indemnify, defend, and hold each Contributor harmless
for any liability incurred by, or claims asserted against such Contributor by
the fact You have accepted any warranty or additional liability.

10. Acceptance of the Licence

The provisions of this Licence can be accepted by clicking on an icon ‘I agree’
placed under the bottom of a window displaying the text of this Licence or by
affirming consent in any other similar way, in accordance with the rules of
applicable law. Clicking on that icon indicates your clear and irrevocable
acceptance of this Licence and all of its terms and conditions.

Similarly, you irrevocably accept this Licence and all of its terms and
conditions by exercising any rights granted to You by Article 2 of this Licence,
such as the use of the Work, the creation by You of a Derivative Work or the
Distribution or Communication by You of the Work or copies thereof.

11. Information to the public

In case of any Distribution or Communication of the Work by means of electronic
communication by You (for example, by offering to download the Work from a
remote location) the distribution channel or media (for example, a website) must
at least provide to the public the information requested by the applicable law
regarding the Licensor, the Licence and the way it may be accessible, concluded,
stored and reproduced by the Licensee.

12. Termination of the Licence

The Licence and the rights granted hereunder will terminate automatically upon
any breach by the Licensee of the terms of the Licence.

Such a termination will not terminate the licences of any person who has
received the Work from the Licensee under the Licence, provided such persons
remain in full compliance with the Licence.

13. Miscellaneous

Without prejudice of Article 9 above, the Licence represents the complete
agreement between the Parties as to the Work.

If any provision of the Licence is invalid or unenforceable under applicable
law, this will not affect the validity or enforceability of the Licence as a
whole. Such provision will be construed or reformed so as necessary to make it
valid and enforceable.

The European Commission may publish other linguistic versions or new versions of
this Licence or updated versions of the Appendix, so far this is required and
reasonable, without reducing the scope of the rights granted by the Licence. New
versions of the Licence will be published with a unique version number.

All linguistic versions of this Licence, approved by the European Commission,
have identical value. Parties can take advantage of the linguistic version of
their choice.

14. Jurisdiction

Without prejudice to specific agreement between parties,

- any litigation resulting from the interpretation of this License, arising
between the European Union institutions, bodies, offices or agencies, as a
Licensor, and any Licensee, will be subject to the jurisdiction of the Court
of Justice of the European Union, as laid down in article 272 of the Treaty on
the Functioning of the European Union,

- any litigation arising between other parties and resulting from the
interpretation of this License, will be subject to the exclusive jurisdiction
of the competent court where the Licensor resides or conducts its primary
business.

15. Applicable Law

Without prejudice to specific agreement between parties,

- this Licence shall be governed by the law of the European Union Member State
where the Licensor has his seat, resides or has his registered office,

- this licence shall be governed by Belgian law if the Licensor has no seat,
residence or registered office inside a European Union Member State.

Appendix

‘Compatible Licences’ according to Article 5 EUPL are:

- GNU General Public License (GPL) v. 2, v. 3
- GNU Affero General Public License (AGPL) v. 3
- Open Software License (OSL) v. 2.1, v. 3.0
- Eclipse Public License (EPL) v. 1.0
- CeCILL v. 2.0, v. 2.1
- Mozilla Public Licence (MPL) v. 2
- GNU Lesser General Public Licence (LGPL) v. 2.1, v. 3
- Creative Commons Attribution-ShareAlike v. 3.0 Unported (CC BY-SA 3.0) for
works other than software
- European Union Public Licence (EUPL) v. 1.1, v. 1.2
- Québec Free and Open-Source Licence — Reciprocity (LiLiQ-R) or Strong
Reciprocity (LiLiQ-R+).

The European Commission may update this Appendix to later versions of the above
licences without producing a new version of the EUPL, as long as they provide
the rights granted in Article 2 of this Licence and protect the covered Source
Code from exclusive appropriation.

All other changes or additions to this Appendix require the production of a new
EUPL version.
9 | ")); 10 | end Licence; 11 | --------------------------------------------------------------------------------