costs

This module consists of code that computes a user’s electricity bill given an electricity consumption profile.

Functions to calculate costs from electricity consumption data.

eeco.costs.add_to_charge_array(charge_dict, key_str, charge_array)[source]

Add to an existing charge array, or an array of all zeros if this charge array does not exist.

This functionality is useful for noncontiguous charges that should be saved under the same key. For example, partial peak hours from 3-5 and 8-10 PM that are billing as a single demand period.

Modifies charge_dict in-place, so nothing is returned.

Parameters:
  • charge_dict (dict of numpy.ndarray) – Dictionary of arrays with keys of the form utility`_`charge_type`_`name`_`start_date`_`end_date`_`charge_limit and values being the $ per kW (electric demand), kWh (electric energy/export), cubic meter / hour (gas demand), cubic meter (gas energy), or $ / month (customer)

  • key_str (str) – The key for the charge array we’d like to modify of the form utility`_`charge_type`_`name`_`start_date`_`end_date`_`charge_limit

  • charge_array (numpy.ndarray) – Value of the charge to add in $ per kW (electric demand), kWh (electric energy/export), cubic meter / hour (gas demand), cubic meter (gas energy), or $ / month (customer)

eeco.costs.build_pyomo_costing(charge_dict, consumption_data_dict, model, electric_consumption_units=Unit("kilowatt"), gas_consumption_units=Unit("meter ** 3 / hour"), resolution='15m', prev_demand_dict=None, prev_consumption_dict=None, consumption_estimate=0, desired_utility=None, desired_charge_type=None, demand_scale_factor=1, additional_objective_terms=None, decomposition_type=None, varstr_alias_func=<function default_varstr_alias_func>)[source]

Wrapper for calculate_cost to build the cost components into a Pyomo model. An objective function will be created in model.objective.

Parameters:
  • charge_dict (dict) – dictionary of arrays with keys of the form utility`_`charge_type`_`name`_`start_date`_`end_date`_`charge_limit and values being the $ per kW (electric demand), kWh (electric energy/export), cubic meter / hour (gas demand), cubic meter (gas energy), or $ / month (customer)

  • consumption_data_dict (dict) – Baseline electrical and gas usage data as an optimization variable object with keys “electric” and “gas”. Values of the dictionary must be of type numpy.ndarray, cvxpy.Expression, or pyomo.environ.Var

  • model (pyomo.Model) – The model object associated with the problem.

  • electric_consumption_units (pint.Unit) – Units for the electricity consumption data. Default is kW

  • gas_consumption_units (pint.Unit) – Units for the natural gas consumption data. Default is cubic meters / hour

  • resolution (str) – String of the form [int][str] giving the temporal resolution on which charges are assessed, the str portion corresponds to numpy.timedelta64 types for example ‘15m’ specifying demand charges that are applied to 15-minute intervals of electricity consumption

  • prev_demand_dict (dict) – Nested dictionary previous maximmum demand charges with an entry of the form {“cost” : float, “demand” : float} for each charge. Default is None, which results in an a prev_demand and prev_demand_cost of zero for all charges.

  • prev_consumption_dict (dict) – Dictionary of previous total energy consumption with a key for each charge to be used when starting the cost calculation partway into a billing period (e.g., while using a moving horizon that is shorter than a month). Default is None, resulting in an a prev_consumption of zero for all charges.

  • consumption_estimate (float) – Estimate of the total monthly demand or energy consumption from baseline data. Only used when consumption_data is cvxpy.Expression or pyomo.environ.Var for convex relaxation of tiered charges, while numpy.ndarray consumption_data will use actual consumption and ignore the estimate.

  • desired_charge_type (list or str) – Name of desired charge type for itemized costs. Either ‘customer’, ‘energy’, ‘demand’, ‘export’, or a list of charge types. Default is None, meaning that all costs will be summed together.

  • desired_utility (list or str) – Name of desired utility for itemized costs. Either ‘electric’, ‘gas’, or a list of utilities (e.g., [‘electric’, ‘gas’]). Default is None, meaning that all costs will be summed together.

  • demand_scale_factor (float) – Optional factor for scaling demand charges relative to energy charges when the optimization/simulation period is not a full billing cycle. Applied to monthly charges where end_date - start_date > 1 day. Default is 1

  • additional_objective_terms (pyomo.Expression, list) – Additional terms to be added to the objective function. Can be a single pyomo Expression or a list of pyomo Expressions. Only used in the case of Pyomo, so None by default.

  • decomposition_type (str or None) – Type of decomposition to use for consumption data. - “absolute_value”: Uses max(x, 0) constraints. Creates nonlinear problem

    for Pyomo due to abs() constraint.

    • “binary_big_M”: Uses binary indicator with Big-M constraints. Creates a MILP (mixed-integer linear program) for Pyomo or CVXPY.

    • None (default): No decomposition, treats all consumption as imports

  • varstr_alias_func (function) – Function to generate variable name for pyomo, should take in a 6 inputs and generate a string output. The function will receive following six inputs:

    • utility: str

    • charge_type: str

    • name: str

    • start_date: str

    • end_date: str

    • charge_limit: str

    Examples of functions:

    f_no_dates=lambda utility, charge_type, name, start_date, end_date, charge_limit: f”{utility}_{charge_type}_{name}_{charge_limit}”

