Building & Climate¶
Building¶
- class ecoengine.objects.building.Building.Building(climate_zone: ClimateZone | None, daily_dhw_use_supplyT_gal: float, peak_load_shape: list[float] | np.ndarray, avg_load_shape: list[float] | np.ndarray, utility_cost_tracker: UtilityCostTracker | None = None, building_type: str = '', design_oat_f: float | None = None, design_inlet_water_temp_f: float | None = None)[source]¶
Bases:
objectStores information about the building and surrounding environment where a DHW system will be sized and/or simulated.
Holds a ClimateZone (ambient conditions), a UtilityCostTracker (billing structure), and the building’s DHW load data (daily use and load shapes).
- __init__(climate_zone: ClimateZone | None, daily_dhw_use_supplyT_gal: float, peak_load_shape: list[float] | np.ndarray, avg_load_shape: list[float] | np.ndarray, utility_cost_tracker: UtilityCostTracker | None = None, building_type: str = '', design_oat_f: float | None = None, design_inlet_water_temp_f: float | None = None) None[source]¶
- Parameters:
climate_zone (ClimateZone | None) – Ambient OAT and cold water temperature data for this location. If None and design conditions are provided, a constant-value ClimateZone is created automatically from those conditions.
daily_dhw_use_supplyT_gal (float) – Design daily hot water consumption at supply temperature [gallons].
peak_load_shape (list[float] | np.ndarray) – Normalized 24-hour load profile for the design (peaky) day. Each value is the fraction of daily DHW use in that hour.
avg_load_shape (list[float] | np.ndarray) – Normalized 24-hour load profile for an average day.
utility_cost_tracker (UtilityCostTracker | None)
building_type (str) – Label for the building type (e.g. ‘multi_family’, ‘multi_use’).
design_oat_f (float | None) – Design outdoor air temperature [°F]. Used only when climate_zone is None; creates a constant-OAT ClimateZone that returns this value for every timestep and as the design condition.
design_inlet_water_temp_f (float | None) – Design cold-water inlet temperature [°F]. Used only when climate_zone is None; creates a constant-inlet-temp ClimateZone that returns this value for every timestep and as the design condition.
- classmethod from_building_type(building_type: str | None | list[str | None], magnitude: float | None | list, climate_zone: ClimateZone | None, gpdpp: float = 25, standard_gpd: str | None = None, n_br: list[int] | None = None, custom_peak_load_shape: list[float] | list[list[float] | None] | None = None, custom_avg_load_shape: list[float] | list[list[float] | None] | None = None, annual: bool = False, **kwargs) Building[source]¶
Construct a Building from a named building type (or a list of types for multi-use buildings).
- Parameters:
building_type (str | None | list[str | None]) – Named type(s): ‘multi_family’, ‘apartment’, ‘motel’, ‘office_building’, ‘mens_dorm’, ‘womens_dorm’, ‘nursing_home’, ‘food_service_a’, ‘food_service_b’, ‘elementary_school’, ‘junior_high’, ‘senior_high’. Use None for a custom-load-shape-only building (requires custom_peak_load_shape). Pass a list for a multi-use building.
magnitude (float | None | list) – Occupancy metric matching the building type(s). For multi-use, pass a list of the same length as building_type. An individual entry may be None only when building_type is also None for that slot (magnitude is then derived from the sum of the unnormalized custom load shape).
climate_zone (ClimateZone | None)
gpdpp (float) – Gallons per person per day. Used for ‘multi_family’ when standard_gpd is None.
standard_gpd (str | None) – Standard GPD key for ‘multi_family’: ‘ashLow’, ‘ashMed’, ‘ecoMark’, or ‘ca’. Overrides gpdpp when provided.
n_br (list[int] | None) – Unit counts by bedroom size [0BR-5BR]. Required for standard_gpd=’ca’.
custom_peak_load_shape (list[float] | list[list[float] | None] | None) – 24-element normalized peak load shape override. For multi-use, pass a list of shapes (or None entries to use the default for that type).
custom_avg_load_shape (list[float] | list[list[float] | None] | None) – Same as custom_peak_load_shape but for the average day.
annual (bool) – If True, load the 8760-hour annual load shape instead of the 24-hour daily shape. Only supported for multi_family buildings.
**kwargs – Forwarded to Building.__init__ (e.g. design_oat_f, utility_cost_tracker).
- Return type:
- Raises:
- is_annual_load_shape() bool[source]¶
Return True if the building is currently using the 8760-hour annual load shape.
- set_to_annual_load_shape() None[source]¶
Switch to the full 8760-hour annual load shape.
Only supported for multi_family buildings, which have an ‘Annual_Normalized’ profile in their load shape JSON. The annual shape serves as both peak and avg (there is no separate peaky day for an annual simulation).
- Raises:
ValueError – If called on a non-multi_family building type.
- set_to_daily_load_shape() None[source]¶
Switch back to the 24-hour daily load shapes (Stream / Stream_Avg).
Only supported for multi_family buildings.
- Raises:
ValueError – If called on a non-multi_family building type.
- get_dhw_load_supplyT_gal(timestep_interval: int, interval_min: int = 1, use_avg: bool = False) float[source]¶
Return the DHW load in gallons at supply temperature for one timestep.
The load shape describes what fraction of the daily total falls in each hour. The returned value is scaled down to the interval duration so that summing over all intervals in a day always equals daily_dhw_use_supplyT_gal.
- Parameters:
- Returns:
Gallons of DHW load at supply temperature for this interval.
- Return type:
- get_oat_f(timestep_interval: int, interval_min: int = 1) float[source]¶
Return outdoor air temperature at the given timestep via ClimateZone.
- Parameters:
- Returns:
Outdoor air temperature [°F].
- Return type:
- get_inlet_water_temp_f(timestep_interval: int, interval_min: int = 1) float[source]¶
Return cold/inlet water temperature at the given timestep via ClimateZone.
- Parameters:
- Returns:
Inlet water temperature [°F].
- Return type:
ClimateZone¶
- class ecoengine.objects.building.ClimateZone.ClimateZone(zone_id: int | None, oat_f_by_hour: list[float] | None, inlet_water_temp_f_by_month: list[float] | None, constant_oat_f: float | None = None, constant_inlet_water_temp_f: float | None = None)[source]¶
Bases:
objectStores outdoor air temperature (OAT) and cold/inlet water temperature for a building’s location over a typical meteorological year.
OAT is stored hourly (8,760 values — one per hour of the year). Inlet water temp is stored monthly (12 values — one per month).
The simulator queries this object at every timestep to obtain ambient conditions for heat-pump performance and load calculations.
- __init__(zone_id: int | None, oat_f_by_hour: list[float] | None, inlet_water_temp_f_by_month: list[float] | None, constant_oat_f: float | None = None, constant_inlet_water_temp_f: float | None = None) None[source]¶
- Parameters:
zone_id (int | None) – Numeric climate zone identifier (1-96 for OAT data; 1-19 for full CA data including kG/kWh). None for design-condition zones.
oat_f_by_hour (list[float] | None) – Outdoor air temperatures for every hour of a typical year [°F]. 8,760 elements for real zones; None for design-condition zones.
inlet_water_temp_f_by_month (list[float] | None) – Average cold-water inlet temperature for each calendar month [°F]. 12 elements for real zones; None for design-condition zones.
constant_oat_f (float | None) – If set, all OAT queries return this value instead of reading from oat_f_by_hour. Set automatically by from_design_conditions().
constant_inlet_water_temp_f (float | None) – If set, all inlet water temp queries return this value instead of reading from inlet_water_temp_f_by_month. Set automatically by from_design_conditions().
- classmethod from_zip_code(zip_code: str | int) ClimateZone[source]¶
Construct a ClimateZone by looking up the CA climate zone for a zip code and loading the corresponding weather data.
- Parameters:
- Return type:
- Raises:
ValueError – If the zip code is not found in the CA lookup table.
- classmethod from_weather_station(station_id: str) ClimateZone[source]¶
Construct a ClimateZone from a named weather station.
- Parameters:
station_id (str) – Weather station name exactly as it appears in the lookup CSV (e.g.
'ID - Boise Air Terminal').- Return type:
- Raises:
ValueError – If the station name is not found in the lookup table.
- classmethod from_zone_id(zone_id: int) ClimateZone[source]¶
Construct a ClimateZone directly from a numeric climate zone ID.
- Parameters:
zone_id (int) – Climate zone number (1-96 for OAT data; 1-19 for full CA data).
- Return type:
- classmethod from_design_conditions(design_oat_f: float | None = None, design_inlet_water_temp_f: float | None = None) ClimateZone[source]¶
Create a constant-condition ClimateZone for use when real climate data is unavailable.
Every OAT query returns design_oat_f; every inlet water temp query returns design_inlet_water_temp_f. The design values are also returned by get_design_oat_f() and get_design_inlet_water_temp_f() directly.
- Parameters:
- Return type:
- get_oat_f(timestep_interval: int, interval_min: int = 1) float[source]¶
Return outdoor air temperature at the given simulation timestep.
OAT data is stored hourly, so this rounds down to the nearest hour. Wraps around yearly (safe for multi-year or 3-day simulations that start mid-year).
- Parameters:
- Returns:
Outdoor air temperature [°F].
- Return type:
- get_inlet_water_temp_f(timestep_interval: int, interval_min: int = 1) float[source]¶
Return cold/inlet water temperature at the given simulation timestep.
Inlet water temperature is stored as a monthly average, so the timestep is converted to a day-of-year and then to a month.
- Parameters:
- Returns:
Inlet water temperature [°F].
- Return type:
- get_design_oat_f() float[source]¶
Return the design-day outdoor air temperature [°F].
For real climate zones: the annual minimum OAT (worst-case heating condition for heat-pump sizing). For design-condition zones: the constant value set at construction.
- get_design_inlet_water_temp_f() float[source]¶
Return the design-day cold water inlet temperature [°F].
For real climate zones: the coldest monthly average (worst-case sizing condition). For design-condition zones: the constant value set at construction.
- get_oat_buckets() dict[float, int][source]¶
Return the distribution of daily average outdoor air temperatures across 5°F buckets for the full typical meteorological year.
For each of the 365 days in the year the 24 hourly OAT values are averaged to produce a daily mean, which is then assigned to the nearest lower multiple of 5°F (e.g. 62.4°F → 60.0°F bucket).
- Returns:
Mapping of bucket temperature [°F] → number of days in that bucket. Only buckets with at least one day are included.
- Return type:
- Raises:
ValueError – If this ClimateZone was created with
from_design_conditions()and has no real hourly OAT data.
UtilityCostTracker¶
- class ecoengine.objects.building.UtilityCostTracker.UtilityCostTracker(demand_period_chart: list[int], demand_charge_map: dict[int, float], energy_charge_map: dict[int, float], is_peak_map: dict[int, bool], is_discount_map: dict[int, bool], monthly_base_charge: float, energy_charge_by_hour: list[float] | None = None, include_discount: bool = False)[source]¶
Bases:
objectStores a utility billing structure and provides per-timestep rate lookups.
Supports monthly base charges, peak/off-peak demand charges ($/kW), and peak/off-peak energy charges ($/kWh), with optional seasonal variation and an optional third discount period (e.g. overnight super-off-peak tariffs).
Period key scheme¶
- Without discount (num_periods = 2):
month × 2→ off-peakmonth × 2 + 1→ peak- With discount (num_periods = 3):
month × 3→ off-peakmonth × 3 + 1→ peakmonth × 3 + 2→ discount
Construction¶
Use the factory classmethods rather than calling
__init__directly:uc = UtilityCostTracker.from_params( monthly_base_charge=190.0, pk_start_hour=16, pk_end_hour=21, pk_demand_charge=38.75, pk_energy_charge=0.21585, off_pk_demand_charge=30.20, off_pk_energy_charge=0.14341, ) uc = UtilityCostTracker.from_csv("utility_rates.csv")
- __init__(demand_period_chart: list[int], demand_charge_map: dict[int, float], energy_charge_map: dict[int, float], is_peak_map: dict[int, bool], is_discount_map: dict[int, bool], monthly_base_charge: float, energy_charge_by_hour: list[float] | None = None, include_discount: bool = False) None[source]¶
- classmethod from_params(monthly_base_charge: float, pk_start_hour, pk_end_hour, pk_demand_charge, pk_energy_charge, off_pk_demand_charge, off_pk_energy_charge, start_month=0, end_month=12, include_discount: bool = False, dscnt_start_hour=None, dscnt_end_hour=None, discnt_demand_charge=None, discnt_energy_charge=None) UtilityCostTracker[source]¶
Build a UtilityCostTracker from rate parameters.
All rate/hour/month parameters may be scalars (uniform year-round rate) or lists (seasonal variation). When lists are supplied they must all have the same length n, where each element describes one contiguous block of months.
start_monthandend_monthmust partition[0, 12]without gaps or overlaps:start_month[0]must be 0,end_month[-1]must be 12, and eachstart_month[i]must equalend_month[i-1].- Parameters:
monthly_base_charge (float) – Fixed monthly connection charge [$].
pk_start_hour (int or list[int]) – Hour of day (0–23) when the peak period begins.
pk_end_hour (int or list[int]) – Hour of day (pk_start_hour–24) when the peak period ends.
pk_end_hour == pk_start_hour→ no peak period.pk_start_hour == 0, pk_end_hour == 24→ all-peak day.pk_demand_charge (float or list[float]) – Peak demand charge [$/kW].
pk_energy_charge (float or list[float]) – Peak energy rate [$/kWh].
off_pk_demand_charge (float or list[float]) – Off-peak demand charge [$/kW].
off_pk_energy_charge (float or list[float]) – Off-peak energy rate [$/kWh].
start_month (int or list[int]) – 0-based month index where each rate block begins. Default 0.
end_month (int or list[int]) – 0-based month index where each rate block ends (exclusive). Default 12.
include_discount (bool) – If True, a third discount period is added within each month.
dscnt_start_hour (int or list[int] or None) – Discount period start hour.
dscnt_end_hour (int or list[int] or None) – Discount period end hour.
discnt_demand_charge (float or list[float] or None) – Discount demand charge [$/kW].
discnt_energy_charge (float or list[float] or None) – Discount energy rate [$/kWh].
- Return type:
- Raises:
ValueError – If any parameter fails validation.
- classmethod from_csv(csv_path: str | None = None, csv_file: TextIOWrapper | None = None) UtilityCostTracker[source]¶
Build a UtilityCostTracker from an 8760-row CSV file.
The CSV must have a header row with (at minimum) these columns:
Energy Rate ($/kWh),Demand Rate ($/kW),Demand Period,Monthly Base Charge.Monthly Base Chargeis read from the first data row only. Demand and energy rates are read from the first row in which eachDemand Periodvalue appears; subsequent rows may leave those columns blank. Demand periods with odd labels are treated as peak; even labels as off-peak.- Parameters:
csv_path (str or None)
csv_file (TextIOWrapper or None)
- Return type:
- Raises:
ValueError – On missing columns, wrong row count, or bad cell values.
- get_energy_charge_at_step(step: int, timestep_min: int) float[source]¶
Return the energy rate [$/kWh] for simulation step step.
- get_demand_period_at_step(step: int, timestep_min: int) int[source]¶
Return the demand period key for simulation step step.
- get_demand_charge_for_period(period_key: int, max_kw: float) float[source]¶
Return the demand charge [$] for period_key given max_kw.
- Parameters:
- Return type:
- Raises:
ValueError – If period_key is not a defined period.
- get_all_demand_period_keys() list[int][source]¶
Return all defined demand period keys (one per month×period type).
- get_yearly_base_charge() float[source]¶
Return the annual base charge [$] (monthly_base_charge × 12).
- to_csv(csv_path: str) None[source]¶
Export the rate structure to a CSV file readable by
from_csv.Produces 8760 data rows (one per hour of a non-leap year) plus a header. Energy and demand rates are written on the first occurrence of each demand period; subsequent rows leave those fields blank. The monthly base charge appears only in the first data row.
- Parameters:
csv_path (str) – Destination file path.