calliope.backend.helper_functions
¶
Functions that can be used to process data in math where and expression strings.
NAME is the function name to use in the math strings.
Defined(return_type, attrs)
¶
Bases: ParsingHelperFunction
Find all items of one dimension that are defined in an item of another dimension.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['where']
class-attribute
instance-attribute
¶
NAME = 'defined'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(*, within, how, **dims)
¶
Find whether members of a model dimension are defined inside another.
For instance, whether a node defines a specific tech (or group of techs). Or, whether a tech defines a specific carrier.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
within
|
str
|
the model dimension to check. |
required |
how
|
Literal[all, any]
|
Whether to return True for |
required |
**dims
|
str
|
key: dimension whose members will be searched for as being defined under the primary dimension ( |
{}
|
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray:
For each member of |
Examples:
Check for any of a list of techs being defined at nodes. Assuming a YAML definition of:
Then: >>> defined(techs=[tech1, tech2], within=nodes, how=any)
[out] <xarray.DataArray (nodes: 2)>
array([ True, False])
Coordinates:
* nodes (nodes) <U5 'node1' 'node2'
>>> defined(techs=[tech1, tech2], within=nodes, how=all)
[out] <xarray.DataArray (nodes: 2)>
array([ False, False])
Coordinates:
* nodes (nodes) <U5 'node1' 'node2'
Source code in src/calliope/backend/helper_functions.py
as_math_string(*, within, how, **dims)
¶
Source code in src/calliope/backend/helper_functions.py
GetValAtIndex(return_type, attrs)
¶
Bases: ParsingHelperFunction
Getter functionality for obtaining values at specific integer indices.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression', 'where']
class-attribute
instance-attribute
¶
NAME = 'get_val_at_index'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(**dim_idx_mapping)
¶
Get value of a model dimension at a given integer index.
This function is primarily useful for timeseries data.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**dim_idx_mapping
|
int
|
kwargs with key (str): Model dimension in which to extract value. value (int): Integer index of the value to extract (assuming zero-indexing). |
{}
|
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray: Dimensionless array containing one value. |
Examples:
>>> coords = {"timesteps": ["2000-01-01 00:00", "2000-01-01 01:00", "2000-01-01 02:00"]}
>>> model_data = xr.Dataset(coords=coords)
>>> get_val_at_index = GetValAtIndex(model_data=model_data)
>>> get_val_at_index(model_data)(timesteps=0)
<xarray.DataArray 'timesteps' ()>
array('2000-01-01 00:00', dtype='<U16')
Coordinates:
timesteps <U16 '2000-01-01 00:00'
>>> get_val_at_index(model_data)(timesteps=-1)
<xarray.DataArray 'timesteps' ()>
array('2000-01-01 00:00', dtype='<U16')
Coordinates:
timesteps <U16 '2000-01-01 02:00'
Source code in src/calliope/backend/helper_functions.py
GroupDatetime(return_type, attrs)
¶
Bases: ParsingHelperFunction
Apply a summation over a datetime group on a datetime dimension in math expressions.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression']
class-attribute
instance-attribute
¶
NAME = 'group_datetime'
class-attribute
instance-attribute
¶
ignore_where = True
class-attribute
instance-attribute
¶
as_array(array, over, group)
¶
Sum an expression array over the given dimension(s).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
expression array |
required |
over
|
DataArray
|
dimension name over which to group |
required |
group
|
DataArray
|
datetime grouper. Any xarray/pandas datetime grouper options datetime grouper options include 'date', 'dayofweek', 'month', etc. |
required |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray: Array with datetime dimension aggregated over the grouper. |
Note
- The array is returned with the
overdimension replaced by the name of the grouper. So, if you select to resample to monthly, the returned array will include themonthdimension. - the
date/timegroupers will return the date/time as a string in ISO8601 format (e.g. "2025-01-01"/"01:00:00"). All other groupers will return integer values (e.g. month 1, 2, 3, etc.).
Examples:
One common use-case is to allow demand to be met at any point on a given date.
For such a demand tech, the daily demand should be indexed over date, e.g.:
sink_use_equals_daily.csv
Then, to set the daily flow into the demand tech to those values:
constraints:
daily_demand:
foreach: [nodes, techs, carriers, date]
where: sink_use_equals_daily
equations:
- expression: "group_datetime(flow_in, timesteps, date) == sink_use_equals_daily"
Similarly, a monthly maximum resource to a supply technology might be used, to simulate e.g. biofuel feedstock availability:
source_use_max_monthly.csv
Then, to set the daily flow into the demand tech to those values:
constraints:
daily_demand:
foreach: [nodes, techs, carriers, month]
where: source_use_max_monthly
equations:
- expression: "group_datetime(flow_in, timesteps, month) <= source_use_max_monthly"
Source code in src/calliope/backend/helper_functions.py
as_math_string(array, over, group)
¶
Source code in src/calliope/backend/helper_functions.py
GroupSum(return_type, attrs)
¶
Bases: ParsingHelperFunction
Apply a summation over an array grouping.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression']
class-attribute
instance-attribute
¶
NAME = 'group_sum'
class-attribute
instance-attribute
¶
ignore_where = True
class-attribute
instance-attribute
¶
as_array(array, groupby, group_dim)
¶
Sum an array over the given groupings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
expression array |
required |
groupby
|
DataArray
|
Array with which to group the array. |
required |
group_dim
|
str
|
Name of dimension that the |
required |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray:
Array with dimension(s) aggregated over the |
Note
- The array is returned with all dimensions over which
groupbyis indexed replaced by a new dimension named bygroup_dim. - To groupby datetime periods (weeks, months, dates, etc.), consider using
group_datetimefor convenience, as you do not need to define a separategroupbyarray.
Examples:
To get the sum over an ad-hoc combination of techs at nodes, e.g. to limit their overall outflow in any given timestep, you would do the following:
- Define an array linking node-tech combinations with a group:
data_definitions: # You may prefer to define this in a CSV file or when referring to the techs within the `nodes` model definition. power_plant_groups: data: [low_emission_plant, low_emission_plant, high_emission_plant, high_emission_plant] index: [ [tech_1, node_1], [tech_2, node_1], [tech_1, node_2], [tech_2, node_2], ] dims: [techs, nodes] - Define a set of outflow limits:
- Define the math to link the two, using
group_sum:
Source code in src/calliope/backend/helper_functions.py
as_math_string(array, groupby, group_dim)
¶
Source code in src/calliope/backend/helper_functions.py
ParsingHelperFunction(return_type, attrs)
¶
Bases: ABC
Abstract base class for helper function parsing.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN
abstractmethod
property
¶
List of parseable math strings that this function can be accessed from.
NAME
abstractmethod
property
¶
Helper function name that is used in the math expression/where string.
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(*args, **kwargs)
abstractmethod
¶
Method to apply the helper function to provide an n-dimensional array output.
This method is called when the class is initialised with return_type=array.
Source code in src/calliope/backend/helper_functions.py
as_math_string(*args, **kwargs)
abstractmethod
¶
Method to update LaTeX math strings to include the action applied by the helper function.
This method is called when the class is initialised with return_type=math_string.
Source code in src/calliope/backend/helper_functions.py
ReduceCarrierDim(return_type, attrs)
¶
Bases: ParsingHelperFunction
Sum over the carrier dimension in math components.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression']
class-attribute
instance-attribute
¶
NAME = 'reduce_carrier_dim'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(array, flow_direction)
¶
Reduce expression array data by selecting the carrier that corresponds to the given carrier tier and then dropping the carriers dimension.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
Expression array. |
required |
flow_direction
|
Literal['in', 'out']
|
Flow direction in which to check for the existence of carrier(s) for technologies defined in |
required |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray: |
Source code in src/calliope/backend/helper_functions.py
as_math_string(array, flow_direction)
¶
Roll(return_type, attrs)
¶
Bases: ParsingHelperFunction
Roll (a.k.a. shift) items along ordered dimensions.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression']
class-attribute
instance-attribute
¶
NAME = 'roll'
class-attribute
instance-attribute
¶
ignore_where
property
¶
Whether or not to ignore where functionality.
as_array(array, **roll_kwargs)
¶
Roll (a.k.a., shift) the array along the given dimension(s) by the given number of places.
Rolling keeps the array index labels in the same position, but moves the data by the given number of places.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
Array on which to roll data. |
required |
**roll_kwargs
|
int
|
kwargs with the following key (str): name of dimension on which to roll. value (int): number of places to roll data. |
{}
|
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray: |
Examples:
>>> array = xr.DataArray([1, 2, 3], coords={"foo": ["A", "B", "C"]})
>>> model_data = xr.Dataset({"bar": array})
>>> roll = Roll()
>>> roll("bar", foo=1)
<xarray.DataArray 'bar' (foo: 3)>
array([3, 1, 2])
Coordinates:
* foo (foo) <U1 'A' 'B' 'C'
Source code in src/calliope/backend/helper_functions.py
as_math_string(array, **roll_kwargs)
¶
Source code in src/calliope/backend/helper_functions.py
SelectFromLookupArrays(return_type, attrs)
¶
Bases: ParsingHelperFunction
N-dimensional indexing functionality.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression']
class-attribute
instance-attribute
¶
NAME = 'select_from_lookup_arrays'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(array, **lookup_arrays)
¶
Apply vectorised indexing on an arbitrary number of an input array's dimensions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
Array on which to apply vectorised indexing. |
required |
**lookup_arrays
|
DataArray
|
key: dimension on which to apply vectorised indexing value: array whose values are either NaN or values from the dimension given in the key. |
{}
|
Raises:
| Type | Description |
|---|---|
BackendError
|
|
BackendError
|
All |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray:
|
Examples:
>>> coords = {"foo": ["A", "B", "C"]}
>>> array = xr.DataArray([1, 2, 3], coords=coords)
>>> lookup_array = xr.DataArray(np.array(["B", "A", np.nan], dtype="O"), coords=coords, name="bar")
>>> model_data = xr.Dataset({"bar": lookup_array})
>>> select_from_lookup_arrays = SelectFromLookupArrays(model_data=model_data)
>>> select_from_lookup_arrays(array, foo=lookup_array)
<xarray.DataArray 'bar' (foo: 3)>
array([ 2., 1., nan])
Coordinates:
* foo (foo) object 'A' 'B' 'C'
The lookup array assigns the value at "B" to "A" and vice versa. "C" is masked since the lookup array value is NaN.
Source code in src/calliope/backend/helper_functions.py
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 | |
as_math_string(array, **lookup_arrays)
¶
Source code in src/calliope/backend/helper_functions.py
Sum(return_type, attrs)
¶
Bases: ParsingHelperFunction
Apply a summation over dimension(s) in math expressions.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression', 'where']
class-attribute
instance-attribute
¶
NAME = 'sum'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(array, *, over)
¶
Sum an expression array over the given dimension(s).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
expression array |
required |
over
|
DataArray | list[DataArray]
|
Dimension(s) over which to apply |
required |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray:
Array with dimensions reduced by applying a summation over the dimensions given in |
Source code in src/calliope/backend/helper_functions.py
as_math_string(array, *, over)
¶
Source code in src/calliope/backend/helper_functions.py
SumNextN(return_type, attrs)
¶
Bases: ParsingHelperFunction
Sum the next N items in an array.
Works best for ordered arrays (datetime, integer) and is equivalent to a summation over a rolling window.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression']
class-attribute
instance-attribute
¶
NAME = 'sum_next_n'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(array, over, N)
¶
Sum values from current up to N from current on the dimension over.
Works best for ordered arrays (datetime, integer).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
Math component array. |
required |
over
|
str
|
Dimension over which to sum |
required |
N
|
int
|
number of items beyond the current value to sum from |
required |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray: Returns the input array with the condition applied, including having been broadcast across any new dimensions provided by the condition. |
Note
- The rolling window does not wrap around to the start of the set when reaching the end. That is, if you have N = 4 then for a dimension of length T, at T - 1 it will sum over dimension positions (T - 1, T), not (T - 1, T, 0, 1).
- You will find that this over-constrains the model unless you limit the constraint (using the
wherestring) to only apply overlen(over) - N. This is linked to the abovementioned lack of wrapping. E.g.where: timesteps<=get_val_at_index(timesteps=-24)if N == 24. - This function is based on an integer number of steps from the current step.
For datetime dimensions like
timesteps, you will (a) need to be using a regular time frequency (e.g. hourly) and (b) updateNto reflect the resolution of your time dimension (N = 4 in if resample.timesteps=1h-> N = 2 if resample.timesteps=2h).
Examples:
One common use-case is to collate N timesteps beyond a given timestep to apply a constraint to it (e.g., demand must be less than X in the next 24 hours):
For such a demand tech, the portion of its demand that is flexible should be separated from sink_use_equals to e.g.,
a sink_use_flexible timeseries parameter which we will use in the DSR constraint:
constraints:
4hr_demand_side_response:
foreach: ["nodes", "techs", "carriers", "timesteps"]
where: "carrier_in AND sink_use_flexible AND timesteps<=get_val_at_index(timesteps=-24)"
equations:
- expression: sum_next_n(flow_in, timesteps, 4) == sum_next_n(sink_use_flexible, timesteps, 4)"
Source code in src/calliope/backend/helper_functions.py
as_math_string(array, over, N)
¶
Source code in src/calliope/backend/helper_functions.py
Where(return_type, attrs)
¶
Bases: ParsingHelperFunction
Apply where array within an expression string.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['expression']
class-attribute
instance-attribute
¶
NAME = 'where'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(array, condition)
¶
Apply a where condition to a math array within an expression string.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
array
|
DataArray
|
Math component array. |
required |
condition
|
DataArray
|
Boolean where array.
If not |
required |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray: Returns the input array with the condition applied, including having been broadcast across any new dimensions provided by the condition. |
Examples:
One common use-case is to introduce a new dimension to the variable which represents subsets of one of the main model dimensions.
In this case, each member of cap_node_groups is a subset of nodes and we want to sum flow_cap over each of those subsets and set a maximum value.
input:
data_definitions:
node_grouping:
data: True
index: [[group_1, region1], [group_1, region1_1], [group_2, region1_2], [group_2, region1_3], [group_3, region2]]
dims: [cap_node_groups, nodes]
node_group_max:
data: [1, 2, 3]
index: [group_1, group_2, group_3]
dims: cap_node_groups
math:
constraints:
my_new_constraint:
foreach: [techs, cap_node_groups]
equations:
- expression: sum(where(flow_cap, node_grouping), over=nodes) <= node_group_max
Source code in src/calliope/backend/helper_functions.py
WhereAny(return_type, attrs)
¶
Bases: ParsingHelperFunction
Apply any over a dimension in where string.
Abstract helper function class, which all helper functions must subclass.
The abstract properties and methods defined here must be defined by all helper functions.
Source code in src/calliope/backend/helper_functions.py
ALLOWED_IN = ['where']
class-attribute
instance-attribute
¶
NAME = 'any'
class-attribute
instance-attribute
¶
ignore_where
property
¶
If True, where arrays will not be applied to the incoming data variables (valid for expression helpers).
as_array(input_component, *, over)
¶
Reduce the boolean where array of a model input by applying any over some dimension(s).
If the component exists in the model, returns a boolean array with dimensions reduced
by applying a boolean OR operation along the dimensions given in over.
If the component does not exist, returns a dimensionless False array.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_component
|
str
|
Reference to a model input. |
required |
over
|
str | list[str]
|
dimension(s) over which to apply |
required |
Returns:
| Type | Description |
|---|---|
DataArray
|
xr.DataArray: resulting array. |