Molecules

The flows of molecules is modelled in ETEngine using a graph, separate from the energy graph. Nodes and edges for the molecule graph are stored in graphs/molecules.

Molecule flows are calculated for both the present and future graphs, although the available features differ when Causality (hourly load calculations) is enabled.

Node documents in ETSource have two attributes which configure flows between the graphs:

  • from_energy – Allows setting a demand on a molecule node, based on a demand in the energy graph. Only supported on nodes in the molecule graph.

  • from_molecules – Allows setting a demand on an energy node, based on a demand in the molecule graph. Only supported on nodes in the energy graph when Causality is enabled.

Without Causality

When no hourly loads are calculated, the energy and molecule graphs are each calculated once.

  1. Energy graph is calculated.
  2. Molecule demands are set, configured with the from_energy attribute.
  3. Molecule graph is calculated.

A consequence of this process is that energy flows may influence the molecule graph, but molecule flows will not cause any changes to the energy graph. Causality is always disabled for the present graph, and is disabled for the future graph whenever the end-user turns off the Merit Order in ETModel.

With Causality

When Causality is enabled, the energy and molecule graphs are each calculated twice. This allows for demands in the molecule graph to set demands in the energy graph, which may then be accounted for in Causality calculations. This is most useful when you wish to account for the electricity demand resulting from CO2 storage.

  1. Energy graph is calculated.
  2. Molecule demands are set, configured with the from_energy attribute.
  3. Molecule graph is calculated.
  4. Some energy demands are set or updated, based on flows in the molecule graph, configured by the from_molecules attribute.
  5. Hourly loads are calculated with Causality.
  6. Energy graph is re-calculated (updated demands set in step 4 are now accounted for).
  7. Molecule graph is re-calculated, accounting for changes resulting from Causality in step 5.

Circular dependencies

The energy and molecule graphs may have a circular dependency. For example, if demand for electricity causes emission of CO2, CO2 is then stored, which causes an increase in demand for electricity. This increase in electricity demand might cause further CO2 emissions, further changing the molecule graph.

Presently there is no way to resolve this without continually repeating steps 4-7, with performance constraints currently prohibiting this. For this reason, such circularities are not fully accounted for: demands set on the energy graph as a result of molecule flows (step 4) are therefore based on the first graph calculation (step 1), which doesn't account for changes made by Causality and the Merit Order.

Setting Causality demands

When using the from_molecules attribute on an energy node, care must be taken to ensure the demand is included in the Causality calculation (for example, the electricity merit order, network gas, etc). Changes to an energy node demand will not propagate through the graph until after Causality has been calculated.

Therefore, from_molecules may only be used on nodes which will not in any way influence the demand of any carrier calculated by Causality, or must be placed on a node directly used in a Causality calculation. For example, an energy node which represents CO2 storage in the energy graph:

# Configure that the energy node demand is based on a demand in the
# molecule graph.
- from_molecules.source = molecules_sequestration_co2
- from_molecules.conversion = 1.0
# The node participates directly in the Merit Order as a consumer.
- merit_order.type = consumer
- merit_order.group = flat

Initial calculation in Refinery

The molecule graph may have shares set on edges, just like the energy graph, but all nodes have a demand of zero.

The molecule nodes and edges are passed through Refinery as if part of the energy graph (although entirely disconnected from energy nodes) in order to set these shares and provide them to ETEngine. As a consequence, molecule nodes must have unique keys and cannot be named identically to their energy counterparts.

Configuring ETSource

Demands in the molecule graph are based on demands calculated in the energy graph. For example, once we know how much electricity is generated by a gas power plant, it's easy to convert that number to a quantity of CO2 emitted. If the gas plant emits 0.1g CO2 per MJ of energy and the plant has an energy demand of 1PJ (one thousand million MJ), then the plant will produce 100T of CO2.

CO2 per MJ: 0.1g
Electricity: 1,000,000,000 MJ
CO2 emitted: 100,000,000g (100T)