Raises:

ValueError – When invalid utility, charge_type, or assessed is provided in charge_arrays

Returns:

The model object associated with the problem with costing components added.

Return type:

pyomo.Model

eeco.costs.calculate_cost(charge_dict, consumption_data_dict, electric_consumption_units=Unit("kilowatt"), gas_consumption_units=Unit("meter ** 3 / hour"), resolution='15m', prev_demand_dict=None, prev_consumption_dict=None, consumption_estimate=0, desired_utility=None, desired_charge_type=None, demand_scale_factor=1, fixed_scale_factor=1, model=None, decomposition_type=None, big_m=1000000.0, varstr_alias_func=<function default_varstr_alias_func>)[source]

Calculates the cost of given charges (demand or energy) for the given billing rate structure, utility, and consumption information as a cvxpy expression or numpy array

Parameters:
  • charge_dict (dict) – dictionary of arrays with keys of the form utility`_`charge_type`_`name`_`start_date`_`end_date`_`charge_limit and values being the $ per kW (electric demand), kWh (electric energy/export), cubic meter / hour (gas demand), cubic meter (gas energy), or $ / month (customer)

  • consumption_data_dict (dict) – Baseline electrical and gas usage data as an optimization variable object with keys “electric” and “gas”. Supports two formats:

    Default format:

    Values are cumulative consumption data Example: {“electric”: np.array([]), “gas”: np.array([])}

    Extended format for imports/exports:

    Values are dictionaries with decomposed “imports” and “exports” keys Example: {“electric”: {“imports”: np.array([]), “exports”: np.array([])}}

    Values must be of type numpy.ndarray, cvxpy.Expression, or pyomo.environ.Var.

  • electric_consumption_units (pint.Unit) – Units for the electricity consumption data. Default is kW

  • gas_consumption_units (pint.Unit) – Units for the natural gas consumption data. Default is cubic meters / hour

  • resolution (str) – String of the form [int][str] giving the temporal resolution on which charges are assessed, the str portion corresponds to numpy.timedelta64 types for example ‘15m’ specifying demand charges that are applied to 15-minute intervals of electricity consumption

  • prev_demand_dict (dict) – Nested dictionary previous maximmum demand charges with an entry of the form {“cost” : float, “demand” : float} for each charge. Default is None, which results in an a prev_demand and prev_demand_cost of zero for all charges.

  • prev_consumption_dict (dict) – Dictionary of previous total energy consumption with a key for each charge to be used when starting the cost calculation partway into a billing period (e.g., while using a moving horizon that is shorter than a month). Default is None, resulting in an a prev_consumption of zero for all charges.

  • consumption_estimate (float, array, dict) – Estimate of the total monthly demand or energy consumption from baseline data. Only used when consumption_data is cvxpy.Expression or pyomo.environ.Var for convex relaxation of tiered charges, while numpy.ndarray consumption_data will use actual consumption and ignore the estimate. If consumption estimate is a float, int, it is assumed to carry units of kWh, therms OR m3. If consumption estimate is array-like it is assumed to carry units of kW, therms/hr OR m3/hr. If consumption estimate is a dict, it should have keys matching the charge dict.

  • desired_charge_type (list or str) – Name of desired charge type for itemized costs. Either ‘customer’, ‘energy’, ‘demand’, ‘export’, or a list of charge types. Default is None, meaning that all costs will be summed together.

  • desired_utility (list or str) – Name of desired utility for itemized costs. Either ‘electric’, ‘gas’, or a list of utilities (e.g., [‘electric’, ‘gas’]). Default is None, meaning that all costs will be summed together.

  • demand_scale_factor (float) – Optional factor for scaling demand charges relative to energy charges when the optimization/simulation period is not a full billing cycle. Applied to monthly charges where end_date - start_date > 1 day. Default is 1

  • fixed_scale_factor (float) – Optional factor for scaling fixed (customer) charges relative to energy charges when the optimization/simulation period is not a full billing cycle. Applied to the whole customer charge, which is otherwise billed in full regardless of horizon length. Default is 1

  • model (pyomo.Model) – The model object associated with the problem. Only used in the case of Pyomo, so None by default.

  • decomposition_type (str or None) – Type of decomposition to use for consumption data. - “absolute_value”: Uses max(x, 0) constraints. Creates nonlinear problem

    for Pyomo due to abs() constraint.

    • “binary_big_M”: Uses binary indicator with Big-M constraints. Creates a MILP (mixed-integer linear program) for Pyomo or CVXPY.

    • None (default): No decomposition, treats all consumption as imports

  • varstr_alias_func (function) – Function to generate variable name for pyomo, should take in a 6 inputs and generate a string output. The function will receive following six inputs:

    • utility: str

    • charge_type: str

    • name: str

    • start_date: str

    • end_date: str

    • charge_limit: str

    Examples of functions:

    f_no_dates=lambda utility, charge_type, name, start_date, end_date, charge_limit: f”{utility}_{charge_type}_{name}_{charge_limit}”

