Tutorial 6: Unit consistency¶
Our models describe physical processes, where every numerical value is associated to a physical unit. For example, the capacity of a coal power plant is a power, thus the unit is, e.g., GW. In our optimization models, we use a large variety of different technologies and carriers, for which the input data is often provided in different units. The optimization problem itself however only accepts numeric values.
Thus, we have to make sure that the numeric values have the same physical base unit, i.e., if our input data for technology A is in GW and for technology B in MW, we want to convert both numeric values to, e.g., GW. Another reason for using a base unit is to keep the numerics of the optimization model in check.
Convert units to common base units¶
We define a set of base units, which we can combine to represent each dimensionality in our model. Each unit has a certain physical dimensionality:
km => [distance]
hour => [time]
Euro => [currency]
GW => [mass]^1 [length]^2 [time]^-3
We make use of the fact, that we can combine the base units to any unit by comparing the dimensionalities. For example, Euro/MWh can be converted to:
Euro/MWh
=> [currency]^1 [mass]^-1 [length]^-2 [time]^2
= [currency]^1 [[mass]^1 [length]^2 [time]^-3]^-1 [time]^-1
=> Euro/GW/hour
We convert the units by calculating the multiplier
(Euro/GW/hour)/(Euro/MWh) = (MW)/(GW) = 0.001
and multiplying the numeric value with the multiplier.
The base units are defined in the input data set in the file
/energy_system/base_units.csv. You have to provide an input unit for all
attributes in the input files. The unit is added as the unit field after
the default value in the attributes.json file (Attribute.json files).
Defining new units¶
We are using the package pint, which
already has the most common units defined. However, some exotic ones, such as
Euro, are not yet defined. You can add new units in the file
system_specification/unit_definitions.txt:
Euro = [currency] = EURO = Eur
pkm = [mileage] = passenger_km = passenger_kilometer
Here, we make use of the existing dimensionality [currency]. If there is a
unit you want to define with a dimensionality that does not exist yet, you can
define it the same way: pkm = [mileage]. The unit pkm now has the
dimensionality [mileage].
What do I have to look out for?
There are a few rules to follow in choosing the base units:
The base units must be exhaustive, thus all input units must be represented as a combination of the base units (i.e.,
Euro/MWh => Euro/GW/hour). Each base unit can only be raised to the power 1, -1, or 0. We do not want to $ represent a unit by any base unit with a different exponent, e.g.,km => (m^3)^(1/3)The base units themselves can not be linearly dependent, e.g., you cannot choose the base units
GW,hourandGJ.The dimensionalities must be unique. While you can use
m^3andkm, you cannot use bothMWandGW. You will get a warning if you define the same unit twice.
Enforcing unit consistency¶
Converting all numeric values to the same set of base units enforces that all
magnitudes are comparable; however, this does not ensure that the units are
consistent across parameters and elements (technologies and carriers). For
example, a user might have defined the capacity of an electrolyzer in GW,
but the investment costs in Euro/(ton/hour).
To enforce unit consistency, ZEN-garden checks the units of all parameters and elements and throws an error if the units are not consistent. In particular, ZEN-garden connects technologies to their reference carriers and checks if the units of the reference carriers are consistent with the units of the technology parameters. If any inconsistency is found, ZEN-garden tries to guess the inconsistent unit (the least common unit) and displays it in the error message.
After ensuring unit consistency, ZEN-garden implies the units of all variables
in the optimization problem based on the units of the parameters. Each variable
definition (variable.add_variable()) has the argument unit_category that
defines the combination of units and can look like
unit_category={"energy_quantity": 1, "time": -1}.
Note
In the results (Results Object), you can retrieve the unit of all
parameters and variables by calling
r.get_unit(<variable/parameter name>), where r is a results object.
Known issues with pint¶
The pint package that we use for the unit handling has amazing
functionalities but also some hurdles to look out for. The ones we have already
found are:
ton: pint uses the keywordtonfor imperial ton, not the metric ton. The keyword for those aremetric_tonortonne. However, per default, ZEN-garden overwrites the definition oftonto be the metric ton, sotonandtonnecan be used interchangeably. If you for some reason want to use imperial tons, set"solver": {"define_ton_as_metric_ton": false}.h: Until recently,hwas treated as the planck constant, not hour. Fortunately, this has been fixed in Feb 2023. If you encounter this error, please update your pint version.