Battery Storage

Battery Storage class based on PySAM’s BatteryStateful Model

class hopp.simulation.technologies.battery.battery.Battery(site: SiteInfo, config: BatteryConfig, config_name: str = 'StandaloneBatterySingleOwner')

Bases: PowerSource

Battery storage class based on PySAM’s BatteryStateful Model.

Parameters:
  • site – Site information

  • config – Battery configuration

site: SiteInfo
config: BatteryConfig
config_name: str
outputs: BatteryOutputs
module_specs = {'capacity': 400, 'surface_area': 30}
setup_system_model()

Executes Stateful Battery setup

property system_capacity_voltage: tuple

Battery energy capacity [kWh] and voltage [VDC]

property system_capacity_kwh: float

Battery energy capacity [kWh]

property system_capacity_kw: float

Battery power rating [kW]

property system_voltage_volts: float

Battery bank voltage [VDC]

property system_mass: float

Battery bank mass [kg]

property footprint_area: float

Battery bank footprint area [m^2]

property energy_capital_cost: float | int

The capital cost per unit of energy capacity [$/kWh] for battery storage technology

property power_capital_cost: float | int

The capital cost per unit of power capacity [$/kW] for battery storage technology

property chemistry: str

Battery chemistry type

setup_performance_model()

Executes Stateful Battery setup

simulate_with_dispatch(n_periods: int, sim_start_time: int | None = None)

Step through dispatch solution for battery and simulate battery

Parameters:
  • n_periods – Number of hours to simulate [hrs]

  • sim_start_time – Start hour of simulation horizon

simulate_power(time_step=None)

Runs battery simulate and stores values if time step is provided

Parameters:

time_step – (optional) if provided outputs are stored, o.w. they are not stored.

update_battery_stored_values(time_step)

Stores Stateful battery.outputs at time step provided.

Parameters:

time_step – time step where outputs will be stored.

validate_replacement_inputs(project_life)

Checks that the battery replacement part of the model has the required inputs and that they are formatted correctly.

batt_bank_replacement is a required array of length (project_life + 1), where year 0 is “financial year 0” and is prior to system operation If the battery replacements are to follow a schedule (batt_replacement_option == 2), the batt_replacement_schedule_percent is required. This array is of length (project_life), where year 0 is the first year of system operation.

__init__(site: SiteInfo, config: BatteryConfig, config_name: str = 'StandaloneBatterySingleOwner') None

Method generated by attrs for class Battery.

_get_model_dict() dict

Convenience method that wraps the attrs.asdict method. Returns the object’s parameters as a dictionary.

Returns:

The provided or default, if no input provided, model settings as a dictionary.

Return type:

dict

as_dict() dict

Creates a JSON and YAML friendly dictionary that can be save for future reloading. This dictionary will contain only Python types that can later be converted to their proper Turbine formats.

Returns:

All key, vaue pais required for class recreation.

Return type:

dict

assign(input_dict: dict)

Sets input variables in the PowerSource class or any of its subclasses (system or financial models)

property benefit_cost_ratio: float

Benefit cost ratio [-] = Benefits / Costs

Benefits include (using present values):

  1. PPA, capacity payment, and curtailment revenues

  2. Federal, state, utility, and other production-based incentive income

  3. Salvage value

Costs: uses the present value of annual costs

calc_capacity_credit_percent(interconnect_kw: float) float

Calculates the capacity credit (value) using the last simulated year’s max feasible generation profile.

Parameters:

interconnect_kw – Interconnection limit [kW]

Returns:

capacity value [%]

calc_nominal_capacity(interconnect_kw: float)

Calculates the nominal AC net system capacity based on specific technology.

Parameters:

interconnect_kw – Interconnection limit [kW]

Returns:

system’s nominal AC net capacity [kW]

property capacity_credit_percent: float

Capacity credit (eligible portion of nameplate) [%]

property capacity_factor: float

System capacity factor [%]

property capacity_payment: list

Capacity payment revenue [$]

property capacity_price: list

Capacity payment price [$/MW]

property construction_financing_cost: float
copy()
Returns:

new instance

property cost_installed: float

Net capital cost [$]

property debt_payment: tuple

Debt total payment [$]

property degradation: tuple

Annual energy degradation [%/year]

property dispatch

Dispatch object

property dispatch_factors: tuple

Time-series dispatch factors normalized by PPA price [-]

property energy_purchases: tuple