Raises:

ValueError – When invalid utility, charge_type, or assessed is provided in charge_arrays

Returns:

  • First entry: float, cvxpy Expression, or pyomo Var representing energy charge costs in USD for the given charge_array and consumption_data

  • Second entry: pyomo ConcreteModel (pyomo path), list of cvxpy constraints from decomposition (cvxpy + decomposition_type path), or None otherwise

Return type:

tuple

eeco.costs.calculate_demand_cost(charge_array, consumption_data, limit=0, next_limit=inf, prev_demand=0, prev_demand_cost=0, consumption_estimate=0, scale_factor=1, model=None, varstr='')[source]

Calculates the cost of given demand charges for the given billing rate structure, utility, and consumption information

Parameters:
  • charge_array (array) – Array of charge cost (in $/kW)

  • consumption_data (numpy.ndarray, cvxpy.Expression, or pyomo.environ.Var) – Baseline electrical or gas usage data as an optimization variable object

  • limit (float) – The total consumption, or limit, that this charge came into effect. Default is 0

  • next_limit (float) – The total consumption, or limit, that the next charge comes into effect. Default is float(‘inf’) indicating that there is no higher tier

  • prev_demand (float) – The previous maximum demand for this charge during the same billing period. Only used for optimizing on a horizon shorter than the billing period, so the default is 0

  • prev_demand_cost (float) – The previous cost for this demand charge during the same billing period. Only used for optimizing on a horizon shorter than the billing period, so the default is 0

  • consumption_estimate (float, array) – Estimate of the total consumption from baseline data in kW, therms/hr OR m3/hr. Only used when consumption_data is cvxpy.Expression or pyomo.environ.Var for convex relaxation of tiered charges, while numpy.ndarray consumption_data will use actual consumption and ignore the estimate.

  • scale_factor (float) – Optional factor for scaling demand charges relative to energy charges when the optimization/simulation period is not a full billing cycle. Applied to monthly charges where end_date - start_date > 1 day. Default is 1.

  • model (pyomo.Model) – The model object associated with the problem. Only used in the case of Pyomo, so None by default.

  • varstr (str) – Name of the variable to be created if using a Pyomo model

Returns:

tuple with the first entry being a float, cvxpy Expression, or pyomo Var representing demand charge costs in USD for the given charge_array and consumption_data and the second entry being the pyomo model object (or None)

Return type:

(cvxpy.Expression, pyomo.environ.Var, or float), pyomo.Model

eeco.costs.calculate_energy_cost(charge_array, consumption_data, n_per_hour, limit=0, next_limit=inf, prev_consumption=0, consumption_estimate=0, model=None, varstr='')[source]

Calculates the cost of given energy charges for the given billing rate structure, utility, and consumption information.