The from_energy attribute on molecule nodes is used to inform the node from which energy node to calculate the molecule flow, and which inputs or outputs to use. The from_molecules attribute may be used on an electricity node to set a demand based on a value in the molecule graph only when Causality is enabled.

Energy nodes using from_molecules should have an initial demand set by ETSource, so that a value can be determined during the first calculation of the energy graph. Typically this involves adding it to the "preset_demand" group and setting a default demand of zero:

- groups = [preset_demand]
~ demand = 0.0

The source attribute

Every molecule node that receives a demand from an energy node must define a source attribute. This should match the key of an energy node where a demand is already known.

- from_energy.source = energy_power_combined_cycle_network_gas

The direction attribute

By default, the molecule flow is determined by the demand of an energy node. For such cases, no direction attribute is needed. However, when used in combination with the conversion attribute, it may be desirable to determine the molecule demand by the input of output of certain carriers on the energy node.

If a node receives both coal and gas energy as inputs, but you only wish to use the coal input to calculate the molecule demand, you must set direction to "input":

- from_energy.direction = input

The conversion attribute

This attribute configures how to convert the quantity of energy (in MJ) to a quantity of molecules. conversion can used with or without the direction attribute.

With no direction value set

In this configuration, the demand in molecules is based on the total demand of the node. However, it would be uncommon for a quantity of energy in MJ to map directly (one-to-one) to a quantity of molecules. To convert from one to another, the conversion acts as a multiplier.

If molecule quantity is measured in kilograms and energy in MJ, the previous gas power plant example (0.1g CO2 per MJ) would be:

- from_energy.conversion = 0.0001

With a direction set

When used in combination with a direction, conversion allows each input or output carrier to have a different conversion to the molecule quantity. The conversion should list each relevant input or output carrier, and the conversion. Any carrier not specified will not influence the quantity of molecules.

- from_energy.conversion.coal = 0.5
- from_energy.conversion.gas = 0.3

Examples

Simple gas power plant

For every 1MJ of energy (node demand) on the gas power plant, 0.5kg of molecules will be set on the molecule graph:

- from_energy.source = energy_power_combined_cycle_network_gas
- from_energy.conversion = 0.5
info

The conversion does not care what molecule carrier is being set. There should be one molecule node for each type of molecule output by the energy node. For example, if the gas power plant has two molecule outputs – CO2 and CO – then there would need to exist two molecule nodes; one for CO2 and one for CO.

Molecule flow varies depending on energy input carrier

For every 1MJ of electricity input 0.3kg of molecules will be set on the molecule graph. For every 1MJ of network gas, 0.5kg will be set:

- from_energy.source = space_heater_hybrid_heatpump
- from_energy.direction = input
- from_energy.conversion.electricity = 0.3
- from_energy.conversion.network_gas = 0.5

Molecule flow is based on energy output

For every 1MJ of useable heat output, 0.25kg of molecules will be set on the molecule graph:

- from_energy.source = industry_aluminium_burner_network_gas
- from_energy.direction = output
- from_energy.conversion.useable_heat = 0.25

Molecule flow is based on a carrier attribute

Rather than hard-coding a conversion value, you may instead read an attribute from a carrier. In place of a numeric value, use carrier: attribute_name.

In this example, the molecule demand will be equal to the demand of the energy node multiplied by the the coal carrier's co2_conversion_per_mj attribute:

- from_energy.source = energy_power_ultra_supercritical_coal
- from_energy.direction = input
- from_energy.conversion.coal = carrier: co2_conversion_per_mj

If the demand for coal by the coal power plant is 100PJ, and the co2_conversion_per_mj is 0.05, then the molecule node will have a demand of 5PJ.

Energy demand is based on molecule demand

An energy node may have a demand set by the demand of a molecule node by using from_molecules on the energy node. The node belongs to the "preset_demand" group with a demand of zero; this demand will be used for the first calculation of the energy graph, but overwritten by the from_molecules value prior to the second calculation.

- groups = [preset_demand]
- from_molecules.source = molecules_sequestration_co2
- from_molecules.conversion = 1.0
~ demand = 0.0