oemof.solph

repository·dev·Indexed 19 days ago

https://github.com/oemof/oemof-solph

A model generator for energy system modelling and optimisation using Linear Programming (LP) and Mixed-Integer Linear Programming (MILP). It allows users to build energy systems as mathematical graphs consisting of EnergySystems, Busses (commodities), and Components such as Sinks, Sources, Converters, and GenericStorage.

Tokens
41.3K
Snippets
115
Records
253
Agent score
65%

What's inside oemof-solph

  1. Understand the core concepts of oemof.solph

    dev

    To model and solve energy systems with oemof.solph, you need to understand four primary conceptual pillars:

    1. Energy System: The top-level abstraction representing the entire network of interconnected parts.
    2. Components: The individual building blocks (e.g., generators, storage, loads) that interact within the system.
    3. Optimization Model: The mathematical representation of the energy system that is passed to a solver to find an optimal operating state.
    4. Result Handling: The process of extracting and analyzing the data produced by the solver after the optimization is complete.
  2. Reduce inflow based on storage level in GenericStorage

    dev
    The GenericStorage component in v0.6.4 now supports reducing inflow based on the current storage_level. Note that this feature is currently being rolled out and does not yet work with all investment types. Check the specific documentation for GenericStorage to see if your specific investment configuration is supported.
  3. Understand the impact of temporal aggregation on data

    dev

    Temporal aggregation (averaging data over larger time steps) has specific effects on energy data:

    • Peak Reduction: Averaging power values reduces the peaks in the data.
    • Energy Preservation: While peaks are reduced, the total energy over the period remains preserved.
    • Bias: Lower resolutions systematically overestimate low loads because the volatility is smoothed out.

    To reduce the number of time steps in a model without losing significant data, you can segment the time index (e.g., dropping nocturnal hours where solar PV production is zero).

  4. Use the shared_limit constraint

    dev
    The shared_limit constraint allows you to restrict the weighted sum of arbitrary variables to a specific corridor. This is useful for modeling shared resources, such as using shared space to store different materials (e.g., wood pallets and logs) with different energy densities.
  5. Understand the EnergySystem model structure

    dev

    An EnergySystem is a mathematical graph of edges and nodes used to model energy networks. It is composed of three main elements:

    • Edges (Flows): Connections between elements that hold optimization variables (e.g., energy amounts or installed capacity) and constraints (e.g., upper/lower bounds).
    • Nodes (Buses): Represent commodities (electricity, heat, gas). A Bus balances inflows and outflows, ensuring their sum equals zero at any time step.
    • Nodes (Components): Model energy conversion (e.g., Converter), energy sources (e.g., Source), energy sinks (e.g., Sink), or energy storage (e.g., Storage).

    To build a model, you initialize an EnergySystem with a time index and then add nodes and flows to define the network topology.

  6. Accessing and navigating model results

    dev

    When you call Model.solve(solver=solver), it returns a Results object. This object behaves like a Python dictionary where the keys correspond to existing variables in your model. The values are typically pandas.Series or pandas.DataFrames.

    Key Characteristics

    • On-demand processing: Accessing data can trigger calculations. To save time, avoid accessing details you do not need.
    • Indexing: Columns are typically indexed using nodes. You can use either the Node objects themselves or their string labels to access data.
    • Keys: Use Results.keys() to see all available variable names in the results object.

    Accessing Data

    To access specific flows or storage levels, use the variable name as the key and the node (or node label) as the index/column identifier.

    results = model.solve(solver=solver)
    # Using Node objects
    flow_from_to = results["flow"][(from_node, to_node)]
    storage_content = results["storage_content"][storage_node]
    
    # Using string labels (equivalent to using Node objects)
    flow_from_to = results["flow"][("from_node_label", "to_node_label")]
    storage_content = results["storage_content"]["storage_node_label"]
  7. Configure BDEW heat load profile content

    dev
    In version 0.0.6, the BDEW heat load profile method was updated to allow users to specify the scope of the generated heat load profile. You can now choose whether the profile includes only space heating or a combination of space heating and warm water.
  8. Optimize PV plant capacity using Investment objects

    dev

    To make the nominal capacity of a component (like a PV plant) an optimization variable rather than a fixed value, assign an Investment object to its nominal_capacity attribute. This allows the optimizer to find the peak power that minimizes total system costs.

    Note: When optimizing capacity, it is a best practice to set a maximum capacity limit to ensure model convergence, preventing the optimizer from attempting to build an infinite system if it is profitable.

    # Example concept: assigning an Investment object to capacity
    # pv_system.nominal_capacity = Investment(periodical_cost=75, ...)
  9. Optimize component capacity using solph.Investment

    dev

    To perform combined design and dispatch optimization (where the size of a component is determined by the optimizer rather than being predefined), pass an instance of solph.Investment to the component's capacity attribute instead of a numerical value.

    When using solph.Investment, you can specify:

    • ep_cost: The equivalent periodical cost (used for economic optimization).
    • Bounds: Upper and lower limits for the capacity optimization.

    This allows the model to decide the most economically efficient size for components like heat pumps or boilers based on the system's requirements and costs.

    # Example concept: setting capacity to an Investment object instead of a float
    component.capacity = solph.Investment(ep_cost=calculated_epc, lower_bound=0, upper_bound=100)
  10. How pathway planning works with time series aggregation

    dev

    Pathway planning allows investment variables to be time-dependent, meaning new capacity can be added at predefined points in time (e.g., every 5 years) rather than just once at the start.

    Requirements and Constraints:

    • Mandatory Pairing: In the current version of oemof.solph, you must use time series aggregation together with pathway planning.
    • Dual Time Indices: You need a "normal" time index for operational resolution (e.g., hourly) and a set of investment periods (e.g., 5-year blocks).
    • Operational Data: All operational time series must span the entire optimization horizon and match the combined length of the investment periods.

    Implementation Steps:

    1. Build one continuous operational time index covering the entire horizon.
    2. Create a list of time indices, one for each investment period.
    3. Create a dictionary of TSAM parameters, with one entry per investment period.

    Note: This feature is currently experimental.