Parameters:
  • charge_array (numpy.ndarray) – Array of the charges in $/kWh for electric and $/cubic meter for gas

  • consumption_data (numpy.ndarray cvxpy.Expression, or pyomo.environ.Var) – Baseline electrical or gas usage data as an optimization variable object

  • n_per_hour (int) – Divisor for the indexed consumption data elements, based on the timeseries resolution

  • limit (float) – The total consumption, or limit, that this charge came into effect. Default is 0

  • next_limit (float) – The total consumption, or limit, that the next charge comes into effect. Default is float(‘inf’) indicating that there is no higher tier

  • prev_consumption (float) – Consumption from within this billing period but outside the horizon window (e.g., previously in the month). Necessary for moving-horizon optimization. Default is 0

  • consumption_estimate (float, array) – Estimate of the total monthly energy consumption from baseline data in kWh, therms OR cubic meters. Only used when consumption_data is cvxpy.Expression or pyomo.environ.Var for convex relaxation of tiered charges, while numpy.ndarray consumption_data will use actual consumption and ignore the estimate.

  • model (pyomo.Model) – The model object associated with the problem. Only used in the case of Pyomo, so None by default.

  • varstr (str) – Name of the variable to be created if using a Pyomo model

Raises:

ValueError – When invalid utility, charge_type, or assessed is provided in charge_arrays

Returns:

tuple with the first entry being a float, cvxpy Expression, or pyomo Var representing energy charge costs in USD for the given charge_array and consumption_data and the second entry being the pyomo model object (or None)

Return type:

(cvxpy.Expression, pyomo.environ.Var, or float), pyomo.Model

eeco.costs.calculate_export_revenue(charge_array, consumption_data, n_per_hour, model=None, varstr='')[source]

Calculates the export revenues for the given billing rate structure, utility, and consumption information.

Only flat rates for exports are supported (in $ / kWh). Returns positive revenue values that should be subtracted from total cost.

Parameters:
  • charge_array (numpy.ndarray) – array with price per kWh sold back to the grid

  • consumption_data (numpy.ndarray, cvxpy.Expression, or pyomo.environ.Var) – Magnitude of exported electrical or gas usage data as an optimization variable object. Should be positive values.

  • n_per_hour (int) – Divisor for the indexed consumption data elements, based on the timeseries resolution

  • model (pyomo.Model) – The model object associated with the problem. Only used in the case of Pyomo, so None by default.

  • varstr (str) – Name of the variable to be created if using a Pyomo model

Raises:

ValueError – When invalid utility, charge_type, or assessed is provided in charge_arrays

Returns:

tuple with the first entry being a float, cvxpy Expression, or pyomo Var representing export revenues in USD for the given charge_array and export_data and the second entry being the pyomo model object (or None)

Return type:

(cvxpy.Expression, pyomo.environ.Var, or float), pyomo.Model

eeco.costs.calculate_itemized_cost(charge_dict, consumption_data_dict, electric_consumption_units=Unit("kilowatt"), gas_consumption_units=Unit("meter ** 3 / hour"), resolution='15m', prev_demand_dict=None, prev_consumption_dict=None, consumption_estimate=0, desired_utility=None, demand_scale_factor=1, fixed_scale_factor=1, model=None, decomposition_type=None, big_m=1000000.0, by_charge_key=False, varstr_alias_func=<function default_varstr_alias_func>)[source]

Calculates itemized costs as a nested dictionary

