Components for modeling industrial production sites
Project description
ETA Components
This is a component library for the mathematical modeling of industrial production sites. Currently it provides models for energy converters, such as CHPs, absorption chillers and energy storages, networks to connect these components to and basic models to mock energy sources and sinks.
The energy converter models are largely based on Baumgärtner (2020): "Optimization of low-carbon energy systems from industrial to national scale" p. 128 ff.
Modeling backend (Linopy-only)
eta-components constructs linear / mixed-integer linear models using Linopy + xarray (vectorized, labelled-array
model construction). The modeling backend is Linopy-only (no Pyomo fallback).
Components
- A large variety of energy converters:
- AbsorptionChiller,
- GasBoiler and ElectrodeBoiler,
- Chp,
- AirWaterCompressionChiller and WaterWaterCompressionChiller,
- DryCooler,
- ParallelHX and CounterCurrentHX,
- AirWaterHeatPump and WaterWaterHeatPump and
- HeatStorage and ColdStorage.
- Networks to enforce energy balance across all connected components:
- Gas, Hydrogen
- Electrical (AC/DC variants)
- HeatingFluid, CoolingFluid
- Environments to provide access to shared parameters:
- AmbientEnvironment.
- Traders to buy and sell energy across the system's boundaries:
- SimpleBuyer and SimpleSeller.
- Mock models for fixed energy sources and sinks, such as waste heat sources or cooling demands:
- SimpleHeatingSource / SimpleHeatingSink
- SimpleCoolingSource / SimpleCoolingSink
- SimpleElectricitySource / SimpleElectricitySink
- System orchestration:
- BasicSystem (Linopy-only)
Features
- On/off operating decisions for all converters.
- Part-load efficiency for all converters.
- Buying decisions for all converters.
- Objective construction via an objective-term registry (e.g.
StaticCost,Emissions). - Plotting of each network's energy production and consumption.
- Indices not only for time steps but also for typical periods and stochastic samples.
What's not implemented yet
- Investment and maintenance cost for all converters.
- Continuous sizing of all converters.
- Sellers and buyers for cooling energy.
- At the moment these must be implemented with buyers or sellers, respectively (because of negative heat flow).
- Variable temperatures for the networks à la Thermal Dependencies paper.
- Framework for bilevel problems.
- Starting cost, ramp limits and maximum starts per time for relevant equipments.
- Measures for increasing efficiency.
- Material data models for production processes.
Requirements
- Python 3.11 or higher
- A MILP/LP solver supported by Linopy (recommended: HiGHS via
highspy)
Installation
To install the project along with its development dependencies, execute the following command:
poetry install
Optionally install the git hooks:
poetry run pre-commit install
Run tests with:
poetry run pytest
Usage
The entire system is modeled as energy flows, thus no volume flows are explicitly implemented. Each converter, trader or energy source or sink must be connected to its corresponding network(s). The networks then enforce an energy balance across all connected components so that energy production and consumption match for each time step. The energy flows are implemented in a thermodynamic contex with each network as the system's boundary. Thus, inlet energy is positive and outlet energy is negative.
E.g. a gas boiler has a negative gas consumption (because it flows out of the gas network) and a positive heat production (because it flows into the heating network). The same goes for electrical energy. Attention is required when using cooling producers or consumers, as cooling producers move heat out of the cooling network (negative production) and cooling consumers move heat into the network (positive consumption).
Quick start
import eta_components.milp_component_library as mcl
from eta_components.milp_component_library.units.base_unit import BaseStandaloneUnit
class DispatchGenerator(BaseStandaloneUnit):
"""Toy generator with linear marginal cost."""
def __init__(
self,
name: str,
data: dict,
system: mcl.systems.BasicSystem,
*,
electrical_network: mcl.networks.Electrical,
):
self._net = electrical_network
super().__init__(name, data, system)
def build(self) -> None:
idx = self.system.index
p = self.system.add_variable(
f"{self.name}__p",
dims=("year", "period", "time"),
coords={d: idx.coords[d].values for d in ("year", "period", "time")},
lower=0,
)
self.vars["p"] = p
self._net.register_unit(self, p, mcl.networks.PowerSign.POSITIVE)
self.system.add_objective_term(
f"{self.name}__opex",
p * float(self.data.get("marginal_cost", 1.0)),
kind="opex",
)
def unregister(self) -> None:
self._net.unregister_unit(self)
self.system.unregister_unit(self)
@property
def time_step_cost(self):
return 0
@property
def annual_cost(self):
return 0
@property
def onetime_cost(self):
return 0
@property
def emissions(self):
return 0
sys = mcl.systems.BasicSystem(n_years=1, n_periods=2, n_time_steps=3, step_length=5 * 60)
el = mcl.networks.Electrical("electrical", {}, sys)
# Fixed demand profile: consumption is negative by convention.
demand = {
(1, 1, 1): -5,
(1, 1, 2): -4,
(1, 1, 3): -6,
(1, 2, 1): -3,
(1, 2, 2): -2,
(1, 2, 3): -5,
}
_ = mcl.sources_sinks.SimpleElectricitySink("demand", {"P_in": demand}, sys, electrical_network=el)
_ = DispatchGenerator("gen", {"marginal_cost": 2.0}, sys, electrical_network=el)
sys.set_objective(mcl.objectives.StaticCost("cost", {"sense": "minimize", "weights": 1}, sys))
results = sys.solve(solver="highs", options={"time_limit_s": 30})
print(results.solve_info)
print(results.vars)
Key concepts in this Linopy-first workflow:
- Indexing:
system.indexdefines canonical coordinates for("year", "period", "time"). Parameters and variables are represented asxarray.DataArray-like objects aligned to these dims. Seedocs/indexing_and_parameters.md. - Extension points: build your own variables/constraints using
system.add_variable(...)andsystem.add_constraints(...). For objectives, register terms withsystem.add_objective_term(...)and use an objective likeStaticCost. - Networks: networks enforce a vectorized power balance (sum of registered power expressions equals zero).
For a longer quickstart, see docs/quickstart_linopy.md.
For solver configuration, see docs/solver_options.md.
Example
There are examples in the folder examples/.
License
Refer to the LICENSE file distributed with this package.
Adding dependencies
Adding dependencies to the project can be done via
poetry add <package-name>@latest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file eta_components-1.1.0.tar.gz.
File metadata
- Download URL: eta_components-1.1.0.tar.gz
- Upload date:
- Size: 42.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.2 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff2e1f97a68130482bbd8a6255a978553019db7fc62309860a424a7b2976924e
|
|
| MD5 |
7d344ff0dcb0f98ca0fbcd3635fcd14b
|
|
| BLAKE2b-256 |
467cf0ac6858226425448e19dc4a7055a1921645b8c1353803be5b8376c9492d
|
File details
Details for the file eta_components-1.1.0-py3-none-any.whl.
File metadata
- Download URL: eta_components-1.1.0-py3-none-any.whl
- Upload date:
- Size: 67.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.1.3 CPython/3.13.2 Windows/11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9f6e535978f88708f5c3be76823a06c53bc71103c336c72056677f58395dc392
|
|
| MD5 |
ecccd5081f955f1597942500fe290c96
|
|
| BLAKE2b-256 |
a18dd800ee3fd37f93b4bc049cde332ed1e49b6ef8f9108c61932ebd8bcba90b
|