693 lines
14 KiB
Python
693 lines
14 KiB
Python
"""
|
|
Python model 'bes.py'
|
|
Translated using PySD
|
|
"""
|
|
|
|
from pathlib import Path
|
|
import numpy as np
|
|
|
|
from pysd.py_backend.statefuls import Integ
|
|
from pysd import Component
|
|
|
|
__pysd_version__ = "3.14.2"
|
|
|
|
__data = {"scope": None, "time": lambda: 0}
|
|
|
|
_root = Path(__file__).parent
|
|
|
|
|
|
component = Component()
|
|
|
|
#######################################################################
|
|
# CONTROL VARIABLES #
|
|
#######################################################################
|
|
|
|
_control_vars = {
|
|
"initial_time": lambda: 0,
|
|
"final_time": lambda: 120,
|
|
"time_step": lambda: 1,
|
|
"saveper": lambda: time_step(),
|
|
}
|
|
|
|
|
|
def _init_outer_references(data):
|
|
for key in data:
|
|
__data[key] = data[key]
|
|
|
|
|
|
@component.add(name="Time")
|
|
def time():
|
|
"""
|
|
Current time of the model.
|
|
"""
|
|
return __data["time"]()
|
|
|
|
|
|
@component.add(
|
|
name="FINAL TIME", units="Month", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def final_time():
|
|
"""
|
|
The final time for the simulation.
|
|
"""
|
|
return __data["time"].final_time()
|
|
|
|
|
|
@component.add(
|
|
name="INITIAL TIME", units="Month", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def initial_time():
|
|
"""
|
|
The initial time for the simulation.
|
|
"""
|
|
return __data["time"].initial_time()
|
|
|
|
|
|
@component.add(
|
|
name="SAVEPER",
|
|
units="Month",
|
|
limits=(0.0, np.nan),
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"time_step": 1},
|
|
)
|
|
def saveper():
|
|
"""
|
|
The frequency with which output is stored.
|
|
"""
|
|
return __data["time"].saveper()
|
|
|
|
|
|
@component.add(
|
|
name="TIME STEP",
|
|
units="Month",
|
|
limits=(0.0, np.nan),
|
|
comp_type="Constant",
|
|
comp_subtype="Normal",
|
|
)
|
|
def time_step():
|
|
"""
|
|
The time step for the simulation.
|
|
"""
|
|
return __data["time"].time_step()
|
|
|
|
|
|
#######################################################################
|
|
# MODEL VARIABLES #
|
|
#######################################################################
|
|
|
|
|
|
@component.add(
|
|
name="Noise", comp_type="Auxiliary", comp_subtype="Normal", depends_on={"time": 1}
|
|
)
|
|
def noise():
|
|
return float(np.random.uniform(0, 5, size=()))
|
|
|
|
|
|
@component.add(
|
|
name="Demand",
|
|
units="loaves/Day",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"base_demand": 1, "noise": 1},
|
|
)
|
|
def demand():
|
|
return base_demand() + noise()
|
|
|
|
|
|
@component.add(
|
|
name="Amplitude of Seasonal Variations",
|
|
units="loaves",
|
|
comp_type="Constant",
|
|
comp_subtype="Normal",
|
|
)
|
|
def amplitude_of_seasonal_variations():
|
|
return 30
|
|
|
|
|
|
@component.add(name="phi", units="radians", comp_type="Constant", comp_subtype="Normal")
|
|
def phi():
|
|
return 0
|
|
|
|
|
|
@component.add(
|
|
name="Base Demand", units="loaves/Day", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def base_demand():
|
|
return 200
|
|
|
|
|
|
@component.add(
|
|
name="Sigma", units="loaves/Day", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def sigma():
|
|
return 5
|
|
|
|
|
|
@component.add(name="Period", units="days", comp_type="Constant", comp_subtype="Normal")
|
|
def period():
|
|
return 7
|
|
|
|
|
|
@component.add(
|
|
name="Available Workers",
|
|
units="workers",
|
|
comp_type="Constant",
|
|
comp_subtype="Normal",
|
|
)
|
|
def available_workers():
|
|
return 2
|
|
|
|
|
|
@component.add(
|
|
name="Base Rate", units="loaves/Day", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def base_rate():
|
|
return 200
|
|
|
|
|
|
@component.add(
|
|
name="Lead Time Sugar", units="days", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def lead_time_sugar():
|
|
return 1
|
|
|
|
|
|
@component.add(
|
|
name="Bread Production",
|
|
units="loaves/Day",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"base_rate": 1, "minresource": 1, "labour_efficiency": 1},
|
|
)
|
|
def bread_production():
|
|
return float(np.minimum(base_rate(), minresource())) * labour_efficiency()
|
|
|
|
|
|
@component.add(
|
|
name="Water Safety", units="litres", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def water_safety():
|
|
return 300
|
|
|
|
|
|
@component.add(
|
|
name="Sugar Purchase",
|
|
units="kg",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={
|
|
"bread_production": 1,
|
|
"suger_per_loaf": 1,
|
|
"sugar_safety": 1,
|
|
"sugar": 1,
|
|
"lead_time_sugar": 1,
|
|
},
|
|
)
|
|
def sugar_purchase():
|
|
return float(
|
|
np.maximum(
|
|
0,
|
|
(bread_production() * suger_per_loaf() + sugar_safety() - sugar())
|
|
/ lead_time_sugar(),
|
|
)
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Flour per Loaf", units="kg/loaf", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def flour_per_loaf():
|
|
return 0.3
|
|
|
|
|
|
@component.add(
|
|
name="Suger per Loaf", units="kg/loaf", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def suger_per_loaf():
|
|
return 0.02
|
|
|
|
|
|
@component.add(
|
|
name="MinSugarWater",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"sugar": 1, "suger_per_loaf": 1, "water_per_loaf": 1, "water": 1},
|
|
)
|
|
def minsugarwater():
|
|
return float(np.minimum(sugar() / suger_per_loaf(), water() / water_per_loaf()))
|
|
|
|
|
|
@component.add(
|
|
name="Yeast Purchase",
|
|
units="kg",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={
|
|
"bread_production": 1,
|
|
"yeast_per_loaf": 1,
|
|
"yeast_safety": 1,
|
|
"yeast": 1,
|
|
"lead_time_yeast": 1,
|
|
},
|
|
)
|
|
def yeast_purchase():
|
|
return float(
|
|
np.maximum(
|
|
0,
|
|
(bread_production() * yeast_per_loaf() + yeast_safety() - yeast())
|
|
/ lead_time_yeast(),
|
|
)
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Labour Efficiency",
|
|
units="Dmnl",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"available_workers": 1, "workers_required": 1},
|
|
)
|
|
def labour_efficiency():
|
|
return float(np.minimum(1, available_workers() / workers_required()))
|
|
|
|
|
|
@component.add(
|
|
name="Water",
|
|
units="litres",
|
|
comp_type="Stateful",
|
|
comp_subtype="Integ",
|
|
depends_on={"_integ_water": 1},
|
|
other_deps={
|
|
"_integ_water": {
|
|
"initial": {},
|
|
"step": {"water_purchase": 1, "water_per_loaf": 1, "bread_production": 1},
|
|
}
|
|
},
|
|
)
|
|
def water():
|
|
return _integ_water()
|
|
|
|
|
|
_integ_water = Integ(
|
|
lambda: water_purchase() - bread_production() * water_per_loaf(),
|
|
lambda: 2000,
|
|
"_integ_water",
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Water Cost", units="$/litre", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def water_cost():
|
|
return 0.001
|
|
|
|
|
|
@component.add(
|
|
name="Lead Time Water", units="days", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def lead_time_water():
|
|
return 1
|
|
|
|
|
|
@component.add(
|
|
name="Lead Time Yeast", units="days", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def lead_time_yeast():
|
|
return 1
|
|
|
|
|
|
@component.add(
|
|
name="Water Purchase",
|
|
units="litres",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={
|
|
"bread_production": 1,
|
|
"water_per_loaf": 1,
|
|
"water_safety": 1,
|
|
"water": 1,
|
|
"lead_time_water": 1,
|
|
},
|
|
)
|
|
def water_purchase():
|
|
return float(
|
|
np.maximum(
|
|
0,
|
|
(bread_production() * water_per_loaf() + water_safety() - water())
|
|
/ lead_time_water(),
|
|
)
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Workers Required",
|
|
units="workers",
|
|
comp_type="Constant",
|
|
comp_subtype="Normal",
|
|
)
|
|
def workers_required():
|
|
return 2
|
|
|
|
|
|
@component.add(
|
|
name="MinFlourYeast",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"flour": 1, "flour_per_loaf": 1, "yeast_per_loaf": 1, "yeast": 1},
|
|
)
|
|
def minflouryeast():
|
|
return float(np.minimum(flour() / flour_per_loaf(), yeast() / yeast_per_loaf()))
|
|
|
|
|
|
@component.add(
|
|
name="MinResource",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"minflouryeast": 1, "minsugarwater": 1},
|
|
)
|
|
def minresource():
|
|
return float(np.minimum(minflouryeast(), minsugarwater()))
|
|
|
|
|
|
@component.add(
|
|
name="Water per Loaf",
|
|
units="litres/loaf",
|
|
comp_type="Constant",
|
|
comp_subtype="Normal",
|
|
)
|
|
def water_per_loaf():
|
|
return 0.2
|
|
|
|
|
|
@component.add(
|
|
name="Waste Bread", units="loaves/Day", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def waste_bread():
|
|
return 2
|
|
|
|
|
|
@component.add(
|
|
name="Raw Material Cost",
|
|
units="$",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={
|
|
"flour_cost": 1,
|
|
"flour_purchase": 1,
|
|
"sugar_purchase": 1,
|
|
"sugar_cost": 1,
|
|
"yeast_purchase": 1,
|
|
"yeast_cost": 1,
|
|
"water_purchase": 1,
|
|
"water_cost": 1,
|
|
},
|
|
)
|
|
def raw_material_cost():
|
|
return (
|
|
flour_cost() * flour_purchase()
|
|
+ sugar_cost() * sugar_purchase()
|
|
+ yeast_cost() * yeast_purchase()
|
|
+ water_cost() * water_purchase()
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Yeast Safety", units="kg", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def yeast_safety():
|
|
return 10
|
|
|
|
|
|
@component.add(
|
|
name="Sugar Safety", units="kg", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def sugar_safety():
|
|
return 20
|
|
|
|
|
|
@component.add(
|
|
name="Bread",
|
|
units="loaves",
|
|
comp_type="Stateful",
|
|
comp_subtype="Integ",
|
|
depends_on={"_integ_bread": 1},
|
|
other_deps={
|
|
"_integ_bread": {
|
|
"initial": {},
|
|
"step": {"bread_production": 1, "waste_bread": 1, "sales": 1},
|
|
}
|
|
},
|
|
)
|
|
def bread():
|
|
return _integ_bread()
|
|
|
|
|
|
_integ_bread = Integ(
|
|
lambda: bread_production() - waste_bread() - sales(), lambda: 0, "_integ_bread"
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Flour",
|
|
units="kg",
|
|
comp_type="Stateful",
|
|
comp_subtype="Integ",
|
|
depends_on={"_integ_flour": 1},
|
|
other_deps={
|
|
"_integ_flour": {
|
|
"initial": {},
|
|
"step": {"flour_purchase": 1, "flour_per_loaf": 1, "bread_production": 1},
|
|
}
|
|
},
|
|
)
|
|
def flour():
|
|
return _integ_flour()
|
|
|
|
|
|
_integ_flour = Integ(
|
|
lambda: flour_purchase() - flour_per_loaf() * bread_production(),
|
|
lambda: 1000,
|
|
"_integ_flour",
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Flour Cost", units="$/kg", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def flour_cost():
|
|
return 0.5
|
|
|
|
|
|
@component.add(
|
|
name="Flour Purchase",
|
|
units="kg",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={
|
|
"bread_production": 1,
|
|
"flour_per_loaf": 1,
|
|
"flour_safety": 1,
|
|
"flour": 1,
|
|
"lead_time_flour": 1,
|
|
},
|
|
)
|
|
def flour_purchase():
|
|
return float(
|
|
np.maximum(
|
|
0,
|
|
(bread_production() * flour_per_loaf() + flour_safety() - flour())
|
|
/ lead_time_flour(),
|
|
)
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Flour Safety", units="kg", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def flour_safety():
|
|
return 200
|
|
|
|
|
|
@component.add(
|
|
name="Labour Cost",
|
|
units="$",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"wage_rate": 1, "total_labour_hours": 1},
|
|
)
|
|
def labour_cost():
|
|
return wage_rate() * total_labour_hours()
|
|
|
|
|
|
@component.add(
|
|
name="Lead Time Flour", units="days", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def lead_time_flour():
|
|
return 1
|
|
|
|
|
|
@component.add(
|
|
name="Maintainance Cost",
|
|
units="$",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"maintainance_rate": 1, "money": 1},
|
|
)
|
|
def maintainance_cost():
|
|
return maintainance_rate() * money()
|
|
|
|
|
|
@component.add(
|
|
name="Maintainance Rate",
|
|
units="fraction/Day",
|
|
comp_type="Constant",
|
|
comp_subtype="Normal",
|
|
)
|
|
def maintainance_rate():
|
|
return 0.002
|
|
|
|
|
|
@component.add(
|
|
name="Money",
|
|
units="$",
|
|
comp_type="Stateful",
|
|
comp_subtype="Integ",
|
|
depends_on={"_integ_money": 1},
|
|
other_deps={
|
|
"_integ_money": {
|
|
"initial": {},
|
|
"step": {
|
|
"revenue": 1,
|
|
"labour_cost": 1,
|
|
"maintainance_cost": 1,
|
|
"raw_material_cost": 1,
|
|
},
|
|
}
|
|
},
|
|
)
|
|
def money():
|
|
return _integ_money()
|
|
|
|
|
|
_integ_money = Integ(
|
|
lambda: revenue() - labour_cost() - maintainance_cost() - raw_material_cost(),
|
|
lambda: 100000,
|
|
"_integ_money",
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Revenue",
|
|
units="$",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"sales_price": 1, "sales": 1},
|
|
)
|
|
def revenue():
|
|
return sales_price() * sales()
|
|
|
|
|
|
@component.add(
|
|
name="Sales",
|
|
units="loaves/Day",
|
|
comp_type="Auxiliary",
|
|
comp_subtype="Normal",
|
|
depends_on={"bread": 1, "demand": 1},
|
|
)
|
|
def sales():
|
|
return float(np.minimum(bread(), demand()))
|
|
|
|
|
|
@component.add(
|
|
name="Sales Price", units="$/loaf", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def sales_price():
|
|
return 4
|
|
|
|
|
|
@component.add(
|
|
name="Sugar",
|
|
units="kg",
|
|
comp_type="Stateful",
|
|
comp_subtype="Integ",
|
|
depends_on={"_integ_sugar": 1},
|
|
other_deps={
|
|
"_integ_sugar": {
|
|
"initial": {},
|
|
"step": {"sugar_purchase": 1, "suger_per_loaf": 1, "bread_production": 1},
|
|
}
|
|
},
|
|
)
|
|
def sugar():
|
|
return _integ_sugar()
|
|
|
|
|
|
_integ_sugar = Integ(
|
|
lambda: sugar_purchase() - bread_production() * suger_per_loaf(),
|
|
lambda: 100,
|
|
"_integ_sugar",
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Sugar Cost", units="$/kg", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def sugar_cost():
|
|
return 0.8
|
|
|
|
|
|
@component.add(
|
|
name="Total Labour Hours",
|
|
units="hours/Day",
|
|
comp_type="Constant",
|
|
comp_subtype="Normal",
|
|
)
|
|
def total_labour_hours():
|
|
return 16
|
|
|
|
|
|
@component.add(
|
|
name="Wage Rate", units="$/Hour", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def wage_rate():
|
|
return 12
|
|
|
|
|
|
@component.add(
|
|
name="Yeast",
|
|
units="kg",
|
|
comp_type="Stateful",
|
|
comp_subtype="Integ",
|
|
depends_on={"_integ_yeast": 1},
|
|
other_deps={
|
|
"_integ_yeast": {
|
|
"initial": {},
|
|
"step": {"yeast_purchase": 1, "yeast_per_loaf": 1, "bread_production": 1},
|
|
}
|
|
},
|
|
)
|
|
def yeast():
|
|
return _integ_yeast()
|
|
|
|
|
|
_integ_yeast = Integ(
|
|
lambda: yeast_purchase() - bread_production() * yeast_per_loaf(),
|
|
lambda: 50,
|
|
"_integ_yeast",
|
|
)
|
|
|
|
|
|
@component.add(
|
|
name="Yeast Cost", units="$/kg", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def yeast_cost():
|
|
return 10
|
|
|
|
|
|
@component.add(
|
|
name="Yeast per Loaf", units="kg/loaf", comp_type="Constant", comp_subtype="Normal"
|
|
)
|
|
def yeast_per_loaf():
|
|
return 0.01
|