Parameters:
  • charge_dict (dict) – dictionary of arrays with keys of the form utility`_`charge_type`_`name`_`start_date`_`end_date`_`charge_limit and values being the $ per kW (electric demand), kWh (electric energy/export), cubic meter / hour (gas demand), cubic meter (gas energy), or $ / month (customer)

  • consumption_data_dict (dict) – Baseline electrical and gas usage data as an optimization variable object with keys “electric” and “gas”. Values of the dictionary must be of type numpy.ndarray, cvxpy.Expression, or pyomo.environ.Var Positive values represent energy imports (consumption from the grid) Negative values represent energy exports (generation sent to the grid)

  • electric_consumption_units (pint.Unit) – Units for the electricity consumption data. Default is kW

  • gas_consumption_units (pint.Unit) – Units for the natural gas consumption data. Default is cubic meters / hour

  • resolution (str) – String of the form [int][str] giving the temporal resolution on which charges are assessed, the str portion corresponds to numpy.timedelta64 types for example ‘15m’ specifying demand charges that are applied to 15-minute intervals of electricity consumption

  • prev_demand_dict (dict) – Nested dictionary previous maximmum demand charges with an entry of the form {“cost” : float, “demand” : float} for each charge. Default is None, which results in an a prev_demand and prev_demand_cost of zero for all charges.

  • prev_consumption_dict (dict) – Dictionary of previous total energy consumption with a key for each charge to be used when starting the cost calculation partway into a billing period (e.g., while using a moving horizon that is shorter than a month). Default is None, resulting in an a prev_consumption of zero for all charges.

  • consumption_estimate (float) – Estimate of the total monthly demand or energy consumption from baseline data. Only used when consumption_data is cvxpy.Expression for convex relaxation of tiered charges, while numpy.ndarray consumption_data will use actual consumption and ignore the estimate.

  • demand_scale_factor (float) – Optional factor for scaling demand charges relative to energy charges when the optimization/simulation period is not a full billing cycle. Applied to monthly charges where end_date - start_date > 1 day. Default is 1

  • fixed_scale_factor (float) – Optional factor for scaling fixed (customer) charges relative to energy charges when the optimization/simulation period is not a full billing cycle. Applied to the whole customer charge, which is otherwise billed in full regardless of horizon length. Default is 1

  • model (pyomo.Model) – The model object associated with the problem. Only used in the case of Pyomo, so None by default.

  • decomposition_type (str or None) – Type of decomposition to use for consumption data. - “absolute_value”: Linear problem using absolute value - “binary_big_M”: Uses binary indicator with Big-M constraints.

    Creates a MILP (mixed-integer linear program) for Pyomo or CVXPY.

    • None (default): No decomposition, treats all consumption as imports

  • by_charge_key (bool) – Whether to further itemize the results by charge key. Default is False.

Returns:

  • dict –

    {

    “electric”: {

    “customer”: float or dict (key -> cost) if by_charge_key

    ”energy”: float or dict (key -> cost) if by_charge_key

    ”demand”: float or dict (key -> cost) if by_charge_key

    ”export”: float or dict (key -> cost) if by_charge_key

    ”total”: float or dict (key -> cost) if by_charge_key

    }

    ”gas”: {

    “customer”: float or dict (key -> cost) if by_charge_key

    ”energy”: float or dict (key -> cost) if by_charge_key

    ”demand”: float or dict (key -> cost) if by_charge_key

    ”export”: float or dict (key -> cost) if by_charge_key

    ”total”: float or dict (key -> cost) if by_charge_key

    }

    ”total”: float or dict (key -> cost) if by_charge_key

    }

  • model_objects (pyomo ConcreteModel, list of cvxpy constraints, or None) – Same as the second return value of calculate_cost.

eeco.costs.create_charge_array(charge, datetime, effective_start_date, effective_end_date, utility='electric')[source]

Creates a single charge array based on the given parameters.

Parameters:
  • charge (pandas.DataFrame) – data for the charge including columns month_start, month_end, weekday_start, weekday_end, hour_start, hour_end, and charge

  • datetime (pandas.DataFrame, pandas.Series, or numpy.ndarray) – If a pandas Series, it must be of type datetime. If a DataFrame it must have a column “DateTime” and row for each timestep

  • effective_start_date (datetime.datetime) – date on which this charge becomes effective

  • effective_end_date (datetime.datetime) – date at which this charge is no longer in effect (i.e., this day is excluded)

Raises:

TypeError – When datetime is not pandas.DataFrame, pandas.Series, or numpy.ndarray

Returns:

timeseries of the cost of the charge with irrelevant timesteps zeroed out

Return type:

panda.Series

eeco.costs.default_varstr_alias_func(utility, charge_type, name, start_date, end_date, charge_limit)[source]

Default function for creating the variable name strings for each charge in the tariff sheet. Can be overwritten in the function call to calculate_cost to customize variable names.

Parameters:
  • utility (str) – Name of the utility (‘electric’ or ‘gas’)

  • charge_type (str) – Name of the charge_type (‘demand’, ‘energy’, or ‘customer’)

  • name (str) – The name of the period for this charge (e.g., ‘all-day’ or ‘on-peak’)

  • start_date (str) – The inclusive start date for this charge

  • end_date (str) – The exclusive end date for this charge

  • charge_limit (str) – The consumption limit for this tier of charges converted to a string

