Introduction
MUSE 2.0 is a tool for running simulations of energy systems, written in Rust. It is a slimmer and faster version of the older MUSE tool. To get started, please look at the user guide and the command line help.
For an overview of the model, see the model description and the dispatch optimisation formulation. For a list of relevant terms, see the glossary.
If you are a developer, please see the developer guide.
User Guide
Running MUSE 2.0
Once you have installed MUSE 2.0, you should be able to run it via the muse2
command-line program.
For details of the command-line interface, see here.
Setting the log level
MUSE uses the fern
crate for logging. The default log level is info
, though this can be
configured either via the log_level
option in settings.toml
or by setting the
MUSE2_LOG_LEVEL
environment variable. (If both are used, the environment variable takes
precedence.)
The possible options are:
error
warn
info
debug
trace
off
By default, MUSE will colourise the log output if this is available (i.e. it is outputting to a terminal rather than a file).
For more information, please consult the fern
documentation.
Input file format
This file contains information about the input file format for MUSE 2.0.
Time slices
time_slices.csv
Time slices define how the year is divided up. Each time slice is composed of a season and a time
of day. Often, this is written separated by a dot (e.g. winter.day
).
Field | Description | Notes |
---|---|---|
season | Name of season | |
time_of_day | Name of time of day | |
fraction | Fraction of year | Must be >0 and <=1 |
Notes
- The fractions for the different time slices must sum to one.
Regions
regions.csv
Describes regions in the system.
Field | Description | Notes |
---|---|---|
id | A unique identifier for a region | |
description | A human-readable label for the region |
Agents
agent_commodity_portions.csv
Portions of commodity demand for which agents are responsible.
Field | Description | Notes |
---|---|---|
agent_id | The agent to apply these values to | |
commodity_id | The commodity for which the agent is responsible | |
years | The year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
commodity_portion | Portion of commodity demand | Value must be >0 and <=1. The portion applies only to the specified years. |
Notes
- If an entry is specified for one agent and commodity, there must be entries covering all milestone years.
- For each agent listed in this file, the total portions for each region/commodity/year combination must sum to one.
- In addition, there must be entries for every SVD and SED commodity for all regions and milestone years.
agent_cost_limits.csv
Limits on expenditure for agents.
Field | Description | Notes |
---|---|---|
agent_id | The agent to apply these values to | |
years | The year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
capex_limit | Maximum capital cost the agent will pay | Must be >0. Optional (defaults to infinity). |
annual_cost_limit | Maximum annual operating cost | The maximum annual operating cost (fuel plus variable operating cost etc.) that the agent will pay. Must be >0. Optional (defaults to infinity). |
Notes
- If cost limits are provided for an agent, they must be present for all years.
agent_objectives.csv
Describes the agents' objectives.
Field | Description | Notes |
---|---|---|
agent_id | An agent ID | |
years | The year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
objective_type | The type of objective | Currently only lcox is supported |
decision_weight | Weight for weighted sum decision rule | Currently unused |
decision_lexico_order | Order in which to consider objectives for lexico decision rule | Currently unused |
Notes
- Every agent must have one objective for each milestone year.
- If the weighted sum decision rule is in use, the
decision_weight
value must be provided, otherwise it must be omitted. - If the lexico decision rule is in use, the
decision_lexico_order
value must be provided, otherwise it must be omitted.
agent_search_space.csv
Defines the processes in which an agent will invest for given parameters.
Field | Description | Notes |
---|---|---|
agent_id | An agent ID | |
commodity_id | The commodity to which this entry applies | |
years | The year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
search_space | The processes in which this agent will invest | One or more process IDs separated by semicolons. If this field is empty or all , all processes will be considered. |
Notes
- If entries are missing for any combination of agent, commodity or milestone year, then it is assumed that all processes can be considered in this case.
agents.csv
Describes agents in the system.
Field | Description | Notes |
---|---|---|
id | A unique identifier for an agent | |
description | A human-readable label for the agent | |
regions | The region(s) in which the agent operates | One or more region IDs, separated by semicolons or the string all |
decision_rule | The decision rule applied to objectives | Currently the only supported rule is simple |
decision_lexico_tolerance | Tolerance for lexico decision rule | Currently unused |
Assets
assets.csv
Defines assets in the system.
Field | Description | Notes |
---|---|---|
process_id | The process of which this asset is an instance | |
region_id | The region in which this agent operates | |
agent_id | The agent to which this asset belongs | |
capacity | The capacity of the asset | Must be >0 |
commission_year | The year in which to commission this asset | This value can be any integer >=0. If it is before the start of the simulation, it will already be commissioned in the first year and if it after the end of the simulation then it will never be commissioned. |
Commodities
commodities.csv
Describes commodities in the system.
Field | Description | Notes |
---|---|---|
id | A unique identifier for the commodity | |
description | A human-readable label for the commodity | |
type | The type of commodity | Must be one of svd (service demand), sed (supply equals demand), inc (input commodity) or ouc (output commodity) |
time_slice_level | The time slice level at which constraints for this commodity are applied | Must be one of annual (whole year), season (whole season) or daynight (a particular time of day) |
Notes
- Every SED (supply equals demand) commodity must have both producer and consumer processes for every region and milestone year.
- Every SVD (service demand) commodity must have a producer for every region and milestone year.
commodity_levies.csv
Defines levies for commodities (or, if value
is negative, incentives).
Field | Description | Notes |
---|---|---|
commodity_id | The commodity to which this entry applies | |
regions | The region(s) to which this entry applies | One or more region IDs, separated by semicolons or the string all |
years | The year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
time_slice | The time slices(s) to which this entry applies | Can be a single time slice (e.g. winter.day ), a whole season (e.g. winter ) or annual , representing the whole year |
balance_type | The type of balance to which this is applied | Can be cons (applies to consumption only), prod (applies to production only) or net (applies to consumption and production) |
value | The value of the levy/incentive |
Notes
- If an entry is included for a given combination of commodity and region, entries must be provided covering all milestone years and time slices.
demand.csv
Specifies the demand for service demand commodities.
Field | Description | Notes |
---|---|---|
commodity_id | The service demand commodity to which this entry applies | |
region_id | The region to which this entry applies | A region ID |
year | The year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
demand | Total demand for this year |
Notes
- Every service demand commodity must have entries in this file covering every combination of milestone year and region.
demand_slicing.csv
Specifies how demand is distributed throughout the year (i.e. for different milestones).
Field | Description | Notes |
---|---|---|
commodity_id | The service demand commodity to which this entry applies | |
region_id | The region to which this entry applies | A region ID |
time_slice | The time slices(s) to which this entry applies | Can be a single time slice (e.g. winter.day ), a whole season (e.g. winter ) or annual , representing the whole year |
fraction | The fraction of annual demand for this entry | Must be >0 and <=1 |
Notes
- The user must provide entries covering every combination of service demand commodity, region and time slice.
- For each combination, the sum of the fractions must equal one.
Processes
process_availabilities.csv
Defines how much of a process's capacity is available throughout the year.
Field | Description | Notes |
---|---|---|
process_id | The process to which this entry applies | |
regions | The region(s) to which this entry applies | One or more region IDs, separated by semicolons or the string all |
years | The milestone year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
time_slice | The time slices(s) to which this entry applies | Can be a single time slice (e.g. winter.day ), a whole season (e.g. winter ) or annual , representing the whole year |
limit_type | The type of limit | Can be lo (a lower bound), hi (an upper bound) or fx (indicating that the availability is constant) |
value | The proportion of capacity which is available | Must be >0 and <=1 |
Notes
- Must be provided for every process.
- Only one type of limit can be supplied for each combination of process/region/year/time slice.
process_flows.csv
The commodity flows for each process.
Field | Description | Notes |
---|---|---|
process_id | The process to which this entry applies | |
commodity_id | The commodity for this flow | |
regions | The region(s) to which this entry applies | One or more region IDs, separated by semicolons or the string all . Must be regions in which the process operates. |
years | The year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
coeff | The flow for this commodity | Can be <0, indicating an input flow, or >0, indicating an output flow. Cannot be zero. |
type | The type of commodity flow | Currently this value must be fixed |
cost | The cost per unit flow | Optional. If present, must be >0. |
Notes
- Commodity flows can vary by region and year.
- For each process, there must be entries covering all the years and regions in which the process operates.
process_parameters.csv
Parameters for processes which vary by region and year.
Field | Description | Notes |
---|---|---|
process_id | The process to which this entry applies | |
regions | The region(s) to which this entry applies | One or more region IDs, separated by semicolons or the string all . Must be regions in which the process operates. |
years | The milestone year(s) to which this entry applies | One or more milestone years separated by semicolons or all |
capital_cost | Overnight capital cost per unit capacity | |
fixed_operating_cost | Annual operating cost per unit capacity | |
variable_operating_cost | Annual variable operating cost per unit activity | |
lifetime | Lifetime in years of an asset created from this process | Must be a positive integer |
discount_rate | Process-specific discount rate | Must be positive. A warning will be issued if this number is >1. |
capacity_to_activity | Factor for calculating the maximum consumption/production over a year. | Must be >=0 |
Notes
- For each process, entries must be provided which cover every combination of milestone year and region in which the process operates.
processes.csv
Describes processes in the system.
Field | Description | Notes |
---|---|---|
id | A unique identifier for a process | |
description | A human-readable label for the process | |
regions | The region(s) in which this process can operate | One or more region IDs, separated by semicolons or the string all |
start_year | The first year when this process is available to agents | |
end_year | The last year when this process is available to agents | Must be >= to start_year |
Command-Line Help for muse2
This document contains the help content for the muse2
command-line program.
Command Overview:
muse2
A tool for running simulations of energy systems
Usage: muse2 [COMMAND]
Subcommands:
run
— Run a simulation modelexample
— Manage example models
muse2 run
Run a simulation model
Usage: muse2 run [OPTIONS] <MODEL_DIR>
Arguments:
<MODEL_DIR>
— Path to the model directory
Options:
-o
,--output-dir <OUTPUT_DIR>
— Directory for output files--debug-model
— Whether to write additional information to CSV files
muse2 example
Manage example models
Usage: muse2 example <COMMAND>
Subcommands:
list
— List available examplesextract
— Extract an example model configuration to a new directoryrun
— Run an example
muse2 example list
List available examples
Usage: muse2 example list
muse2 example extract
Extract an example model configuration to a new directory
Usage: muse2 example extract <NAME> [NEW_PATH]
Arguments:
<NAME>
— The name of the example to extract<NEW_PATH>
— The destination folder for the example
muse2 example run
Run an example
Usage: muse2 example run [OPTIONS] <NAME>
Arguments:
<NAME>
— The name of the example to run
Options:
-o
,--output-dir <OUTPUT_DIR>
— Directory for output files--debug-model
— Whether to write additional information to CSV files
This document was generated automatically by
clap-markdown
.
Model Description
Introduction
Model Purpose
This Software Requirements Specification (SRS) describes MUSE 2.0 (ModUlar energy systems Simulation Environment). The purpose of MUSE is to provide users with a framework to simulate pathways of energy system transition, usually in the context of climate change mitigation.
Model Scope
MUSE is an Integrated Assessment Modelling framework that is designed to enable users to create and apply an agent-based model that simulates a market equilibrium on a set of user-defined commodities, over a user-defined time period, for a user-specified region or set of regions. MUSE was developed to simulate approaches to climate change mitigation over a long time horizon (e.g. 5-year steps to 2050 or 2100), but the framework is generalised and can therefore simulate any market equilibrium.
Overall Description
Overview
MUSE 2.0 is the successor to MUSE. The original MUSE framework is open-source software available on GitHub, coded in Python. MUSE 2.0 is implemented following re-design of MUSE to address a range of legacy issues that are challenging to address via upgrades to the existing MUSE framework, and to implement the framework in the high-performance Rust language.
MUSE is classified as a recursive dynamic modelling framework in the sense that it iterates on a single time period to find a market equilibrium, and then moves to the next time period. Agents in MUSE have limited foresight, reacting only to information available in the current time period. This is distinct from intertemporal optimisation modelling frameworks (such as TIMES and MESSAGEix) which have perfect foresight over the whole modelled time horizon.
Model Concept
MUSE 2.0 is a bottom-up engineering-economic modelling framework that computes a price-induced supply-demand equilibrium on a set of user-defined commodities. It does this for each milestone time period within a user-defined time horizon. This is a "partial equilibrium" in the sense that the framework equilibrates only the user-defined commodities, as opposed to a whole economy.
MUSE 2.0 is data-driven in the sense that model processing and data are entirely independent, and user-defined data is at the heart of how the model behaves. It is also "bottom-up" in nature, which means that it requires users to characterise each individual process that produces or consumes each commodity, along with a range of other physical, economic and agent parameters.
At a high level, the user defines:
-
The overall temporal arrangements, including the base time period, milestone time periods and time horizon, and within-period time slice lengths.
-
The service demands for each end-use (e.g. residential heating, steel production), for each region, and how that demand is distributed between the user-defined time slices within the year. Service demands must be given a value for the base time period and all milestone time periods in each region.
-
The existing capacity of each process (i.e. assets) in the base time period, and the year in which it was commissioned or will be decommissioned.
-
The techno-economic attributes (e.g. capital cost, operating costs, efficiency, lifetime, input and output commodities, etc) of each process. This must include attributes of processes existing in the base time period (i.e. assets) and possible future processes that could be adopted in future milestone time periods.
-
The agents that choose between technologies by applying search spaces, objectives and decision rules. Portions of demand for each commodity must be assigned to an agent, and the sum of these portions must be one.
The model takes this data, configures and self-checks, and then solves for a system change pathway:
- Initialisation
- Commodity Price Discovery
- Agent Investment
- Carbon Budget Solution (or CO2 Price Responsiveness)
- Recursively Solve Using Steps (2) to (5) for Each Milestone Year until End
Framework Processing Flow
The MUSE 2.0 solution concept is as follows:
1. Initialisation
Read input data, performing basic temporal set up, commodity and process/asset information. A range of input data consistency checks are performed.
2. Commodity Price Discovery
Dispatch Optimisation (hereon "dispatch") is executed to determine commodity production and consumption, with fixed asset capacities. In the first milestone year - the calibrated base year - this step is performed before any agent investment step. In later milestone years, it is performed after agent investment is complete to determine prices for the following milestone year alongside production/consumption of all commodities.
A. Price discovery via asset dispatch optimisation using dual solution
Asset dispatch is determined via linear programming, where the objective function is the cost of operating the system over a year, which must be minimised. The dual solution of this optimisation is used to discover commodity price. The methodology for dispatch is described in detail in the Dispatch Optimisation section of the documentation.
Price is discovered for each commodity, for each time slice, and for each region, using the dual solution from the dispatch optimisation. Price is determined for each time slice by (a) taking the dual value for the commodity balance constraint, (b) adding the dual value of the capacity/availability constraint (this step is performed separately for each asset/process), and then (c) taking the maximum value from the set of results from steps a-b.
The result is a time sliced price for each commodity in each region.
B. Price discovery for commodities not produced
We also calculate the prices of commodities that are not present in the dispatch solution, but could exist in the solution for the next milestone year. These are calculated directly from input data. This is done by calculating the marginal price of the process producing the commodity in question with the best decision value, assuming maximum utilisation.
Issue 1: There may be a better way to do this step 2(B). One could add all processes that could potentially exist in the milestone year to the dispatch optimisation formulation, even those that do not have a related asset (i.e. they have no capacity in the milestone year). A commodity balance constraint could then be created for every commodity, even those that are not yet produced. Marginal prices could be observed from the dispatch optimisation result as per other commodity prices. This would need to be tried out to see if it works.
3. Agent Investment
The capacity investment of new assets required in the next milestone year are calculated as follows:
A. End-of-life capacity decommissioning
We decommission assets that have reached the end of their life in the milestone year.
B. Agent investment
Starting with each service demand (SVD) commodity, for each agent that produces that commodity:
i. Determine potential utilisation at time slice level
For each asset/process that produces the commodity, we calculate the potential dispatch in each time slice. This is done by observing the amount of demand that is above the marginal cost of this process in the solution for the previous milestone year (i.e. demand that the process could competitively serve assuming nothing changes from the previous milestone year).
For example, if demand is 8 units, and asset A serves 2 units of that at a marginal cost of $3, and asset B serves 4 units at a marginal cost of $5, but process C has a marginal cost of $4, then the algorithm assumes that process C could serve up to 6 units of demand in that time slice (though also limited by its capacity/availability constraints in this and other time slices, etc).
If the asset/process has lower marginal cost than any asset in a time slice, we assume dispatch only limited by capacity/availability constraints and demand level. If the process has the same marginal cost as an asset, we assume that asset is NOT displaced. If the process has marginal cost higher than any asset, we assume it can only serve demand currently unserved (i.e. due to asset decommissioning at 3(A) or demand increase), if any exists. If there is no asset (e.g. where demand was zero in previous milestone year, or all existing assets were decommissioned) then we assume dispatch only limited by process capacity/availability constraints and demand level.
ii. Calculate objective and decision values for each asset/process
Using the resulting set of time sliced potential utilisations, we then calculate the objective value/s and decision values for the asset/process. For assets, the objective value is calculated without including capital costs (which are sunk unrecoverable costs).
Issue 2: There are some complications here, e.g. where an asset/process has availability constraints that interact across time slices, so one cannot consider one time slice at a time. Or when a process has both annual and time slice level availability constraints, which interact.
iii. Add new asset or confirm asset not decommissioned
We add the best asset/process (based on objective/s and decision rule) to the capacity mix. If an asset, this confirms that the asset will not be decommissioned. If a process, this confirms the process becomes an asset. The capacity of this asset is the maximum possible, as limited by capacity growth, addition or aggregate limit constraints, and further limited by the demand level (i.e. capacity is not installed if it is more than needed to serve demand).
Issue 3: It is likely that through this iterative process we will end up with assets that are not performing well (as measured by objectives/decision), because their utilisation will change as other assets are added/confirmed. One partial solution is to continue the process - including recalculation of all assets' objectives/decisions at each iteration - until nothing changes between iterations (i.e. no new/confirmed assets) but such as approach may result in unintended consequences (e.g. process with nominally 2nd-best objective but low marginal cost being adopted). There would likely also be convergence instabilities and complex interactions between assets' objectives and utilisation.
iv. Repeat step 3(B)i - iii until all demand is served, then decommission any unused assets
Once all demand is served, we decommission assets that have a utilisation of zero in all time slices. These assets have become stranded. This could happen when, for example, carbon prices are high and emitting assets become unfavorable as a result (e.g. operating them is too expensive and cannot compete with new technology even though the latter has capital cost included).
C. Complete agent investment
Repeat step 3(B) for each commodity in the model, and repeat until all commodities have been processed.
Issue 4: The order in which this is done is important, as all downstream commodity demand must be known prior to agent investment. Service demand commodities should probably go first, but in most models there will be no other commodity without circular dependencies as described below.
Issue 5: Circularities here, e.g. power system capacity is required to produce H2, but also H2 can be consumed in the power sector so H2 capacity is needed to produce it, which in turn requires more power system capacity. An imperfect approach is to check if peak demand for each commodity has changed at the end of a run through all commodities, and if it has then run the capacity investment algorithm again for that commodity. Again, this is a heuristic solution that may lead to mathematical instabilities or poor quality solutions.
Issue 6: What about commodities that are consumed but not produced, or produced but not consumed? Do this capacity investment step only for SVD and SED commodities? And also check for processes that consume or produce non-balance commodities, and check if they can make money - invest in them if they do - requires specific objective of NPV.
4. Carbon Budget Solution (or CO2 price responsiveness)
Where a CO2 budget or price is specified, steps (2)-(3) are initially run with the CO2 price from the previous milestone year. After completion, we run dispatch with a CO2 budget equal to the user prescribed level (if it exists) for the new milestone year, and record the resulting CO2 price (dual solution of the CO2 constraint). If the CO2 price is less than zero then re-run dispatch without the budget constraint and set CO2 price to zero. If there is no solution to the dispatch optimisation, then the CO2 budget cannot be met. In this case we re-run dispatch without the budget constraint but with the CO2 price from the previous milestone year. We warn the user that the budget set was not met for the milestone year.
Alternatively, a user might specify a CO2 price for all or part of the time horizon, and no carbon budget, in which case the model runs dispatch with the specified carbon price relating to each milestone year in steps (2)-(3) and no further processing is needed here.
5. Recursively Solve using Steps (2) to (5) for each Milestone Year until End
Find commodity prices for the current milestone year as described in step (2). The model then moves to the next milestone time period and repeats steps (3)-(4), using these prices as inputs (i.e. assuming that prices from the previous milestone year persist in the next milestone year). This process continues until the end of the time horizon is reached.
Issue 7: At this point we have commodity prices for every time period in the simulation. The model could then perform a "super-loop" where the entire process above is repeated, but agents have some foresight of on commodity price. Super-loops will be considered for inclusion in a later release of MUSE.
Dispatch Optimisation Formulation
Decision variables
\( q_{r,a,c,ts} \), where q represents c commodity flow in region r, to/from asset a, in time slice ts. Negative values are flows into the asset and positive values are flows from the asset; q must be ≤0 for input flows and ≥0 for output flows. Note that q is a quantity flow (e.g. energy) as opposed to an intensity (e.g. power).
where
r = region
a = asset
c = commodity
ts = time slice
Objective function
$$ min. \sum_{r}{\sum_{a}{\sum_{c}{\sum_{ts}}}} cost_{r,a,c,ts} * q_{r,a,c,ts} $$
Where cost is a vector of cost coefficients representing the cost of each commodity flow.
$$ cost_{r,a,c,ts} = var\_ opex_{r,a,pacs} + flow\_ cost_{r,a,c} + commodity\_ cost_{r,c,ts} $$
var_opex is the variable operating cost for a PAC. If the commodity is not a PAC, this value is zero.
flow_cost is the cost per unit flow.
commodity_cost is the exogenous (user-defined) cost for a commodity. If none is defined for this combination of parameters, this value is zero.
NOTE: If the commodity flow is an input (i.e. flow <0), then the value of cost should be multiplied by −1 so that the impact on the objective function is positive.
Constraints
Issue 1: It would reduce the size of the optimisation problem if all assets of the same type that are in the same region are grouped together in constraints (to reduce the number of constraints). However, this approach would also complicate pre- and post-optimisation processing which would need to unpick grouped assets and allocate back to their agent owners.
Asset-level input-output commodity balances
Non-flexible assets
Assets where ratio between output/s and input/s is strictly proportional. Energy commodity asset inputs and outputs are proportional to first-listed primary activity commodity at a time slice level defined for each commodity. Input/output ratio is a fixed value.
For each r, a, ts, c:
$$ \frac{q_{r,a,c,ts}}{flow_{r,a,c}} - \frac{q_{r,a,pac1,ts}}{flow_{r,a,pac1}} = 0 $$
for all commodity flows that the process has (except pac1). Where pac1 is the first listed primary activity commodity for the asset (i.e. all input and output flows are made proportional to pac1 flow).
TBD - cases where time slice level of the commodity is seasonal or annual.
Commodity-flexible assets
Assets where ratio of input/s to output/s can vary for selected commodities, subject to user-defined ratios between input and output.
Energy commodity asset inputs and outputs are constrained such that total inputs to total outputs of selected commodities is limited to user-defined ratios. Furthermore, each commodity input or output can be limited to be within a range, relative to other commodities.
For each r, a, c, ts:
(TBD)
for all c that are flexible commodities. “in” refers to input flow commodities (i.e. with a negative sign), and “out” refers to output flow commodities (i.e. with a positive sign).
Asset-level capacity and availability constraints
Primary activity commodity/ies output must not exceed asset capacity or any other limit as defined by availability factor constraint user inputs.
For the capacity limits, for each r, a, c, ts. The sum of all PACs must be less than the assets' capacity:
$$ \sum_{pacs} \frac{q_{r,a,c,ts}}{capacity\_ a_{a} * time\_ slice\_ length_{ts}} \leq 1 $$
For the availability constraints, for each r, a, c, ts:
$$ \sum_{pacs} \frac{q_{r,a,c,ts}}{capacity\_ a_{a} * time\_ slice\_ length_{ts}} \leq process.availability.value(up)_{r,a,ts} $$
$$ \sum_{pacs} \frac{q_{r,a,c,ts}}{capacity\_ a_{a} * time\_ slice\_ length_{ts}} \geq process.availability.value(lo)_{r,a,ts} $$
$$ \sum_{pacs} \frac{q_{r,a,c,ts}}{capacity\_ a_{a} * time\_ slice\_ length_{ts}} = process.availability.value(fx)_{r,a,ts} $$
The sum of all PACs must be within the assets' availability bounds. Similar constraints also limit output of PACs to respect the availability constraints at time slice, seasonal or annual levels. With appropriate selection of q on the LHS to match RHS temporal granularity.
Note: Where availability is specified for a process at daynight
time slice level, it supersedes
the capacity limit constraint (i.e. you don't need both).
Commodity balance constraints
Commodity supply-demand balance for a whole system (or for a single region or set of regions). For each internal commodity that requires a strict balance (supply == demand, SED), it is an equality constraint with just “1” for each relevant commodity and RHS equals 0. Note there is also a special case where the commodity is a service demand (e.g. Mt steel produced), where net sum of output must be equal to the demand.
For supply-demand balance commodities. For each r and each c:
$$\sum_{a,ts} q_{r,a,c,ts} = 0$$
For a service demand, for each c, within a single region:
$$\sum_{a,ts} q_{r,a,c,ts} = cr\_ net\_ fx$$
Where c is a service demand commodity and cr_net_fx is the exogenous (user-defined) demand for
the given time slice selection. Note that the ts to be summed over will differ depending on the
specified time slice level for a given commodity. If the time slice level is annual
, it will be
every time slice, if it's season
then there will be separate constraints for each season and if
it's time_slice
then there will be separate constraints for every individual time slice.
TBD – commodities that are consumed (so sum of q can be a negative value). E.g. oil reserves.
TBD – trade between regions.
Asset-level commodity flow share constraints for flexible assets
Restricts share of flow amongst a set of specified flexible commodities. Constraints can be constructed for input side of processes or output side of processes, or both.
$$ q_{r,a,c,ts} \leq process.commodity.constraint.value(up)_{r,a,c,ts} * \left( \sum_{flexible\ c} q_{r,a,c,ts} \right) $$
$$ q_{r,a,c,ts} \geq process.commodity.constraint.value(lo)_{r,a,c,ts} * \left( \sum_{flexible\ c} q_{r,a,c,ts} \right) $$
$$ q_{r,a,c,ts} = process.commodity.constraint.value(fx)_{r,a,c,ts} * \left( \sum_{flexible\ c} q_{r,a,c,ts} \right) $$
Could be used to define flow limits on specific commodities in a flexible process. E.g. a refinery that is flexible and can produce gasoline, diesel or jet fuel, but for a given crude oil input only a limited amount of jet fuel can be produced and remainder of production must be either diesel or gasoline (for example).
Other net and absolute commodity volume constraints
Net constraint: There might be a net CO2 emissions limit of zero in 2050, or even a negative value. Constraint applied on both outputs and inputs of the commodity, sum must less then (or equal to or more than) a user-specified value. For system-wide net commodity production constraint, for each c, sum over regions, assets, time slices.
$$\sum_{r,a,ts} q_{r,a,c,ts} \leq commodity.constraint.rhs\_ value(up)$$
$$\sum_{r,a,ts} q_{r,a,c,ts} \geq commodity.constraint.rhs\_ value(lo)$$
$$\sum_{r,a,ts} q_{r,a,c,ts} = commodity.constraint.rhs\_ value(fx)$$
Similar constraints can be constructed for net commodity volume over specific regions or sets of regions.
Production or consumption constraint: Likewise similar constraints can be constructed to limit absolute production or absolute consumption. In these cases selective choice of q focused on process inputs (consumption) or process outputs (production) can be applied.
Model diagrams
This document contains diagrams showing the algorithm used by MUSE 2.0. It is likely to contain errors and omissions and will change as the code is developed. It is principally aimed at MUSE developers.
Functions are described with the following terms:
- Inputs: immutable input arguments; values not modified by function
- Outputs: values returned from function
- Modifies: mutable input arguments; values modified by function
Glossary
Activity: The flow of input/s or output/s of a Process that are limited by its capacity. For example, a 500MW power station can output 500MWh per hour of electrical power, or a 50MW electrolyser consumes up to 50MWh per hour of electrical power to produce hydrogen.
Agent: A decision-making entity in the system. An Agent is responsible for serving a user-specified portion of a Commodity demand or Service Demand. Agents invest in and operate Assets to serve demands and produce commodities.
Agent Objective/s: One or more objectives that an Agent considers when deciding which Process to invest in. Objectives can be economic, environmental, or others.
Asset: Once an Agent makes an investment, the related capacity of their chosen Process becomes an Asset that they own and operate. An Asset is an instance of a Process, it has a specific capacity, and a decommissioning year. A set of Assets must exist in the base year sufficient to serve base year demands (i.e. a calibrated base year, based on user input data).
Availability: The maximum, minimum or fixed percentage of maximum output (or input) that an Process delivers over a period. The time period could be a single time slice, a season, or a year.
Base Year: The starting year of a model run. The base year is typically calibrated to known data, including Process stock and commodity consumption/production.
Calibration: The act of ensuring that the model represents the system being modelled in a historical base year.
Capacity: The maximum output (or input) of an Asset.
Capital Cost: The overnight capital cost of a process.
Commodity: A substance (e.g. CO2) or form of energy (e.g. electricity) that can be produced and/or consumed by Processes* in the model. A Service Demand is a type of commodity that is defined at the end point of the system.
Commodity Levy: Represents a tax, levy or other external cost on a commodity. Levies can be applied to all commodity production (sum of output of all processes for that commodity), net production (sum of output and input for all processes), or all consumption (sum of input for all processes). It can also be negative, indicating an incentive on commodity production/consumption/net.
Decision Rule: The rule via which an Agent uses the Objective/s to decide between Process options to invest in. Examples include single objective, weighted sum between multiple objectives, or epsilon constraint where a secondary objective is considered if two options with similar primary objectives are identified.
Dispatch: The way in which Assets are operated to serve demand. MUSE 2.0 uses merit order dispatch, subject to Availability and other constraints that can be defined by the user.
End Year: The final year in the model time horizon.
Equivalent Annual Cost (EAC): An Agent objective, representing the annualised cost of serving all or part of an Agent's demand for a year, considering the Asset's entire lifetime.
Fixed Operating Cost: The Asset or Process annual operating cost charged per unit of capacity.
Input Commodity/ies: The commodities that flow into a Process.
Levelised Cost of X (LCOX): An Agent objective, representing the discounted cost of 1 unit of output commodity X from a process over its lifetime under a specified discount rate.
Lifetime: The lifetime of a Process, measured in years.
Milestone Years: A set of years in the model time horizon where model results are recorded. For example, with a 2025 Base Year and End Year 2100, a user might choose to record outputs in 5-year steps.
Merit Order: A method of operating Assets when the cheapest is dispatched first, followed by the next most expensive, etc, until demand is served. Also called “unit commitment.”
Output Commodity/ies: The commodities that flow out of a Process.
Process: A blueprint of an available Process that converts input commodities to output commodities. Processes have economic attributes of capital cost, fixed operating cost per unit capacity, non-fuel variable operating cost per unit activity, and risk discount rate. They have physical attributes of quantity and type of input and output commodities (which implicitly specify efficiency), Availability limits (by time slice, season and/or year), lifetime (years). When a Process is selected by an Agent for investment an instance of it called an Asset is created.
Region: A geographical area that is modelled. Regions primarily determine trade boundaries.
Season: A year is usually broken down into seasons in the model. For example, summer, winter, other.
Sector: Models are often broken down into sectors, each of which is associated with specific Service Demands or specific Commodity production. For example, the residential sector, the power sector, etc.
Service Demand: A Service Demand is a type of commodity that is consumed at the boundary of the modelled system. For example, tonne-kilometers of road freight, PJ of useful heat demand, etc.
Discount Rate: The discount rate used to calculate any process-specific agent economic objectives that require a discount rate. For example, Equivalent Annual Cost, Net Present Value, Levelised Cost of X, etc.
Time Horizon: The overall period modelled. For example, 2025–2100.
Time Period: Refers to a specific Milestone Year in the time horizon.
Time Slice: The finest time period in the model. The maximum time slice length is 1 year (where a model does not represent seasons or within-day (diurnal) variation). A typical model will have several diurnal time slices, and several seasonal time slices.
Utilisation: The percentage of an Asset's capacity that is actually used to produce its commodities. Must be between 0 and 1, and can be measured at time slice, season, or year level.
Variable Operating Cost: The variable operating cost charged per unit of activity of the Process.
Developer Guide
This is a guide for those who wish to contribute to the MUSE 2.0 project or make local changes to the code.
The API documentation is available here.
Installing the Rust toolchain
We recommend that developers use rustup
to install the Rust toolchain. Follow the instructions on
the rustup
website.
Once you have done so, select the stable
toolchain (used by this project) as your default with:
rustup default stable
As the project uses the latest stable toolchain, you may see build errors if your toolchain is out of date. You can update to the latest version with:
rustup update stable
Installing C++ tools for HiGHS
The highs-sys
crate requires a C++ compiler and cmake to be installed on your system.
These may be installed already, but if you encounter errors during the build process for highs-sys
(e.g. "Unable to find libclang"), you should follow the instructions here
under "Building HiGHS".
Working with the project
To build the project, run:
cargo build
Note that if you just want to build-test the project (i.e. check for errors and warnings) without
building an executable, you can use the cargo check
command, which is much faster.
To run MUSE 2.0 with the "simple" example, you can run:
cargo run run examples/simple
(Note the two run
s. The first is for cargo
and the second is passed as an argument to the built
muse2
program.)
Tests can be run with:
cargo test
More information is available in the official cargo
book.
Checking test coverage
We use Codecov to check whether pull requests introduce code without tests.
To check coverage locally (i.e. to make sure newly written code has tests), we recommend using cargo-llvm-cov.
It can be installed with:
cargo install cargo-llvm-cov
Once installed, you can use it like so:
cargo llvm-cov --open
This will generate a report in HTML format showing which lines are not currently covered by tests and open it in your default browser.
Developing the documentation
We use mdBook for generating technical documentation.
If you are developing the documentation locally, you may want to check that your changes render correctly (especially if you are working with equations).
To do this, you first need to install mdBook:
cargo install mdbook
You can then view the documentation in your browser like so:
mdbook serve -o
Recreate the command_line_help.md
file
This file is created automatically. In order to update it if needed, due to changes in the CLI, just run:
cargo run -- --markdown_help > docs/command_line_help.md
Pre-Commit hooks
Developers must install the pre-commit
tool in order to automatically run this
repository's hooks when making a new Git commit. Follow the instructions on the pre-commit
website in order to get started.
Once you have installed pre-commit
, you need to enable its use for this repository by installing
the hooks, like so:
pre-commit install
Thereafter, a series of checks should be run every time you commit with Git. In addition, the
pre-commit
hooks are also run as part of the CI pipeline.
Note: you may get errors due to the clippy
hook failing. In this case, you may be able to
automatically fix them by running cargo clipfix
(which we have defined as an alias in
.cargo/config.toml
).