The port record#
Every block of Calliope v0.7.0's math, with the file that states it here.
A block is done where one block states it as Calliope does. It is
split where the same rows and the same optimum have a different
statement, such as two blocks for two equations:, or a term of a sum for a
restated sum. It is prep where a column the file cannot compute comes
from data preparation. It is out where the file deliberately states
nothing, and the note says why.
Parameters are not listed: each one Calliope declares is a parameter of the
same name, in the file that reads it, with the conventions
for defaults and dimensions. The one exception is storage_loss in the
inter-cluster variant, a row below.
What mathspec is missing#
Each gap below is a place the port is not one block for one. None stops a block from being stated.
- Closed: a power or a quotient over a sum of parameters. mathspec
refused
(1 - storage_loss) ** timestep_resolutionand Calliope's annuity factor, whose base and divisor are sums. #757 admits them, and the port writes both as Calliope does. - A default that is not zero. Calliope's
default:is the value arithmetic reads and, at the same time, "not given" to awhere:. A mathspec parameter has one reading of a missing row,0, so data prep fills each default the math reads. Two masks change:area_useis built wherearea_use_min > 0, where Calliope builds it wherearea_use_minis given at all, anddistance_only_for_transmissionchecks the filled defaults, not what the modeller wrote. - A
where:on apiecewise:block. A curve has a row per link at every coordinate of its frame. Calliope's SOS2 costs hold only where a technology has breakpoints, and elsewhere the link row would pinflow_capto zero. The link readspiecewise_flow_cap, a copy offlow_capmasked to the technologies with a curve. - One label of a dimension. Calliope writes
flow_out[carriers=electricity]. Here a named expression takes the value wherecarriers == electricityand zero elsewhere, and a sum overcarriersreads it. The CHP, net-import and urban-scale files hold eleven such expressions. - A label read off the coordinate it indexes. Calliope's
map_dim(nodes, link_from), and a slice by a per-technology carrier, compare a lookup with the dimension the operand already carries.atreads onto a dimension the operand does not carry, and awhere:does not compare a relation column with its dimension. The port declares these lookups as bare relations over the pair,link_from: {key: [techs, nodes]}, and tests the pair in a case. - One parameter at several shapes. Calliope's
annual_flow_maxandnet_import_shareare read per technology, per node and over a group, and the data decides. A mathspec parameter has one shape, so the group row ofannual_energy_balancereads a scalar of its own, andnet_import_shareis one number. - An empty sum that no file adds to. An
empty: truesum with no term is a column the spec reads and does not build, not zero.penaltyhas the body0, so a model with no feasibility file reads a zero penalty. - Closed:
sum(over=[a, b]). Calliope sums over a list of dimensions. #778 admits the list, and #779 admits it in a macro, so the port writes each sum as one call. - A warning. An assumption holds or the data is refused. Calliope's three
checks at
errors: warnare out.
The port also found two mathspec bugs, fixed in their own pull requests:
advice raised KeyError on an objective that reads a sum other files add
to (#767), and merge
refused a given variable read by its frame alone where the introducer is an
integer (#768).
base.yaml#
| Calliope | status | here | note |
|---|---|---|---|
dimensions carriers, costs, nodes, techs, timesteps |
done | every fragment | clusters and datesteps in the inter-cluster variant |
lookups base_tech, carrier_in, carrier_out, include_storage, one_way |
done | flows | a one_of is an assumption |
lookups link_from, link_to |
split | flows, transmission | a bare relation over technology and node, gap 5 |
lookups carrier_export, cyclic_storage, cluster_first_timestep, source_cap_equals_flow_cap |
done | export, storage, supply | |
lookup lookup_cluster_last_timestep |
done | storage | a relation from a time step onto a time step |
lookups sink_unit, source_unit |
done | demand, supply | absolute, the default, is what no row reads as |
lookups latitude, longitude |
out | read by no math; Calliope derives distance from them in data preparation |
|
flow_capacity_per_storage_capacity_min, _max |
done | storage | |
source_capacity_equals_flow_capacity |
done | supply | |
force_zero_area_use, area_use_per_flow_capacity |
done | area | |
area_use_capacity_per_loc |
split | area | where: area_use over a node is a count over technologies |
flow_capacity_systemwide_max, _min |
done | flows | any(…, over=nodes) is count(…, over=nodes) >= 1 |
balance_conversion |
done | conversion | |
flow_out_max, flow_out_min, flow_in_max |
done | flows | |
source_max |
done | supply | |
storage_max, storage_discharge_depth_limit |
done | storage | |
system_balance |
split | balance | carrier_flow == 0, the sum of a term from each file that moves a carrier |
balance_demand |
split | demand | balance_demand_equals and balance_demand_max, one block per equation |
balance_demand_min_use |
done | demand | |
balance_supply_no_storage |
done | supply | |
balance_supply_with_storage |
done | supply_storage | |
source_availability_supply |
split | supply | _equals and _max, one block per equation |
balance_supply_min_use |
done | supply | |
balance_storage |
done | storage | |
set_storage_initial |
split | storage | one row per store, built at the last time step rather than read there |
balance_transmission, symmetric_transmission |
done | transmission | where(flow_cap, map_dim(…)) is a case over the bare relation, gap 5 |
export_balance |
done | export | |
ramping_up, ramping_down |
done | flows | the first time step is out of the row, so roll is a shift |
variables flow_cap, flow_out, flow_in, flow_export, source_use, source_cap, storage_cap, storage |
done | flows, export, supply, storage | default: 0 is absence: zero |
variable area_use |
split | area | built where area_use_min > 0, gap 2 |
variables unmet_demand, unused_supply |
split | feasibility | config.ensure_feasibility is whether the file is composed |
objective min_cost_optimisation |
split | settings | system_cost + penalty, each a sum other files add to |
$unmet_demand |
done | feasibility | unmet_demand_penalty, a term of penalty |
flow_out_inc_eff, flow_in_inc_eff |
done | flows | |
cost_operation_variable |
split | cost | a sum; flows, supply and export each add their cost. Calliope's two cases, supply or not, are one sum, since a supply technology has no inflow |
cost_investment_flow_cap, _storage_cap, _source_cap, _area_use |
done | flows, storage, supply, area | each is a term of cost_investment, and the flow capacity one through flows_cost_investment |
cost_investment |
split | cost | a sum each capacity adds to |
cost_investment_annualised |
done | cost | $depreciation_rate is a named expression with cases |
cost_operation_fixed |
split | cost | its body here, and flows_cost_operation_fixed added |
cost |
done | cost | |
postprocessed capacity_factor, systemwide_capacity_factor, total_generation, systemwide_levelised_cost, total_levelised_cost |
done | reporting | reported; the where: is the absence of what they read |
postprocessed unmet_sum |
done | feasibility | reported |
postprocessed curtailment, total_curtailment |
done | supply | reported |
check must_have_base |
done | flows | an assumption |
check distance_only_for_transmission |
split | flows | checks the filled defaults, gap 2 |
checks unbounded_*_cost |
done | flows, storage, area, supply | |
check finite_source_use |
split | supply, demand | one assumption per parameter |
check all_or_nothing_lat_lon |
out | the coordinates are data preparation | |
checks export_only_for_outflows, storage_initial_max, cyclic_storage_needs_inter_cluster |
done | export, storage | |
checks flow_in_for_supply_tech, flow_out_for_demand_tech, no_storage_discharge_depth_when_clustering |
out | warnings, gap 9 |
milp.yaml#
| Calliope | status | here | note |
|---|---|---|---|
lookups cap_method, integer_dispatch, force_async_flow |
done | milp | |
variables purchased_units, operating_units, available_flow_cap |
done | milp | |
variable async_flow_switch |
done | milp | an integer in [0, 1] is domain: binary |
bounds of flow_cap, area_use, source_cap, storage_cap |
done | variant | |
unit_commitment_milp, flow_out_max_milp, flow_in_max_milp, storage_capacity_units_milp, flow_capacity_units_milp, storage_capacity_max_purchase_milp, unit_capacity_max_systemwide_milp, async_flow_in_milp, async_flow_out_milp, available_flow_cap_continuous, available_flow_cap_binary, available_flow_cap_max_binary_continuous_switch |
done | milp | |
unit_capacity_min_systemwide_milp |
done | milp | built where the system-wide maximum is set, as Calliope writes it |
flow_out_min_milp, flow_capacity_max_purchase_milp, flow_capacity_minimum, storage_capacity_minimum, area_use_minimum, source_capacity_minimum |
split | milp | one block per equation |
flow_out_max, flow_out_min, flow_in_max |
done | variant | the where: only |
flow_capacity_systemwide_min |
split | variant, milp | the patch narrows the base row; the purchased case is a block of the fragment |
cost_investment_purchase |
done | milp | a term of cost_investment |
cost_investment |
split | milp | Calliope restates it whole; here the purchase is a term |
descriptions of flow_cap_min, flow_cap_min_systemwide, flow_out_min_relative |
done | variant | |
| checks | done | milp | assumptions; cap_method's one_of too |
operate.yaml#
| Calliope | status | here | note |
|---|---|---|---|
parameters flow_cap, area_use, source_cap, storage_cap |
done | variant | each replaces the variable of its name |
parameter purchased_units |
done | variant | |
every .active: false |
done | operate, operate_milp | a removal; the terms of the removed sums are removed with them |
cost |
done | variant | |
check operate_mode_cyclic_storage |
done | variant | |
| operate mode's window and horizon | out | a loop of solves, not math |
spores.yaml#
| Calliope | status | here | note |
|---|---|---|---|
| parameters | done | variant | |
total_system_cost_max |
split | variant | one row over system_cost + penalty. Calliope restates the objective, and misses a cost an example adds to it, such as fuel distribution |
objective min_spores |
done | variant | |
postprocessed spores_score_cumulative, spores_baseline_cost_tracked |
done | variant | reported |
| the SPORES iterations | out | a loop of solves that updates spores_score, not math |
storage_inter_cluster.yaml#
| Calliope | status | here | note |
|---|---|---|---|
lookups timestep_cluster, lookup_datestep_cluster, lookup_datestep_last_cluster_timestep |
done | variant | relations |
storage_max, cyclic_storage_needs_inter_cluster off |
done | variant | removals |
$storage_previous_step of balance_supply_with_storage and balance_storage |
done | variant | one named expression, patched once |
set_storage_initial |
split | variant | built at the last day, as in the base |
storage_intra_max, storage_intra_min, storage_inter_max, storage_inter_min, balance_storage_inter |
done | variant | a slice by a lookup is at through the relation |
| variables | done | variant | |
storage_loss over time steps |
prep | variant | (1 - storage_loss) ** 24 reads it per day, so the variant declares it without time steps |
The examples#
| Calliope | status | here | note |
|---|---|---|---|
annual_energy_balance.yaml |
split | annual_energy_balance | the group row reads annual_flow_max_group, gap 6; where: source_use over a technology is base_tech == 'supply' |
chp_htp.yaml |
split | chp_htp, variant | the rewritten balance_conversion is a patch and a block of its own; a carrier slice is a case, gap 4 |
demand_share_per_timestep_decision.yaml |
split | demand_share_per_timestep_decision | the sum row is one per node: Calliope repeats it in every time step, and mathspec refuses a row repeated along a dimension it does not read |
fuel_dist.yaml |
split | fuel_dist | Calliope restates system_balance and the objective; here each gains a term |
max_time_varying.yaml |
done | max_time_varying | |
monthly_peak_flow_charge.yaml |
split | monthly_peak_flow_charge | the month is a relation, so the row is one per time step; the charge is a term of cost_operation_fixed |
net_import_share.yaml |
split | net_import_share | a carrier and a node group are cases, gap 4; the share is one number, gap 6 |
piecewise_linear_costs.yaml |
split | piecewise_linear_costs | a term of cost_investment |
piecewise_linear_efficiency.yaml |
done | piecewise_linear_efficiency | |
share_all_timesteps.yaml, share_per_timestep.yaml |
split | share_all_timesteps, share_per_timestep | the demand technology is at through a relation; the carrier is a case, gap 5 |
sos2_piecewise_linear_costs.yaml |
split | sos2_piecewise_linear_costs | piecewise: with method: sos2, over a masked copy of flow_cap, gap 3 |
uptime_downtime_limits.yaml |
done | uptime_downtime_limits | |
urban-scale additional_math.yaml |
split | urban_scale_chp, variant | as the CHP example |