Returns:

Variable name of the form utility`_`charge_type`_`name`_`start_date`_`end_date`_`charge_limit

Return type:

str

eeco.costs.detect_charge_periods(rate_data, charge_type, month, weekday, resolution_minutes=30)[source]

Categorize charges into charge periods (peak, half-peak, off-peak, super-off-peak) for a particular month, weekday and charge_type.

Parameters:
  • rate_data (pandas.DataFrame) – Tariff data with required columns

  • charge_type (str) – Type of charge (ENERGY or DEMAND)

  • month (int) – Month (1-12)

  • weekday (int) – Weekday (0-6)

  • resolution_minutes (int) – Time resolution in minutes for checking full day coverage. Default 30

Returns:

  • period_categories: dict with period classifications for each row index: - PEAK: highest charge periods - HALF_PEAK: periods adjacent to peak - OFF_PEAK: average charge periods - SUPER_OFF_PEAK: below average charge periods

  • base_charge: the most frequent charge value

  • has_overlapping: the most frequent charge value

Return type:

tuple with

eeco.costs.get_billing_period_scale_factor(start_dt, end_dt)[source]

Fraction of a monthly billing period covered by the analysis horizon.

The horizon’s overlap with each calendar month it touches is summed, so horizons spanning several months are handled correctly.

Parameters:
  • start_dt (datetime-like (see get_timesteps())) – first timestep to be included in the cost analysis

  • end_dt (datetime-like (see get_timesteps())) – end of the cost analysis, exclusive: the horizon runs up to but does not include end_dt

Returns:

the horizon’s length as a fraction of a monthly billing period

Return type:

float

eeco.costs.get_charge_array_duration(key)[source]

Parse a charge array key to determine the duration of the charge period in days.

Parameters:

key (str) – Charge key of form utility_charge_type_name_start_date_end_date_charge_limit where start_date and end_date are in YYYYMMDD or YYYY-MM-DD format

Returns:

Duration of the charge period in days

Return type:

int

Raises:

ValueError – If the key format is invalid or dates cannot be parsed

eeco.costs.get_charge_array_length(charge_array)[source]

Number of timesteps in a charge array for np and cvxpy objects.

Parameters:

charge_array (numpy.ndarray or cvxpy.Expression) – array of charges per timestep

Returns:

number of timesteps in charge_array

Return type:

int

eeco.costs.get_charge_df(start_dt, end_dt, rate_data, resolution='15m', keep_fixed_charges=True, scale_fixed_charges=True, scale_demand_charges=False)[source]

Creates a dictionary where the values are charge arrays and keys are of the form {utility}_{type}_{name}_{start_date}_{end_date}_{limit}

Parameters:
  • start_dt (datetime-like (see get_timesteps())) – first timestep to be included in the cost analysis

  • end_dt (datetime-like (see get_timesteps())) – end of the cost analysis, exclusive: the horizon runs up to but does not include end_dt

  • rate_data (pandas.DataFrame) – tariff data with required columns utility, type, basic_charge_limit, name, month_start, month_end, weekday_start, weekday_end, hour_start, hour_end, and charge and optional columns assessed (default “monthly”), effective_start_date, and effective_end_date

  • resolution (str) – granularity of each timestep in string form with default value of “15m”

  • keep_fixed_charges (bool) – Whether to discard fixed (i.e., customer) charges or keep them. Default is True, which returns fixed (and all other) charges.

  • scale_fixed_charges (bool) – If True, fixed charges will be divided amongst all time steps and scaled by the horizon’s fraction of a billing period. If False, they will not be scaled but included in the first timestep only. Default is True.

  • scale_demand_charges (bool)

Returns:

DataFrame of charge arrays

Return type:

pandas.DataFrame

eeco.costs.get_charge_dict(start_dt, end_dt, rate_data, resolution='15m')[source]

Creates a dictionary where the values are charge arrays and keys are of the form {utility}_{type}_{name}_{start_date}_{end_date}_{limit}