Energy purchases from grid [$]

property energy_sales: tuple

PPA revenue gross [$]

property energy_value: tuple

PPA revenue net [$]

export()
Returns:

dictionary of variables for system and financial

property federal_depreciation_total: tuple

Total federal tax depreciation [$]

property federal_taxes: tuple

Federal tax benefit (liability) [$]

classmethod from_dict(data: dict)

Maps a data dictionary to an attr-defined class.

TODO: Add an error to ensure that either none or all the parameters are passed in

Parameters:

data – dict The data dictionary to be mapped.

Returns:

cls

The attr-defined class.

property gen_max_feasible: list

Maximum feasible generation profile that could have occurred (year 1)

classmethod get_model_defaults() Dict[str, Any]

Produces a dictionary of the keyword arguments and their defaults.

Returns:

Dictionary of keyword argument: default.

Return type:

Dict[str, Any]

static import_financial_model(financial_model, system_model, config_name)
initialize_financial_values()

These values are provided as default values from PySAM but should be customized by user

Debt, Reserve Account and Construction Financing Costs are initialized to 0 Federal Bonus Depreciation also initialized to 0

property insurance_expense: tuple

Insurance expense [$]

property internal_rate_of_return: float

Internal rate of return (after-tax) [%]

property levelized_cost_of_energy_nominal: float

Levelized cost (nominal) [cents/kWh]

property levelized_cost_of_energy_real: float

Levelized cost (real) [cents/kWh]

property logger
property net_present_value: float

After-tax cumulative NPV [$]

property om_capacity

Capacity-based O&M amount [$/kWcap]

property om_capacity_expense

O&M capacity-based expense [$]

property om_fixed

Fixed O&M annual amount [$/year]

property om_fixed_expense

O&M fixed expense [$]

property om_production

Production-based O&M amount [$/Mwh]

property om_total_expense

Total operating expenses [$]

property om_variable

Production-based O&M amount [$/kWh] For battery: production-based System Costs amount [$/kWh-discharged]

Type:

For non-battery technologies

property om_variable_expense

O&M production-based expense [$]

plot(figure=None, axes=None, color='b', site_border_color='k', site_alpha=0.95, linewidth=4.0)
property ppa_price: tuple

PPA price [$/kWh]

set_overnight_capital_cost(energy_capital_cost, power_capital_cost)

Set overnight capital costs [$/kW].

This method calculates and sets the overnight capital cost based on the given energy and power capital costs.

Parameters:
  • energy_capital_cost (float) – The capital cost per unit of energy capacity [$/kWh].

  • power_capital_cost (float) – The capital cost per unit of power capacity [$/kW].

Returns:

This method does not return any value. The calculated overnight capital cost is stored internally.

Return type:

None

Note

The overnight capital cost is calculated using the formula: overnight_capital_cost = (energy_capital_cost * hours) + power_capital_cost where hours is the ratio of energy capacity to power capacity.

Example

>>> set_overnight_capital_cost(1500, 500)
simulate(interconnect_kw: float, project_life: int = 25, lifetime_sim=False)

Run the system and financial model

Parameters:
  • project_lifeint, Number of year in the analysis period (execepted project lifetime) [years]

  • lifetime_simbool, For simulation modules which support simulating each year of the project_life, whether or not to do so; otherwise the first year data is repeated

property system_nameplate_mw: float

System nameplate [MW]

property tax_incentives: list

The sum of Federal and State PTC and ITC tax incentives [$]

property total_installed_cost: float

Installed cost [$]

property total_revenue: list

Total revenue [$]

value(var_name: str, var_value=None)

Gets or Sets a variable value within either the system or financial PySAM models. Method looks in system model first. If unsuccessful, then it looks in the financial model.

Note

If system and financial models contain a variable with the same name, only the system model variable will be set.

value(var_name) Gets variable value

value(var_name, var_value) Sets variable value

Parameters:
  • var_name – PySAM variable name

  • var_value – (optional) PySAM variable value

Returns:

Variable value (when getter)

calculate_total_installed_cost(energy_capital_cost: float, power_capital_cost: float) float
simulate_financials(interconnect_kw: float, project_life: int, cap_cred_avail_storage: bool = True)

Sets-up and simulates financial model for the battery

Parameters:
  • interconnect_kw – Interconnection limit [kW]

  • project_life – Analysis period [years]

  • cap_cred_avail_storage – Base capacity credit on available storage (True), otherwise use only dispatched generation (False)

