Discrete Event Simulation¶
The discrete event simulation (DES) consists of:
A Context instance which stores supply-chain-level information and methods.
Many Component instances that transition through the supply chain during the simulation.
A Facility Inventory for every facility in the supply chain: this inventory records material flows.
A Transportation Tracker for every facility in the supply chain with inbound material flows.
Context¶
-
class
celavi.des.
Context
(locations_filename: str, step_costs_filename: str, component_material_masses_filename: str, possible_components: List[str], possible_materials: List[str], cost_graph: celavi.costgraph.CostGraph, lca: celavi.pylca_celavi.des_interface.PylcaCelavi, cost_graph_update_interval_timesteps: int, path_dict: Dict = None, min_year: int = 2000, end_year: int = 2050, max_timesteps: int = 600, timesteps_per_year: int = 12, model_run: int = 0, verbose: int = 0)¶ The Context class:
Provides the discrete time sequence for the model
Holds all the components in the model
Holds parameters for pathway cost models (dictionary)
Links the CostGraph to the DES model
Provides translation of years to timesteps and back again
-
__init__
(locations_filename: str, step_costs_filename: str, component_material_masses_filename: str, possible_components: List[str], possible_materials: List[str], cost_graph: celavi.costgraph.CostGraph, lca: celavi.pylca_celavi.des_interface.PylcaCelavi, cost_graph_update_interval_timesteps: int, path_dict: Dict = None, min_year: int = 2000, end_year: int = 2050, max_timesteps: int = 600, timesteps_per_year: int = 12, model_run: int = 0, verbose: int = 0)¶ - Parameters
locations_filename (str) – Path to the processed facility locations dataset.
step_costs_filename (str) – Path to the step_costs dataset that determines the process steps in each facility.
component_material_masses_filename (str) – Path to the dataset specifying component composition (materials and masses) over time.
possible_components (List[str]) – The list of possible technology components.
possible_materials (List[str]) – The possible materials in the components. This should span all component types.
cost_graph (CostGraph) – The CostGraph instance to use with this Context instance.
lca (PylcaCelavi) – The pyLCIA instance to use with this Context instance.
cost_graph_update_interval_timesteps (int) – Frequency at which the process costs within the CostGraph instance are re-calculated.
path_dict (Dict) – Dictionary of parameters for the learning-by-doing models and all other pathway cost models. The structure and content of this dictionary will vary by case study and is specified in the Scenario configuration file.
min_year (int) – Simulation start (calendar) year. Optional. If left unspecified defaults to 2000.
max_timesteps (int) – The maximum number of discrete timesteps in the simulation. Defaults to 200 or an end year of 2050.
timesteps_per_year (int) – The number of timesteps in one simulation year. Default value is 12 timesteps per year, corresponding to a monthly model resolution.
model_run (int) – Model run identifier
verbose (int) – toggle print statements of LCA mass available and calculation steps 0 = no prints. 1 = all prints.
-
years_to_timesteps
(year: float) → int¶ Convert calendar year into the corresponding timestep of the discrete event model.
- Parameters
year (float) – The year can have a fractional part. The result of the conversion is rounding to the nearest integer.
- Returns
The DES timestep that corresponds to the year.
- Return type
int
-
timesteps_to_years
(timesteps: int) → float¶ Convert the discrete DES timestep to a fractional calendar year.
- Parameters
timesteps (int) – The discrete timestep number. Must be an integer.
- Returns
The year converted from the discrete timestep.
- Return type
float
-
populate
(df: pandas.core.frame.DataFrame, lifespan_fns: Dict[str, Callable[], float]])¶ Before a model can run, components must be loaded into it. This method loads components from a DataFrame, has the following columns which correspond to the attributes of a component object:
Each component is placed into a process that will timeout when the component begins its useful life, as specified in year. From there, choices about the component’s lifecycle are made as further processes time out and decisions are made at subsequent timesteps.
- Parameters
df (pd.DataFrame) –
The DataFrame which has components specified in the columns below.
- Columns:
- kind: str
The type of component as a string. It isn’t called “type” because “type” is a keyword in Python.
- year: float
The year the component goes into use.
- mass_tonnes: float
The mass of the component in tonnes.
lifespan_fns (Dict[str, Callable[[], float]]) – A dictionary with the kind of component as the key and a Callable (probably a lambda function) that takes no arguments and returns a float as the value. When called, the value should return a value sampled from a probability distribution that corresponds to a predicted lifespan of the component. The key is used to call the value in a way similar to the following: lifespan_fns[row[“kind”]]()
-
cumulative_mass_for_component_in_process_at_timestep
(component_kind: str, process_name: List[str], timestep: int)¶ Calculate the cumulative mass at a certain time of a given component passed through processes that contain the given name.
For example, if you want to find cumulative component mass passed through coarse grinding facilities at time step 100, this is your method!
Note: This uses the average component mass for the year, not the sum of facility inventories.
- Parameters
component_kind (str) – The kind of component (such as “blade” passing through an inventory)
process_name (str) – The process name (such as “fine griding”) to look for in the facility inventory names.
timestep (int) – The time, in timestep, to calculate the cumulative inventory for.
- Returns
Total cumulative mass of the component in the process at the timestep.
- Return type
float
-
pylca_interface_process
(env)¶ pylca_interface_process() runs periodically to update the LCIA model with results from the DES model. It updates the LCA code with the latest distance and mass flow calculations.
It only calls the LCA code for timesteps where the mass_kg > 0. Years with zero mass flows are not passed to the LCA.
- Parameters
env (Environment) – The SimPy environment this process belongs to.
-
average_total_component_mass_for_year
(year)¶ Totals the masses of all materials in a component for a given year.
- Parameters
year (float) – The floating point year. Will be rounded to nearest integer year with int() and floor()
- Returns
Average total component mass for a year.
- Return type
float
-
update_cost_graph_process
(env)¶ This is the SimPy process that updates the cost graph periodically.
-
run
() → Dict[str, celavi.inventory.FacilityInventory]¶ This method executes the discrete event simulation.
- Returns
A dictionary of inventories mapped to their cumulative histories.
- Return type
Dict[str, pd.DataFrame]
Component¶
A technology component is the basic unit of a CELAVI simulation. A component has one or more constituent materials that are also tracked.
-
class
celavi.component.
Component
(context, kind: str, year: int, lifespan_timesteps: float, manuf_facility_id: int, in_use_facility_id: int, mass_tonnes: Dict[str, float] = 0)¶ The Component class works with the Context class to run the discrete event simulation. There is one instance of Component per physical component in the simulation. This class models each step in the lifecycle of the component, from begining of life (BOL) to end of life (EOL).
-
__init__
(context, kind: str, year: int, lifespan_timesteps: float, manuf_facility_id: int, in_use_facility_id: int, mass_tonnes: Dict[str, float] = 0)¶ This takes parameters named the same as the instance variables. See the comments for the class for further information about instance attributes.
It sets the initial state, which is an empty string. This is because there is no state until the component begins life, when the process defined in method begin_life() is called by SimPy.
- Parameters
context (Context) – The context that contains this component.
kind (str) – The type of this component. It isn’t called “type” because “type” is a keyword in Python.
year (int) – The calendar year in which this component enters the in use state for the first time.
lifespan_timesteps (float) – The component useful lifetime: the period, in timesteps, that the component spends in its first in use state. The argument can be provided as a floating point value, but it is converted into an integer before it is assigned to the instance attribute. This allows components to have either fixed integer lifespans, fixed float lifespans, or lifespans defined with a Weibull probability distribution.
mass_tonnes (Dict[str, float]) – Component composition by material, in tonnes. Keys are material names. Values are material masses.
manuf_facility_id (int) – The facility id where the component begins life (typically but not necessarily a manufacturing facility type) used in initial pathway selection from CostGraph.
in_use_facility_id (int) – The facility ID where the component spends its first useful lifetime before beginning the end-of-life process (typically but not necessarily a renewable energy power plant).
-
create_pathway_queue
(from_facility_id: int)¶ Query the CostGraph instance and construct a queue of the lifecycle for this component. This method is called during the manufacturing step and during the eol_process when exiting the in use stage.
This method does not return anything, rather it modifies the instance attribute self.pathway with a new deque.
- Parameters
from_facility_id (int) – The starting location of the the component.
-
bol_process
(env)¶ This process starts the lifecycle for this component. Since it is only called once, it does not have a loop, like most other SimPy processes. When the component reaches end-of-life, this method sets the end-of-life (EOL) pathway for the component.
- Parameters
env (simpy.Environment) – The SimPy environment running the DES timesteps.
-
eol_process
(env)¶ This process controls the state transitions for the component at each end-of-life (EOL) event.
- Parameters
env (simpy.Environment) – The environment in which this process is running.
-
move_component_to
(env, loc, dist: float, route_id=None, amt=1.0)¶ Increment mass, count, and transportation inventories.
- Parameters
env (simpy.Environment) – The environment in which this process is running.
loc (int) – Destination facility ID.
dist (float) – Transportation distance in km to destination facility.
route_id (str) – UUID for route along which component is moved. Defaults to None.
amt (float) – Number of components being moved. Defaults to 1.
-
move_component_from
(env, loc, amt=1.0)¶ Decrement mass and count inventories at the current facility.
Only INBOUND transportation is tracked, thus no transportation tracking is done by this method.
- Parameters
env (simpy.Environment) – The environment in which this process is running.
loc (int) – Current facility ID.
amt (float) – Number of components being moved. Defaults to 1.
-
Facility Inventory¶
-
class
celavi.inventory.
FacilityInventory
(facility_id: int, facility_type: str, step: str, possible_items: List[str], timesteps: int, quantity_unit: str = 'tonne', can_be_negative: bool = False)¶ The inventory class holds an inventory of materials and quantities for a landfill, virgin material extraction, or recycled material availability.
-
__init__
(facility_id: int, facility_type: str, step: str, possible_items: List[str], timesteps: int, quantity_unit: str = 'tonne', can_be_negative: bool = False)¶ - Parameters
facility_id (int) – The unique facility ID from the processed facility locations dataset.
facility_type (str) – The type of the facility from the locations table.
step (str) – The processing step that is held by this inventory.
possible_items (List[str]) – A list of strings (e.g., “Nacelle Aluminum”) that represent all possible component materials that may be stored in this inventory.
timesteps (int) – The number of discrete timesteps in the simulation that this inventory will hold.
quantity_unit (str) – The unit in which the quantity is recorded.
can_be_negative (bool) – True if the quantity in this inventory can be negative. If False, the quantity must always be positive, and the instance will raise an exception if there is an attempt of a negative transaction.
-
increment_quantity
(item_name: str, quantity: float, timestep: int) → float¶ Changes the material quantity in this inventory.
For virgin material extractions, the quantity should be negative to indicate a withdrawal.
For landfills and other facility types where components or materials accumulate or are stored, the quantity should be positive to indicate a deposit of material.
For other facility inventories, the quantity can either be positive or negative, depending on if there is an increase in supply or a decrease in supply at a particular facility inventory.
- Parameters
item_name (str) – The material being deposited or withdrawn
quantity (int) – The quantity of the material, either positive or negative.
timestep (int) – The timestep of this deposit or withdrawal or deposit (depending on the sign of the quantity).
- Returns
The new quantity of the material.
- Return type
int
-
property
cumulative_history
¶ Calculate the cumulative level of a facility inventory over all its transactions.
For facilities where material is not stored and does not accumulate, the cumulative history will be zero. The cumulative_input_history will be more informative for facilities of this type.
- Returns
The cumulative history of all the transactions of the component materials.
- Return type
pd.DataFrame
-
property
cumulative_input_history
¶ Calculate the cumulative input quantities of a facility inventory over all its input transactions.
- Returns
The cumulative history of all the transactions of the component materials.
- Return type
pd.DataFrame
-
property
transaction_history
¶ Convert a dictionary of transactions at this facility into a DataFrame.
Because this method instantiates a DataFrame, it should be called sparingly, as this is a resource consuming procedure.
- Returns
The history of transactions in dataframe form.
- Return type
pd.DataFrame
-
property
input_transaction_history
¶ Convert a dictionary of input transactions at this facility into a DataFrame.
Because this method instantiates a DataFrame, it should be called sparingly, as this is a resource consuming procedure.
- Returns
The history of input transactions in dataframe form.
- Return type
pd.DataFrame
-
Critical Instance Variables¶
These variables are passed to other classes and methods within CELAVI.
- self.component_materials: Dict[str, float]
The cumulative amount of component materials over the entire lifetime of the simulation.
- self.component_materials_deposits: List[Dict[str, float]]
The history of the deposits from this inventory. These are instantaneous, not cumulative, values.
Transportation Tracker¶
-
class
celavi.transportation_tracker.
TransportationTracker
(timesteps)¶ The TransportationTracker class inbound tonne*km values into a facility. What distinguishes this class from the FacilityInventory is that the inbound tonne_km only increments.
-
__init__
(timesteps)¶ - Parameters
timesteps – An integer of the maximum number of timesteps that will be recorded in the model.
-
increment_inbound_tonne_km
(tonne_km, timestep, route_id=None)¶ - Parameters
tonne_km – A float of the number of tonne*km being transported during the given timestep.
timestep – The timestep that is being incremented.
route_id – UUID for the route along which material is transported
-