Parameters:
  • start_dt (datetime-like (see get_timesteps())) – first timestep to be included in the cost analysis

  • end_dt (datetime-like (see get_timesteps())) – end of the cost analysis, exclusive: the horizon runs up to but does not include end_dt

  • rate_data (pandas.DataFrame) – tariff data with required columns utility, type, basic_charge_limit, name, month_start, month_end, weekday_start, weekday_end, hour_start, hour_end, and charge and optional columns assessed (default “monthly”), effective_start_date, and effective_end_date

  • resolution (str) – granularity of each timestep in string form with default value of “15m”

Returns:

dictionary of charge arrays

Return type:

dict

eeco.costs.get_charge_name(charge, index=None)[source]

Get a unique row name for each row of charge df.

Parameters:
  • charge (dict or pandas.Series) – The charge row data containing NAME and PERIOD fields

  • index (int, optional) – Index to use if name is empty or None

Returns:

A unique name with underscores converted to dashes

Return type:

str

eeco.costs.get_charge_records(model)[source]

Handles on the Pyomo components built for each charge.

Keyed the same way as prev_demand_dict by the original charge_dict key, so a caller never has to rebuild a variable name that varstr_alias_func may have changed.

Parameters:

model (pyomo.environ.Model) – A model that calculate_cost has already built costs on

Raises:

ValueError – When no charges have been recorded on model

Returns:

Keyed by charge_dict key. Each entry holds the varstr and charge_type strings alongside the limit, max, and max_pos components named in CHARGE_COMPONENT_SUFFIXES, which are None for charges that built none

Return type:

dict

eeco.costs.get_charge_window(charge_array, model=None)[source]

Timesteps at which a charge is actually assessed and nonzero.

Parameters:
  • charge_array (numpy.ndarray) – Array of charges in $/kWh, $/kW, $/therm, or $/m3

  • model (pyomo.environ.Model) – The model object associated with the problem. Default is None, in which case positions into charge_array are returned rather than index values.

Returns:

Positions into charge_array where the charge is nonzero, or the corresponding model._var_index values when a Pyomo model is given

Return type:

list

eeco.costs.get_conversion_factors(electric_consumption_units, gas_consumption_units)[source]

Calculate conversion factors for electric and gas utilities.

Parameters:
  • electric_consumption_units (pint.Unit) – Units for the electricity consumption data

  • gas_consumption_units (pint.Unit) – Units for the gas consumption data

Returns:

Dictionary with conversion factors for each utility type

Return type:

dict

eeco.costs.get_converted_consumption_data(consumption_data_dict, conversion_factors, decomposition_type, model=None, big_m=1000000.0)[source]

Ensure consumption_data_dict has imports/exports structure with proper unit conversion.

Parameters:
  • consumption_data_dict (dict) – Dictionary with utility keys and consumption data values

  • conversion_factors (dict) – Dictionary with conversion factors for each utility type

  • decomposition_type (str or None) – Type of decomposition to apply (e.g., “absolute_value”)

  • model (pyomo.Model, optional) – Pyomo model object for optimization variables

Returns:

  • consumption_data_dict with imports/exports structure

  • pyomo ConcreteModel, list of cvxpy constraints, or None

Return type:

tuple

eeco.costs.get_next_limit(key_substr, current_limit, keys)[source]

Finds the next charge limit for the charge represented by key

Parameters:
  • key_substr (str) – The beginnging of the key for which we want to get the next limit (i.e., {utility}_{type}_{name}_{start_date}_{end_date})

  • current_limit (int) – The limit for the current tier

  • keys (list of str) – List of all the keys in the charge dictionary

Returns:

limit in the tier after key, which is inf if there is no higher tier

Return type:

float

eeco.costs.get_prev_demand_dict(charge_dict, usage_data, start_dt, billing_period_starts, prev_dict=None)[source]

Compute a new or updated previous max demand charge dict for use in costing.

For each charge in charge_dict, resets the tracked maximum to zero at the start of the relevant timeframe. Then accumulates the running maximum.

Parameters:
  • charge_dict (dict) – Maps charge key strings to charge arrays (numpy arrays or cp.Expression).

  • usage_data (numpy.ndarray) – Array of consumption values for the current timestep window.

  • start_dt (datetime-like (see get_timesteps())) – Start datetime of the current optimization window.

  • billing_period_starts (list) – List of datetimes marking the start of each billing period.

  • prev_dict (dict, optional) – Existing previous-max dict to update. Defaults to empty dict.

Returns:

Mapping of charge key to {“demand”: running peak demand, “cost”: running max of usage * charge}

Return type:

dict

eeco.costs.get_timesteps(start_dt, end_dt, resolution='15m')[source]

Number of timesteps in the horizon and the corresponding datetime column.

Parameters:
  • start_dt (datetime-like) – first timestep to be included in the cost analysis. Accepts datetime.datetime, numpy.datetime64, and ISO-8601 strings

  • end_dt (datetime-like) – end timestep of the cost analysis, exclusive. The last timestep returned is one resolution before end_dt. Accepts datetime.datetime, numpy.datetime64, and ISO-8601 strings

  • resolution (str) – granularity of each timestep in string form with default value of “15m”

Returns:

the number of timesteps and a single-column DataFrame of their datetimes

Return type:

tuple of (int, pandas.DataFrame)

Warns:

UserWarning – when the horizon is not a whole multiple of resolution, since the trailing partial timestep is dropped from the returned timeseries but still counted when prorating fixed charges

eeco.costs.parametrize_charge_dict(start_dt, end_dt, rate_data, variants=None)[source]

Takes in an existing charge_dict and varies it parametrically to create alternative rate structures. Calls parametrize_rate_data to parametrize the billing csv file, then calls it on the dates specified.

Parameters:
  • start_dt (datetime-like (see get_timesteps())) – first timestep to be included in the cost analysis

  • end_dt (datetime-like (see get_timesteps())) – end of the cost analysis, exclusive: the horizon runs up to but does not include end_dt

  • rate_data (pandas.DataFrame) – tariff data with required columns

  • variants (list[dict]) – List of dictionaries containing variation parameters with keys: - percent_change_dict: dict for charge scaling (see parametrize_rate_data) - shift_peak_hours_before: float to shift peak start, in hours - shift_peak_hours_after (float) : shift peak end, in hours - variant_name (str, optional) : variant name

Returns:

dictionary of charge_dicts with different variations

Return type:

dict

Raises:

UserWarning – If global scaling overrides individual ratios in any variant (inherited from parametrize_rate_data)

eeco.costs.parametrize_rate_data(rate_data, percent_change_dict={}, shift_peak_hours_before=0, shift_peak_hours_after=0, variant_name=None)[source]

Parametrize rate data by charge periods (peak, half-peak, off-peak, super-off-peak) or exact charge keys. Applies scaling and window shifting to create alternative rate structures.

Parameters:
  • rate_data (pandas.DataFrame) – Tariff data with required columns

  • percent_change_dict (dict, optional) – Dictionary for charge scaling. Can be one of three formats:

    Format 1 - Nested dictionary with structure for charge scaling:

    {

    ‘demand’: {

    ‘peak’: float, ‘half_peak’: float, ‘off_peak’: float, ‘super_off_peak’: float

    },

    ‘energy’: {

    ‘peak’: float, ‘half_peak’: float, ‘off_peak’: float, ‘super_off_peak’: float

    }

    }

    Format 2 - Dictionary with exact charge key prefixes based on csv:

    {

    ‘electric_demand_peak-summer’: float, ‘electric_energy_0’: float, ‘electric_demand_all-day’: float, …

    }

    Format 3 - Global scaling for all charges of each type:

    {

    ‘demand’: float, # scales all demand charges ‘energy’: float, # scales all energy charges

    }

    If None, all ratios default to 1.0

  • shift_peak_hours_before (float, optional) – Hours to shift peak window start (negative=earlier, positive=later). Must be multiple of 0.25 hours. Default 0

  • shift_peak_hours_after (float, optional) – Hours to shift peak window end (negative=earlier, positive=later). Must be multiple of 0.25 hours. Default 0

  • variant_name (str, optional) – Name for this variant. Default None

Returns:

Updated rate_data dataframe with parametrized charges and windows

Return type:

pandas.DataFrame

Raises:
  • ValueError – If percent_change_dict contains both period-based scaling and individual charge scaling for the same charge type

  • UserWarning – If percent_change_dict contains exact charge keys that are not found in the data

eeco.costs.parse_charge_key(key)[source]

Splits a charge key into its fields, inverting default_varstr_alias_func.

Parameters:

key (str) – Charge key of the form utility`_`charge_type`_`name`_`start_date`_`end_date`_`charge_limit

Raises:

ValueError – When key has fewer than six underscore-separated fields

Returns:

utility, charge_type, name, start_date, end_date, charge_limit

Return type:

tuple of str