calc_gen_max_feasible_kwh(interconnect_kw, use_avail_storage: bool = True) List[float]

Calculates the maximum feasible capacity (generation profile) that could have occurred.

Parameters:
  • interconnect_kw – Interconnection limit [kW]

  • use_avail_storage – Base capacity credit on available storage (True), otherwise use only dispatched generation (False)

Returns:

Maximum feasible capacity [kWh]

property generation_profile: Sequence

System power generated [kW]

property replacement_costs: Sequence

Battery replacement cost [$]

property annual_energy_kwh: float

Annual energy [kWh]

class hopp.simulation.technologies.battery.battery.BatteryConfig(system_capacity_kwh: float, system_capacity_kw: float, chemistry: str = 'LFPGraphite', tracking: bool = True, minimum_SOC: float = 10, maximum_SOC: float = 90, initial_SOC: float = 10, fin_model: dict | Singleowner | CustomFinancialModel | None = None)

Bases: BaseClass

Configuration class for Battery.

Parameters:
  • tracking – default True -> Battery

  • system_capacity_kwh – Battery energy capacity [kWh]

  • system_capacity_kw – Battery rated power capacity [kW]

  • chemistry

    Battery chemistry option

    • ”LFPGraphite” (default)

    • ”LMOLTO”

    • ”LeadAcid”

    • ”NMCGraphite”

  • minimum_SOC – Minimum state of charge [%]

  • maximum_SOC – Maximum state of charge [%]

  • initial_SOC – Initial state of charge [%]

  • fin_model – Financial model. Can be any of the following: - a dict representing a CustomFinancialModel - an object representing a CustomFinancialModel or a Singleowner.Singleowner instance

system_capacity_kwh: float
system_capacity_kw: float
chemistry: str
tracking: bool
minimum_SOC: float
maximum_SOC: float
initial_SOC: float
fin_model: dict | Singleowner | CustomFinancialModel | None
__init__(system_capacity_kwh: float, system_capacity_kw: float, chemistry: str = 'LFPGraphite', tracking: bool = True, minimum_SOC: float = 10, maximum_SOC: float = 90, initial_SOC: float = 10, fin_model: dict | Singleowner | CustomFinancialModel | None = None) None

Method generated by attrs for class BatteryConfig.

_get_model_dict() dict

Convenience method that wraps the attrs.asdict method. Returns the object’s parameters as a dictionary.

Returns:

The provided or default, if no input provided, model settings as a dictionary.

Return type:

dict

as_dict() dict

Creates a JSON and YAML friendly dictionary that can be save for future reloading. This dictionary will contain only Python types that can later be converted to their proper Turbine formats.

Returns:

All key, vaue pais required for class recreation.

Return type:

dict

classmethod from_dict(data: dict)

Maps a data dictionary to an attr-defined class.

TODO: Add an error to ensure that either none or all the parameters are passed in

Parameters:

data – dict The data dictionary to be mapped.

Returns:

cls

The attr-defined class.

classmethod get_model_defaults() Dict[str, Any]

Produces a dictionary of the keyword arguments and their defaults.

Returns:

Dictionary of keyword argument: default.

Return type:

Dict[str, Any]

property logger
class hopp.simulation.technologies.battery.battery.BatteryOutputs(n_timesteps, n_periods_per_day)

Bases: object

I: Sequence
P: Sequence
Q: Sequence
SOC: Sequence
T_batt: Sequence
gen: Sequence
n_cycles: Sequence
dispatch_I: List[float]
dispatch_P: List[float]
dispatch_SOC: List[float]
__init__(n_timesteps, n_periods_per_day)

Class for storing stateful battery and dispatch outputs.

dispatch_lifecycles_per_day: List[int | None]
The following outputs are simulated from the BatteryStateful model, an entry per timestep:

I: current [A] P: power [kW] Q: capacity [Ah] SOC: state-of-charge [%] T_batt: temperature [C] gen: same as P n_cycles: number of rainflow cycles elapsed since start of simulation [1]

The next outputs, an entry per timestep, are from the HOPP dispatch model, which are then passed to the simulation:

dispatch_I: current [A], only applicable to battery dispatch models with current modeled dispatch_P: power [mW] dispatch_SOC: state-of-charge [%]

This output has a different length, one entry per day:

dispatch_lifecycles_per_day: number of cycles per day

export()