The Hydrogen model is the first step to a general model framework for any energy system representable as a network of regions, hubs, and transportation arcs. It is provided with data and functions specific to Hydrogen production and distribution but aims to be agnostic to the energy carrier being modeled.
The model centers on an object type called Grid, which creates a collection of objects (Regions, Hubs, Arcs, and Registry) that function together to allow users to manipulate the model interactively. A user can input data at the most granular level, and then customize their run for the resolution they desire.
Once the user has specified the configuration they desire via the Grid object, they can build a Pyomo model object that performs the optimization and outputs results.
Data for a run must first be prepared in the following files. For each file, there is a specific format that must be followed:
The regions.csv file stores the regionality settings for the grid you are creating. The CSV should flow from top level regions in the first column, and subregions must be entered in the following columns. Mixed depths are supported, so you can have a blank entry in a subregion column, and the build will look to the subsequent columns to find a subregion. Any region that appears in a column to the right of a region in another column, on the same row, will be treated as a subregion contained in its parent region.
For example, the following table would generate the regionality in the below diagrams:
region | subregion | sub-subregion | data | parameters |
---|---|---|---|---|
A | A data | |||
A | A1 | A1 data | ||
A | A1 | A1a | A1a data | |
A | A2 | A2 data | ||
A | A2 | A2a | A2a data | |
A | A2 | A2b | A2b data | |
B | B data | |||
B | Ba | Ba data |
This would append all the rows after the column labeled data to the rightmost region that appears in that row. You can create any parameters you want; the model can freely be expanded upon.
A few final notes on the regions data formatting:
-
IMPORTANT NOTE: region names must be unique. If this is a problem (for example, where all region types use numeric-naming) you can hyphenate the names or append a prefix depending on which column it is in.
-
If you aggregate to top-level regions, they aggregate the data from their subregions to acquire their own data. Region data includes electricity and natural gas costs, and demand.
The fundamental unit of production is the hub. Th hubs.csv file lists the hubs, what region they are located in, and the rest of the columns are parameter / data fields that get attached to that hub.
In the first column, insert the names of the hubs, and in the second column, the name of the region. Every column afterwards should contain hub-specific parameters. For example, production capacity, geographic coordinates etc. Currently, hubs are set to be 1 hub per subregion. Higher level regions have no hubs of their own.
Transportation of the resource in the model follows entities called transportation arcs. These are connections between hubs, and the data format is in the transportation_arcs.csv file where the arcs are represented by two columns - 'origin' and 'destination'. All other columns are for data / parameters you want to attach to the arc; for now, these are just capacity and cost.
The parameter_list.xlsx file is an excel file with 4 sheets. One sheet for region, one for hub, and for arc, and one for global. The purpose of this file is to list all the parameters and their properties.
The two properties for given parameters are 'aggregation_type' and 'default_value'
-
aggregation_type: can be either summable or meanable so that if you load data, and then decide to do a run where you aggregate regions, it knows how to combine the data during aggregation. Meanable quantities (e.g. costs) get averaged, and summable quantities (e.g. capacities) get summed.
-
default_value: the value if none are specified by the user. It is useful to set it to either zero or inf so that functionally if you do not specify, it defaults to an infeasible value.
See the hydrogen preprocessor directory for more information on how input data is prepared.
The fundamental structure of the model is an object called a Grid. Grids coordinates actions between Region, Hub, and Arc, and Registry, allowing you to manipulate data that the model reads. It also visualizes your network.
When a Grid object is created, the regions in the data file are instantiated as a collection of Region objects, and the data for each Region is appended to the object. Hubs are created as independent objects that are assigned a home Region. Arcs are instantiated with references to their origin and destination Hub objects, and the Hub objects record the Arcs they are connected to.
The Grid class has a large number of methods that can be called. The main ones a user might interact with are the aggregation methods: collapse() and collapse_level()
This takes the name of a region as an argument and makes that region absorb all its subregions (and they absorb their subregions etc.) so that the region becomes a leaf in the tree hierarchy. For any data entries the region has no field for, it will aggregate the corresponding entries in the subregions and acquire that value for the region. Currently there are two aggregation methods that the user inputs in the parameter_list.xlsx input file for each data field - "summable" and "meanable". The summable fields get added when aggregating (i.e., demand, population etc.) and the meanable quantities get averaged (i.e., prices, weather conditions etc.)
A user who wants to model only some regions in detail and wants a coarser representation of other regions to reduce complexity could use this feature to simplify a grid. For example, see the following grid:
If the user runs the following method...
grid.collapse('South')
... they create a grid with the southern region collapsed as visualized in the network.
This method takes the desired depth of region nesting, and collapses all regions at that depth. If you have four levels of region-nesting, say Region, Census Region, State, County, and you want to collapse the data to only two levels of depth, you'd use collapse_level. For example, our regionality in the image above:
would become the following after running collapse_level
grid.collapse_level(2)
Collapsing further to the highest nesting level results in a more "sparse" grid object.
grid.collapse_level(1)
The Hydrogen Model is a cost minimization linear program that seeks to minimize total cost given the constraints on production capacity, demand, and transportation.
Demand is either exogenous in integrated mode or included in the input files as a base parameter with changes over time governed by a function in standalone mode.
Demand is specific to regions and the hubs in a region must satisfy the given demand for each time index. Hubs may not exceed their production capacity, but capacity can be expanded to meet demand in subsequent years. In addition, production can be transported along transportation arcs, subject to transportation constraints, incurring a cost per unit transported.
When the model runs, it returns the dual of the demand constraints, giving a regional hydrogen price.
Name | Symbol | Code | Description |
---|---|---|---|
Hubs | hubs | The names of all the hubs (str) | |
Arcs | arcs | The names of all the arcs, which are tuples of hubs, in the format (origin hub, destination hub) | |
Regions | regions | The names of all the regions for which demand is being calculated (str) | |
Technologies | technology | The names of technology types for production (str) | |
Year | year | The year index (RangeSet) |
Name | Symbol | Code | Units | Description |
---|---|---|---|---|
Production Capacity | capacity | kg H2/year | the base production capacity for each hub and technology type (index: hubs,technology) | |
Electricity Consumption Rate | electricity_consumption_rate | GWh/kg | The base electricity_consumption_rate for producing a unit of fuel (index: technology) | |
Gas Price | gas price | $/mmBtu | price of gas in $/mmBtu (index: regions, year) | |
Hydrogen Demand | demand | kg H2 | hydrogen demand in kg (index: regions, year) | |
Electricity Price | electricity_price | $/KWh | price of electricity in $/GWh (index: regions, year) | |
Production Cost | cost | $/kg | cost to produce 1 kg of hydrogen (index:hubs, technology, year) | |
Transportation Capacity | transportation_capacity | kg H2/year | ||
Transportation Cost | $/kg H2 | |||
Capacity Expansion Cost | $/ kg H2/year | |||
Transportation Capacity Expansion Cost | $/kg H2/year |
Name | Symbol | Domain | Code | Units | Description |
---|---|---|---|---|---|
Hydrogen Production Volume | h2_volume | kg H2 | hydrogen production in kg (index: hubs, technology, year) | ||
Transportation Volume | transportation_volume | kg H2 | h2 transported along arc in kg (index: arcs, year) | ||
Production Capacity Expansion | capacity_expansion | kg H2/year | production capacity expansion in kg (index: hubs, technology, year) | ||
Transportation Capacity Expansion | trans_capacity_expansion | kg H2/year | transportation capacity expansion along arc (index: arcs, year) |
The Objective function is a total cost expression that can be divided into distinct parts representing production costs, transportation costs, production capacity expansion costs, and transportation capacity expansion costs.
Each component of the objective function are explained below.
Production cost is a variable cost associated with hydrogen production. In the code, it is initialized as a function, get_production_cost, which should be modifiable with access to all data in the model itself as well as all data stored in the grid. This is open-ended. For the current simplified version, it is set to just energy consumption costs.
Currently, Production cost uses the below formula.
Letting
Production Capacity Expansion cost is the levelized annual financing cost of building production capacity. It is also the product of many components from preprocessor data, filled in by a function and treated as a black box. For that reason, it is simply represented by the parameter
Letting
Let
The values going into
Let
The details of transportation capacity expansion cost are glossed over, but should depend on the distance and terrain in between the origin and destination hubs, which isn't fully known.
Denoted capacity_constraint in the model. Notation is as follows:
--
The Constraint expression for the capacity constraints are by hub, and take the following form:
not explicitly stored as a parameter, but as data attached to individual arcs (this should be fixed)
notation:
--
Currently not implemented
notation:
--
The constraints are by region, which is how demand is processed for the model. The demand must be met for each region in each year. The constraints add up all production in regions with hubs present, plus the net transportation flow for all of them. Mathematically: