API Reference

This page groups every public binding exported by Posy2. For a narrative guide to the constructors, see Component Builders. Nosy types and lower-level modelling operations are documented in the Nosy API reference.

Package

Posy2 — Module
Posy2

High-level country and regional energy-system modelling tools built on Nosy.jl. Posy2 provides standard component builders, optional DC power-flow constraints,and post-processing for solved Nosy snapshots.

source

Configuration And Input Data

Posy2.Posy2Options — Type
Posy2Options(; data_dir=joinpath(pwd(), "data"),
    techdata_file="tech_data.xlsx", timeseries_file="time_series.xlsx",
    tech_mode=:arguments, timeseries_mode=:arguments,
    discount_rate=0.05, co2_price=0.0)

Configure Posy2 input workbooks and economic assumptions. Pass the resulting object to a Nosy snapshot as Snapshot(sim, Dict(:posy => options)). A snapshot carrying no :posy entry is read as Posy2Options(), which is workbook-free.

Fields:

  • data_dir: directory containing the input workbooks. It defaults to joinpath(pwd(), "data"), which follows the process working directory.
  • techdata_file: technology-parameter workbook filename.
  • timeseries_file: hourly time-series workbook filename.
  • tech_mode: :arguments (default) to use documented neutral defaults and require structural values explicitly, or :excel to fill omitted technology arguments from the workbook.
  • timeseries_mode: :arguments (default) to use documented neutral profiles and require structural profiles explicitly, or :excel to fill omitted profiles from the workbook.
  • discount_rate: real discount rate used to annualise investment and decommissioning costs.
  • co2_price: carbon price applied by emitting component builders.

DC power flow is not configured here: call applydcopf! on the snapshot when a study needs KVL constraints.

source
Posy2.posy_options — Function
posy_options(s::Snapshot)

Return the Posy2Options stored in s.options[:posy], or the workbook-free Posy2Options() when the snapshot carries no :posy entry.

Throw an ArgumentError when the entry is present but is not a Posy2Options object.

source
Posy2.readtechdata — Function
readtechdata(filename="tech_data.xlsx"; data_dir=joinpath(pwd(), "data"))

Open and return the Posy2 technology-parameter workbook at joinpath(data_dir, filename).

The workbook is cached by path, filename, and modification time. If another application has locked the file, Posy2 reads a temporary copy when possible.

source
Posy2.gettechparam — Function
gettechparam(xl, tech_column::String, param::String, sheetname::String, digits::Int)
gettechparam(s::Snapshot, tech_column::String, param::String, sheetname::String;
    digits=6)

Read one technology parameter from sheetname. Technology sheets use a tech column for parameter names and one column per technology; tech_column selects the technology column and param selects the row.

The snapshot method resolves the workbook through Posy2Options when tech_mode=:excel; :arguments rejects direct snapshot lookups. Numeric values are rounded to digits. Cells of a *_profile row hold the yearly cost shares as a semicolon-separated string and are returned as a Vector{Float64}; other strings are returned unchanged. Missing sheets, columns, rows, or values raise ArgumentError with workbook context.

source
Posy2.readtimeseries — Function
readtimeseries(filename="time_series.xlsx";
    data_dir=joinpath(pwd(), "data"))

Open and return the Posy2 hourly time-series workbook at joinpath(data_dir, filename).

The workbook is cached by path, filename, and modification time. If another application has locked the file, Posy2 reads a temporary copy when possible.

source
Posy2.gettimeseries — Function
gettimeseries(xl, title::String, sheetname::String, digits::Int)
gettimeseries(s::Snapshot, title::String, sheetname::String; digits=6)

Read and return the complete column title from sheetname in a Posy2 time-series workbook.

The snapshot method resolves the workbook through Posy2Options when timeseries_mode=:excel; :arguments rejects direct snapshot lookups. Values are rounded to digits. Missing sheets or columns, and columns containing missing, non-numeric, or non-finite values raise ArgumentError with workbook context.

source

Demand And Flexibility

Posy2.makedemand — Function
makedemand(name::String, zone::String, n::Node, s::Snapshot;
    tech::String=name, profile=nothing, profile_multiplier=1.0, profile_shift_hours::Int=0,
    annual_flat_demand::Real=0., grid_losses=0.,
)

Build, connect and return a component based on the Demand template.

Arguments:

  • name: component name prefix.
  • tech: technology label used for reporting and component queries; defaults to name.
  • zone: time series name in the time series workbook (demand sheet).
  • n: demand node to connect the component to.
  • s: snapshot to register the component in.
  • profile: Hourly demand in MW, or a scalar expanded across the simulation mesh. If nothing, read zone from the demand sheet.
  • profile_multiplier: Dimensionless multiplier applied to the profile demand. 0 disables it and skips the zone, profile, and profile_shift_hours inputs.
  • profile_shift_hours: Circular profile shift in hours (e.g. align the first day to Monday).
  • annual_flat_demand: Flat demand in MWh/year, distributed over 8760 hours (annual_flat_demand >= 0).
  • grid_losses: Proportional grid-loss fraction on demand input (0 <= grid_losses < 1).
source
Posy2.makeflathydrogendemand — Function
makeflathydrogendemand(name::String, n::Node, annual_demand::Real, s::Snapshot;
    tech::String=name)

Build, connect and return a flat hydrogen demand component.

Arguments:

  • name: component name prefix.
  • tech: technology label used for reporting and component queries; defaults to name.
  • n: hydrogen demand node to connect the component to.
  • annual_demand: Total hydrogen demand in MWh/year. Must satisfy annual_demand >= 0.
  • s: snapshot to register the component in.
source
Posy2.makeflexhydrogendemand — Function
makeflexhydrogendemand(name::String, n::Node, annual_demand::Real, s::Snapshot;
    tech::String=name)

Build, connect and return a flexible hydrogen demand component.

Arguments:

  • name: component name prefix.
  • tech: technology label used for reporting and component queries; defaults to name.
  • n: hydrogen demand node to connect the component to.
  • annual_demand: Total hydrogen demand in MWh/year, enforced through YearlySum("input", annual_demand, :equal). Must satisfy annual_demand >= 0.
  • s: snapshot to register the component in.
source
Posy2.makedemandresponse — Function
makedemandresponse(name::String, elec::Node, cap, cost::Real, s::Snapshot;
    tech::String=name, type::Symbol=:volDR)

Build, connect and return a demand response component represented as negative consumption.

The positive output is an unconnected accounting flow used for capacity, cost, and reporting. The connected negative consumption input is -(1 - elec.losses) * output; when node losses are zero, it is exactly -output. Consequently, activation enters the nodal balance on the demand side without modifying existing demand components.

Arguments:

  • name: component name prefix.
  • tech: technology label used for reporting and component queries; defaults to name.
  • elec: electricity node to connect the component to.
  • cap: Response capacity in MW. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and Inf leaves output unlimited. nothing emits a warning to distinguish it from unlimited capacity.
  • cost: Activation cost in currency/MWh.
  • s: snapshot to register the component in.
  • type: variable cost label used for reporting (default :volDR).
source

Electric Vehicles

Posy2.makeEV — Function
makeEV(name::String, elec::Node, s::Snapshot;
    tech::String=name,
    fixed_profile::Bool=true, smart_charging::Bool=false, vehicle_to_grid::Bool=false,
    annual_consumption=nothing, offhours1=nothing, offhours2=nothing, minratio=nothing, days_threshold::Integer=104,
    number_ev=nothing, initial_connected_share=nothing,
    zone::Union{Nothing,String}=nothing, tech_column::String="EV",
    compensation::Real=0., grid_losses=0.,
    departures=nothing, arrivals=nothing,
    departure_soc=nothing, arrival_soc=nothing,
    charging_eff::Union{Nothing,Real}=nothing, self_discharge::Union{Nothing,Real}=nothing,
    max_charging_power_per_ev::Union{Nothing,Real}=nothing, max_dispatch_power_per_ev::Union{Nothing,Real}=nothing,
    battery_capacity_per_ev::Union{Nothing,Real}=nothing,
)

Build, connect and return an EV component.

Arguments:

  • name: Component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • elec: Electricity node to connect EV charging/discharging flows.

  • s: Target snapshot where the EV component and behaviors are registered.

  • fixed_profile: Enable fixed-profile EV demand mode (deterministic hourly charging profile).

  • smart_charging: Enable flexible charging mode (charging only, no discharge to grid).

  • vehicle_to_grid: Enable flexible charging + grid discharge (V2G) mode. Exactly one of fixed_profile, smart_charging, vehicle_to_grid must be true.

  • annual_consumption: Yearly EV electricity consumption in fixed-profile mode (MWh/year). Must be non-negative and is rejected in flexible modes.

  • offhours1: Winter off-hour indices (0-23, no duplicates). Required when fixed_profile=true; ignored otherwise.

  • offhours2: Summer off-hour indices (0-23, no duplicates). Required when fixed_profile=true; ignored otherwise.

  • minratio: Dimensionless charging level during off-hours (0 <= minratio <= 1). Required when fixed_profile=true; ignored otherwise. The hourly profile is normalized so that it sums to annual_consumption; a schedule that leaves no charging hour at all (every hour an off-hour with minratio=0) is rejected.

  • days_threshold: Number of first winter days before summer segment in fixed-profile assembly (0 <= days_threshold <= 183, used only when fixed_profile=true).

The fleet, mobility-profile, charging-efficiency, and battery-limit arguments below are used only in flexible/V2G modes unless stated otherwise.

  • number_ev: Number of vehicles in the fleet (> 0). Scales per-vehicle power and battery limits.
  • initial_connected_share: Share of the fleet connected immediately before the first model timestep (0 <= initial_connected_share <= 1).
  • zone: Zone key used to read omitted EV time series in :excel mode.
  • departures: Hourly number of vehicles departing the connected fleet, scalar or vector, nonnegative. If nothing, read it from the configured time-series workbook (EV_departure).
  • arrivals: Hourly number of vehicles arriving to the connected fleet, scalar or vector, nonnegative. If nothing, read it from the configured time-series workbook (EV_arrival).
  • departure_soc: Mean SOC of departing vehicles in [0, 1], scalar or vector. If nothing, read it from EV_departure_soc in :excel mode.
  • arrival_soc: Mean SOC of arriving vehicles in [0, 1], scalar or vector. If nothing, read it from EV_arrival_soc in :excel mode.
  • tech_column: Technology column name in the storage tech data sheet for EV parameters, used in flexible/V2G modes; defaults to "EV".
  • compensation: V2G compensation in currency/MWh of grid discharge (ignored in non-V2G modes).
  • grid_losses: Proportional grid-loss fraction on EV input in fixed-profile mode (0 <= grid_losses < 1).
  • charging_eff: Dimensionless charging efficiency in flexible/V2G modes (0 < charging_eff <= 1); defaults to one in :arguments mode.
  • self_discharge: Self-discharge fraction per hour in flexible/V2G modes (0 <= self_discharge < 1); defaults to zero in :arguments mode.
  • max_charging_power_per_ev: Maximum charging power in MW/vehicle (> 0), required explicitly in :arguments mode.
  • max_dispatch_power_per_ev: Maximum V2G power in MW/vehicle (>= 0), required explicitly for V2G in :arguments mode and ignored otherwise.
  • battery_capacity_per_ev: Battery capacity in MWh/vehicle (> 0), required explicitly in :arguments mode.
source

Generation

Posy2.makedispatchable — Function
makedispatchable(name::String, elec::Node, s::Snapshot;
    tech::String=name, tech_column::String=tech,
    cap=nothing, mincap=nothing, maxcap=nothing, capacity_multiplier=nothing,
    integer_uc=false, uc=false, fuel_node=nothing, co2_node=nothing,
    co2_price=co2_price(s),
    overnight_cost, om_fixed_cost, decommissioning, lifetime,
    construction_profile, decommissioning_profile, connection_cost,
    om_var_cost, fuel_cost, no_load_cost, startup_cost, co2_emission,
    efficiency, unit_size, ramp_up, ramp_down, min_power, min_uptime,
    min_downtime, startup_duration, shutdown_duration,
)

Build, connect and return a dispatchable component.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • tech_column: technology column name in the dispatchable tech data sheet; defaults to tech.

  • elec: Electricity node connected to component output flow.

  • s: Target snapshot where the component and behaviors are registered.

  • cap: Output capacity in MW. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it. Numeric 0 builds a zero-capacity component.

  • mincap: Lower capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • maxcap: Upper capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • capacity_multiplier: Dimensionless time-varying multiplier on output capacity.

  • integer_uc: If true, newly constructed UC commitment variables are integer; used only when uc=true.

  • uc: Enables UC constraints and UC linked costs (no_load_cost, startup_cost). An extracted Snapshot instead replays the commitment schedule already solved for the matching component, and then requires a fixed cap.

  • fuel_node: If provided, fuel is modeled as an input flow linked by efficiency. If nothing, fuel is modeled as a variable cost on output energy (fuel_cost).

  • co2_node: CO2 node connected when co2_emission is nonzero. It is required in that case and otherwise defaults to nothing.

  • co2_price: Carbon price in currency/tCO2, used only when co2_emission != 0.

  • overnight_cost: Overnight CAPEX in currency/kW of output capacity.

  • om_fixed_cost: Fixed O&M in currency/kW/year of output capacity.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

  • connection_cost: Connection cost as a fraction of annualized investment.

  • om_var_cost: Variable O&M in currency/MWh of output.

  • fuel_cost: Fuel cost in currency/MWh of output, used only without fuel_node.

  • no_load_cost: No-load cost in currency/committed-unit/hour, used with UC.

  • startup_cost: Startup cost in currency/unit-start, used with UC.

  • co2_emission: Emission factor in kgCO2/MWh of output; converted to tCO2.

  • efficiency: Output per unit of fuel input (dimensionless when both carriers use MWh), used only with fuel_node.

  • unit_size: Generating-unit size in MW. 0 disables unit sizing; a positive value is required with UC.

  • ramp_up, ramp_down: Maximum ramp fractions of unit capacity per hour; nonzero values require a positive unit_size.

  • min_power: Minimum committed output as a fraction of unit capacity, used only when uc=true.

  • min_uptime, min_downtime, startup_duration, shutdown_duration: Durations in hours, used only when uc=true.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source
Posy2.makenuclear — Function
makenuclear(name::String, elec::Node, s::Snapshot;
    tech::String=name, tech_column::String=tech,
    cap=nothing, mincap=nothing, maxcap=nothing, integer_cap=false, warm_start=nothing,
    uc=false, integer_uc=false, startup_mask=nothing, shutdown_mask=nothing,
    refuel::Bool=true, refuel_duration::Union{Nothing,Real}=nothing,
    refuel_slot_spacing::Union{Nothing,Integer}=nothing, refuel_fraction_per_year::Union{Nothing,Real}=nothing,
    fuel_node=nothing, co2_node=nothing, co2_price=co2_price(s),
    overnight_cost::Union{Nothing,Real}=nothing, om_fixed_cost::Union{Nothing,Real}=nothing,
    decommissioning::Union{Nothing,Real}=nothing, lifetime::Union{Nothing,Real}=nothing, construction_profile=nothing, decommissioning_profile=nothing,
    connection_cost::Union{Nothing,Real}=nothing, om_var_cost::Union{Nothing,Real}=nothing, fuel_cost::Union{Nothing,Real}=nothing,
    waste_cost::Union{Nothing,Real}=nothing, no_load_cost::Union{Nothing,Real}=nothing, startup_cost::Union{Nothing,Real}=nothing,
    co2_emission::Union{Nothing,Real}=nothing, efficiency::Union{Nothing,Real}=nothing, unit_size::Union{Nothing,Real}=nothing,
    ramp_up::Union{Nothing,Real}=nothing, ramp_down::Union{Nothing,Real}=nothing,
    min_power::Union{Nothing,Real}=nothing, min_uptime::Union{Nothing,Real}=nothing, min_downtime::Union{Nothing,Real}=nothing,
    startup_duration::Union{Nothing,Real}=nothing, shutdown_duration::Union{Nothing,Real}=nothing,
)

Build, connect and return a nuclear reactor component.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • tech_column: technology column name in the dispatchable tech data sheet; defaults to tech.

  • elec: electricity node to connect the component to.

  • s: snapshot to register the component in.

  • cap: Output capacity in MW. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it.

  • mincap: Lower capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • maxcap: Upper capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • integer_cap: Integer flag for variable capacity; ignored for fixed or inherited capacity.

  • warm_start: Variable-capacity warm start in MW; ignored for fixed or inherited capacity.

  • uc: Enables UC constraints and UC linked costs. An extracted Snapshot instead replays the commitment schedule already solved for the matching component and requires a fixed cap. Fresh refuelling constraints are built only when uc=true; with uc=false they are ignored, and a replayed schedule retains its solved refuelling decisions.

  • integer_uc: Integer UC commitment variables, used only when uc=true.

  • startup_mask: Startup availability mask, used only when uc=true.

  • shutdown_mask: Shutdown availability mask, used only when uc=true.

  • refuel: Enables planned refuelling constraints. Set to false to disable refuelling regardless of the other refuelling arguments.

  • refuel_duration: Planned refuelling outage in hours. A positive value enables refuelling constraints when refuel_fraction_per_year > 0. If nothing, use the workbook value in :excel mode and zero in :arguments mode.

  • refuel_slot_spacing: Spacing, in hours, of the grid at which a refuelling outage may start: 8760 leaves a single allowed start, 730 leaves about twelve. Must be positive. Required when refuelling is enabled, and not read from the workbook. The grid is mapped onto the time mesh, so a mesh coarser than the spacing opens fewer starts than the grid holds.

  • refuel_fraction_per_year: Minimum refuelling events per unit/year. If nothing, use the workbook value in :excel mode and zero in :arguments mode.

  • fuel_node: If provided, fuel is represented as linked input flow using efficiency. If nothing, fuel_cost is applied as output variable cost.

  • co2_node: CO2 node connected when co2_emission is nonzero. It is required in that case and otherwise defaults to nothing.

  • co2_price: Carbon price in currency/tCO2, used only when co2_emission != 0.

  • overnight_cost: Overnight CAPEX in currency/kW of output capacity.

  • om_fixed_cost: Fixed O&M in currency/kW/year of output capacity.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

  • connection_cost: Connection cost as a fraction of annualized investment.

  • om_var_cost, fuel_cost, waste_cost: Costs in currency/MWh of output; fuel_cost is used directly only without fuel_node.

  • no_load_cost: No-load cost in currency/committed-unit/hour, used with UC.

  • startup_cost: Startup cost in currency/unit-start, used with UC.

  • co2_emission: Emission factor in kgCO2/MWh of output; converted to tCO2.

  • efficiency: Output per unit of fuel input (dimensionless when both carriers use MWh), used only with fuel_node.

  • unit_size: Reactor-unit size in MW. 0 disables unit sizing; a positive value is required with UC.

  • ramp_up, ramp_down: Maximum ramp fractions of unit capacity per hour; nonzero values require a positive unit_size.

  • min_power: Minimum committed output as a fraction of unit capacity, used only when uc=true.

  • min_uptime, min_downtime, startup_duration, shutdown_duration: Durations in hours, used only when uc=true.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source
Posy2.makeintermittentsource — Function
makeintermittentsource(name::String, elec::Node, s::Snapshot;
    tech::String=name, tech_column::String=tech,
    cap=nothing, mincap=nothing, maxcap=nothing,
    weather_year=nothing, profile=nothing,
    co2_node=nothing, co2_price=co2_price(s),
    overnight_cost::Union{Nothing,Real}=nothing, om_fixed_cost::Union{Nothing,Real}=nothing,
    decommissioning::Union{Nothing,Real}=nothing, lifetime::Union{Nothing,Real}=nothing, construction_profile=nothing, decommissioning_profile=nothing,
    connection_cost::Union{Nothing,Real}=nothing, om_var_cost::Union{Nothing,Real}=nothing,
    fuel_cost::Union{Nothing,Real}=nothing, co2_emission::Union{Nothing,Real}=nothing,
)

Build, connect and return an intermittent source component.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • tech_column: technology column name in the intermittent tech data sheet; defaults to tech.

  • elec: electricity node to connect the component to.

  • s: snapshot to register the component in.

  • cap: Output capacity in MW. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it.

  • mincap: Lower capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • maxcap: Upper capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • weather_year: Year suffix used to select profile series profiles_<year>. Required for workbook lookup; unused when profile is supplied explicitly.

  • profile: Dimensionless hourly capacity-factor vector or scalar in [0, 1]. If nothing, read the <tech_column>_<node> workbook column. With numeric cap == 0, an omitted profile is replaced by zero without a workbook or weather-year lookup.

  • co2_price: Carbon price in currency/tCO2, used only when co2_emission != 0.

  • co2_node: CO2 node connected when co2_emission is nonzero. It is required in that case and otherwise defaults to nothing.

  • overnight_cost: Overnight CAPEX in currency/kW of output capacity.

  • om_fixed_cost: Fixed O&M in currency/kW/year of output capacity.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

  • connection_cost: Connection cost as a fraction of annualized investment.

  • om_var_cost, fuel_cost: Costs in currency/MWh of output.

  • co2_emission: Emission factor in kgCO2/MWh of output; converted to tCO2.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source
Posy2.makehydroror — Function
makehydroror(name::String, zone::String, elec::Node, s::Snapshot;
    tech::String=name, cap=nothing, mincap=nothing, maxcap=nothing,
    tech_column::String="Hydro ror", weather_year=nothing,
    intake, intake_profile=nothing,
    overnight_cost::Union{Nothing,Real}=nothing, om_fixed_cost::Union{Nothing,Real}=nothing, om_var_cost::Union{Nothing,Real}=nothing,
    decommissioning::Union{Nothing,Real}=nothing, lifetime::Union{Nothing,Real}=nothing, construction_profile=nothing, decommissioning_profile=nothing,
)

Build, connect and return a run of river hydro component.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • zone: Time series zone used to read the hydro intake profile.

  • elec: electricity node to connect the component to.

  • s: snapshot to register the component in.

  • cap: Output capacity in MW. A number fixes capacity, nothing creates a new capacity decision, a JuMP variable or affine expression reuses that external decision, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it.

  • mincap: Lower capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • maxcap: Upper capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • tech_column: technology column name in the intermittent tech data sheet; defaults to "Hydro ror".

  • weather_year: Year suffix used to select intake series hydro_ror_<year>. Required for workbook lookup; unused when intake_profile is supplied explicitly.

  • intake_profile: Dimensionless hourly run-of-river intake shape or scalar, nonnegative with a strictly positive sum. The profile is normalized to sum to one before the total intake is applied. If nothing, read zone from the selected workbook sheet.

  • intake: Total yearly intake in MWh, spread over the normalized profile. 0 disables intake and skips the zone, profile, and weather-year lookup.

  • overnight_cost: Overnight CAPEX in currency/kW of output capacity.

  • om_fixed_cost: Fixed O&M in currency/kW/year of output capacity.

  • om_var_cost: Variable O&M in currency/MWh of output.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source

Hydrogen

Posy2.makeflathydrogenpurchase — Function
makeflathydrogenpurchase(name::String, n::Node, annual_supply::Real, s::Snapshot;
    tech::String=name)

Build, connect and return a flat hydrogen purchase component.

Arguments:

  • name: component name prefix.
  • tech: technology label used for reporting and component queries; defaults to name.
  • n: hydrogen node to connect the component to.
  • annual_supply: Purchased hydrogen in MWh/year, converted internally to a flat hourly flow (annual_supply / 8760).
  • s: snapshot to register the component in.
source

Storage And Conversion

Posy2.makehydroreservoir — Function
makehydroreservoir(name::String, zone::String, elec::Node, s::Snapshot;
    tech::String=name, tech_column::String=tech,
    discharge_cap, charge_cap, intake, energy_cap=Inf, spillage=false,
    weather_year=nothing, grid_losses=0., simplified=false,
    intake_profile=nothing,
    roundtrip_eff::Union{Nothing,Real}=nothing,
    overnight_cost::Union{Nothing,Real}=nothing, om_fixed_cost::Union{Nothing,Real}=nothing, om_var_cost::Union{Nothing,Real}=nothing,
    decommissioning::Union{Nothing,Real}=nothing, lifetime::Union{Nothing,Real}=nothing,
    construction_profile=nothing, decommissioning_profile=nothing,
)

Build, connect and return a hydro reservoir component.

This builder does not cover endogenous capacity expansion of the reservoir. discharge_cap, charge_cap and energy_cap are exogenous: unlike the other builders they accept neither nothing nor a JuMP expression, and so are never capacity decisions. A model-sized reservoir would be built free of charge, because CAPEX and fixed O&M are applied to discharging capacity alone. Costs still apply to the fixed capacities, so an existing fleet reports its annualized cost.

If you need an expandable reservoir, please write a dedicated component builder for it. It needs a cost basis for each expanded dimension, which the shared storage technology sheet does not carry.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • tech_column: technology column name in the storage tech data sheet; defaults to tech.

  • zone: Zone used for reservoir intake time series lookup.

  • elec: electricity node to connect the component to.

  • s: snapshot to register the component in.

  • discharge_cap: Discharging capacity in MW. A number fixes it, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it.

  • charge_cap: Charging capacity in MW with the same choices. The input port is always created; numeric 0 gives it a zero capacity, so a turbine-only reservoir still reports a charging flow of zero.

  • intake: Total yearly natural intake in MWh, spread over the normalized profile. 0 disables natural intake.

  • energy_cap: Storage level capacity in MWh, with the same choices as discharge_cap, plus Inf (the default) which leaves the level unlimited by adding no level capacity behavior.

  • spillage: Add an unconnected, unlimited spill output that lets the reservoir release stored energy without generating. It defaults to false, which forces all natural intake to eventually become generation.

  • weather_year: Year suffix used to select the intake series stored in reservoir_inflow_<year>. Required when intake_profile is read from the time-series workbook; unused when a profile is supplied explicitly or natural intake is disabled.

  • grid_losses: Proportional charging-loss fraction (0 <= grid_losses < 1).

  • simplified: Passed to LazyStorage(..., simplified=...).

  • intake_profile: Dimensionless hourly natural-intake shape or scalar, nonnegative with a strictly positive sum. It is normalized to sum to one before intake is applied. If nothing, read zone from reservoir_inflow_<weather_year>.

  • roundtrip_eff: Dimensionless round-trip charging efficiency.

  • overnight_cost: Overnight CAPEX in currency/kW of discharging capacity.

  • om_fixed_cost: Fixed O&M in currency/kW/year of discharging capacity.

  • om_var_cost: Variable O&M in currency/MWh discharged.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source
Posy2.makebatterystorage — Function
makebatterystorage(name::String, elec::Node, s::Snapshot;
    tech::String=name, tech_column::String=tech,
    power_cap=nothing, power_mincap=nothing, power_maxcap=nothing,
    simplified=false, grid_losses=0.,
    roundtrip_eff::Union{Nothing,Real}=nothing, duration::Union{Nothing,Real}=nothing,
    overnight_cost::Union{Nothing,Real}=nothing, om_fixed_cost::Union{Nothing,Real}=nothing,
    decommissioning::Union{Nothing,Real}=nothing, lifetime::Union{Nothing,Real}=nothing, construction_profile=nothing, decommissioning_profile=nothing,
    connection_cost::Union{Nothing,Real}=nothing, om_var_cost::Union{Nothing,Real}=nothing,
)

Build, connect and return a battery storage component.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • tech_column: technology column name in the storage tech data sheet; defaults to tech.

  • elec: electricity node to connect the component to.

  • s: snapshot to register the component in.

  • power_cap: Power capacity in MW. It bounds charging and discharging alike, and the stored level at power_cap * duration. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it.

  • power_mincap: Lower power-capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • power_maxcap: Upper power-capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • simplified: Passed to BasicStorage(..., simplified=...).

  • grid_losses: Proportional charging-loss fraction (0 <= grid_losses < 1).

  • roundtrip_eff: Dimensionless round-trip storage efficiency.

  • duration: Storage duration in hours (duration > 0); required in :arguments mode and otherwise read from the workbook when nothing.

  • overnight_cost: Overnight CAPEX in currency/kW of charging capacity.

  • om_fixed_cost: Fixed O&M in currency/kW/year of charging capacity.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

  • connection_cost: Connection cost as a fraction of annualized investment.

  • om_var_cost: Variable O&M in currency/MWh charged.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source
Posy2.makehydrogenstorage — Function
makehydrogenstorage(name::String, h2::Node, s::Snapshot;
    tech::String=name, tech_column::String=tech,
    energy_cap=nothing, energy_mincap=nothing, energy_maxcap=nothing,
    roundtrip_eff::Union{Nothing,Real}=nothing,
    overnight_cost::Union{Nothing,Real}=nothing, om_fixed_cost::Union{Nothing,Real}=nothing,
    decommissioning::Union{Nothing,Real}=nothing, lifetime::Union{Nothing,Real}=nothing, construction_profile=nothing, decommissioning_profile=nothing,
)

Build, connect and return a hydrogen storage component.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • tech_column: technology column name in the storage tech data sheet; defaults to tech.

  • h2: hydrogen node to connect the component to.

  • s: snapshot to register the component in.

  • energy_cap: Stored-energy capacity in MWh. Charging and discharging power are left unlimited. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it.

  • energy_mincap: Lower energy-capacity bound in MWh; checked as an assertion against a fixed or inherited one.

  • energy_maxcap: Upper energy-capacity bound in MWh; checked as an assertion against a fixed or inherited one.

  • roundtrip_eff: Dimensionless round-trip storage efficiency. If nothing, read it from the workbook in :excel mode and use one in :arguments mode.

  • overnight_cost: Overnight CAPEX in currency/kWh of storage capacity.

  • om_fixed_cost: Fixed O&M in currency/kWh/year of storage capacity.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source
Posy2.makeelectrolyser — Function
makeelectrolyser(name::String, elec::Node, h2::Node, s::Snapshot;
    tech::String=name, tech_column::String=tech,
    cap=nothing, mincap=nothing, maxcap=nothing,
    grid_losses=0.,
    efficiency::Union{Nothing,Real}=nothing,
    overnight_cost::Union{Nothing,Real}=nothing, om_fixed_cost::Union{Nothing,Real}=nothing,
    decommissioning::Union{Nothing,Real}=nothing, lifetime::Union{Nothing,Real}=nothing, construction_profile=nothing, decommissioning_profile=nothing,
    om_var_cost::Union{Nothing,Real}=nothing,
)

Build, connect and return an electrolyser component.

Arguments:

  • name: component name prefix.

  • tech: technology label used for reporting and component queries; defaults to name.

  • tech_column: technology column name in the electrolysis tech data sheet; defaults to tech.

  • elec: electricity node to connect the component to.

  • h2: hydrogen node to connect the component to.

  • s: snapshot to register the component in.

  • cap: Electricity input capacity in MW. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the capacity of "<name> <node name>" in it.

  • mincap: Lower capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • maxcap: Upper capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • grid_losses: Proportional electricity-loss fraction (0 <= grid_losses < 1).

  • efficiency: Hydrogen output per unit of electricity input (dimensionless when both carriers use MWh). If nothing, read it from the workbook in :excel mode and use one in :arguments mode.

  • overnight_cost: Overnight CAPEX in currency/kW of electricity input capacity.

  • om_fixed_cost: Fixed O&M in currency/kW/year of electricity input capacity.

  • decommissioning: Decommissioning cost as a fraction of overnight CAPEX.

  • lifetime: Asset lifetime in years (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares.

  • decommissioning_profile: Dimensionless yearly decommissioning-cost shares.

  • om_var_cost: Variable O&M in currency/MWh of electricity input.

With nothing, economic arguments use workbook values in :excel mode. In :arguments mode, costs default to zero; nonzero overnight cost requires lifetime and construction_profile, plus decommissioning_profile when decommissioning is nonzero.

source

Interconnections

Posy2.makepricelink — Function
makepricelink(name::String, elec::Node, s::Snapshot;
    neighbor::String=name, neighbor_column::String=neighbor,
    import_cap=nothing, import_mincap=nothing, import_maxcap=nothing,
    export_cap=nothing, export_mincap=nothing, export_maxcap=nothing,
    exclusive_direction::Bool=false, neighbor_is_foreign::Bool=true,
    transaction_cost::Real=0.,
    spot_price=nothing, import_availability=nothing, export_availability=nothing,
)

Build, connect and return an interconnection component named "<name>_<elec.name>", trading with a neighbouring market represented by an exogenous price series instead of an explicit node. If exclusive_direction is true, apply a one direction at a time constraint at every timestep.

Arguments:

  • name: interconnector name prefix.

  • elec: local electricity node to connect the interconnector to.

  • s: snapshot to register the component in.

  • neighbor: counterparty market, reported as the :neighbor tag and as the remote endpoint of directed flows. Defaults to name.

  • neighbor_column: name the workbook columns are built from. Defaults to neighbor.

  • import_cap: Import capacity in MW, following the common capacity contract: a number fixes it, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the "output" capacity of "<name>_<elec.name>" in it. Numeric 0 disables imports.

  • import_mincap: Lower import capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • import_maxcap: Upper import capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • export_cap: Export capacity in MW, with the same contract; an extracted Snapshot inherits the "input" capacity. Numeric 0 disables exports.

  • export_mincap: Lower export capacity bound in MW.

  • export_maxcap: Upper export capacity bound in MW.

  • exclusive_direction: if true, apply SOS1 one direction at a time flow constraint.

  • neighbor_is_foreign: if true, the neighbouring market lies outside the modelled system and the component is tagged :foreign. A price interconnection carries this on itself because its remote endpoint is not a node that could hold a :foreign tag, unlike maketransmissionlink. Set it to false when the price series represents another internal zone.

  • transaction_cost: Transaction adder in currency/MWh on both directions.

  • spot_price: Foreign spot price in currency/MWh, as an hourly vector or scalar.

  • import_availability: Dimensionless hourly multiplier for the foreign-to-local direction, each value in [0, 1], read from column "<neighbor_column>><elec.name>".

  • export_availability: Dimensionless hourly multiplier for the local-to-foreign direction, with the same [0, 1] domain, read from column "<elec.name>><neighbor_column>". Availability is resolved for every direction except a numeric zero one. When omitted, it comes from the workbook in :excel mode and defaults to one in :arguments mode. spot_price is required whenever either direction has active capacity, and is read from column "<neighbor_column>". When both capacities are numeric zeros the corridor is disabled: no spot price is read and the reported exogenous price is an hourly series of zeros.

Neither direction carries an investment cost, so bound an optimized capacity with import_maxcap or export_maxcap.

source
Posy2.maketransmissionlink — Function
maketransmissionlink(name::String, a::Node, b::Node, s::Snapshot;
    cap=nothing, mincap=nothing, maxcap=nothing,
    exclusive_direction::Bool=false, dc::Bool=false,
    transaction_cost::Real=0., loss_factor::Real=0.,
    susceptance::Union{Nothing,Real}=nothing,
    a_to_b_availability=nothing, b_to_a_availability=nothing,
    overnight_cost=nothing, om_fixed_cost=nothing,
    lifetime=nothing, construction_profile=nothing,
)

Build, connect and return an interconnection component linking two nodes. Whether the link crosses the self-system boundary is derived at reporting time from the connected nodes' :foreign tags; there is no component-level flag.

Arguments:

  • name: interconnector name prefix.

  • a: first node linked by the interconnector.

  • b: distinct second node linked by the interconnector; self-connections are rejected before model construction.

  • s: snapshot to register the component in.

  • cap: Installed capacity in MW. A number fixes capacity, a JuMP VariableRef or AffExpr reuses that expression, nothing creates a capacity decision, and an extracted Snapshot inherits the capacity of "<name>_<a.name>_<b.name>" in it. Numeric 0 builds a zero-capacity component.

  • mincap: Lower capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • maxcap: Upper capacity bound in MW; checked as an assertion against a fixed or inherited one.

  • exclusive_direction: apply an SOS1 one direction at a time flow constraint.

  • dc: if true, tag as :DC; otherwise tag as :AC.

  • transaction_cost: Transaction adder in currency/MWh on each direction.

  • loss_factor: Dimensionless proportional loss; must be finite and satisfy 0 <= loss_factor < 1.

  • susceptance: AC series susceptance in model power units/rad (MW/rad under the standard convention; must be negative), used only when dc=false; stored in Snapshot.options[:ic_susceptance] (required for KVL when applydcopf! is called).

  • a_to_b_availability: Dimensionless hourly a -> b multiplier vector or scalar, each value in [0, 1].

  • b_to_a_availability: Dimensionless hourly b -> a multiplier vector or scalar, with the same [0, 1] domain. These directional multipliers represent asymmetric available transfer capacity against the shared installed capacity. A nonzero fixed or optimized capacity reads both workbook columns in :excel mode when omitted, and defaults both to one in :arguments mode. Numeric zero does not resolve either availability series.

  • overnight_cost: Overnight CAPEX in currency/kW of shared capacity. Defaults to zero.

  • om_fixed_cost: Fixed O&M in currency/kW/year of shared capacity. Defaults to zero.

  • lifetime: Asset lifetime in years, used to annualize nonzero overnight cost (> 0, integer-valued).

  • construction_profile: Dimensionless yearly construction-cost shares, required when overnight_cost is nonzero.

In :excel mode both directional multipliers are read from the sheet that matches the link type: transfer_capacities_AC when dc=false, transfer_capacities_DC when dc=true. Columns are named From>To after the node names. An AC and a DC link on the same node pair therefore carry their own availability series, and neither reads transfer_capacities, which belongs to makepricelink.

Node interconnections cannot be added after applydcopf! has run on the snapshot; build the full topology first.

Exactly one AC and one DC may share the same unordered node pair (either, both, or neither is fine). A second AC or a second DC on that pair raises an error. Component-name collisions are also rejected before model construction. Aggregate equivalent parallel circuits before calling this builder.

source

Economics And Optimisation

Posy2.eac — Function
eac(overnight_cost::Real, discount_rate::Real, lifetime, construction_profile)

Return the annualized investment cost in function of the overnight cost, the discount rate, the lifetime and the construction profile. The effects are the following:

  • total cost (financing taking construction time into account + overnight cost)
  • annualization via corrected CRF (so that operation starts right after construction, no white year)

Units: overnight_cost is a cost per unit of capacity and the result is that cost per unit of capacity per year. Builders take overnight_cost in currency per kW and multiply it by 1000 before calling eac, so a direct call takes currency per MW and returns currency per MW per year. discount_rate is a fraction per year, lifetime is a number of years, and construction_profile is a number or a vector of yearly shares summing to 1.

source
Posy2.applydcopf! — Function
applydcopf!(s::Snapshot)

Add KVL (DC power flow) constraints at snapshot level, so that cycles in the AC network are enforced globally. For each independent cycle, constrain sum(flow_ij / B_ij) = 0, where flow_ij is the net midpoint flow and B_ij the susceptance registered by maketransmissionlink. DC interconnections are excluded. Warns when there is no AC loop to constrain.

Call it before Nosy.optimize! in the studies that need DC power flow, and leave it out of the others: there is no snapshot option to switch it off.

It may be called only once per snapshot, and no node interconnection may be added afterwards: the constraints are built from the topology present at the call, so a second call would stack duplicates and a later interconnection would leave them describing a different network. Both raise an ArgumentError.

source

Post-processing And Export

Posy2.selfcost — Function
selfcost(s::Snapshot)

Return the self total cost associated with Snapshot s. This includes:

  • all non-interconnection components in self nodes
  • no non-interconnection components in foreign nodes
  • import costs and export revenues for interconnections connected to self nodes
  • congestion rent for interconnections connected to self nodes
source
Posy2.losses — Function
losses(s::Snapshot; collapse=true, categories=LOSSCATEGORIES, by=nothing)

Return a DataFrame of the electricity losses of Snapshot s, with one row per (loss source, node) pair and the columns:

columncontent
nodeelectricity node the loss is charged to
sourcecomponent causing the loss, or the node name for :node losses
techtechnology label of the source
categoryone of (:node, :component, :interconnection, :storage, :selfdischarge)
lossesMWhe value, or hourly MWhe series when collapse=false

Lossless sources are omitted, so an empty table means a lossless system.

categories restricts the reported categories:

  • :node: nodal losses of Node(losses=...), a ratio of the node inflow
  • :component: proportional grid losses flow of a single component
  • :interconnection: transfer losses of a node interconnection
  • :storage: charging conversion loss of a storage or EV, input * (1 - eff)
  • :selfdischarge: stored energy lost over a timestep

Only (:node, :component, :interconnection) are flows of the nodal balance; :storage and :selfdischarge are internal to their component and are already included in its charging flow.

Every row is attributed to a single node, and a component spanning several electricity nodes (a node interconnection) splits its loss equally between them. Therefore sum(df.losses) is the system total, grouping by node gives nodal losses and grouping by source gives whole-component losses.

by aggregates the table over one or more of :node, :source, :tech and :category, keeping the losses column:

losses(result)                          # every loss source
losses(result; by=:node)                # losses of each node
losses(result; by=(:tech, :category))   # losses of each technology, split by cause
losses(result; by=:source, categories=(:interconnection,))  # losses of each interconnection

Losses of non-electricity nodes (e.g. hydrogen storage) are out of scope, and so are carrier conversion losses (electrolysis, fuel to power): their output is a product on another carrier rather than a loss of the electricity system.

source
Posy2.write_results — Function
write_results(s::Snapshot{Float64}, path::String; overwrite::Bool=false)

Write the standard Posy2 workbook report of the extracted snapshot s to path and return path. Missing parent directories are created.

path is taken as given, extension included; nothing is prepended to it. An existing file is never touched unless overwrite=true is passed, in which case it is replaced.

source