diff --git a/.gitignore b/.gitignore
index 38550be98..2d3fc7ce3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,6 +28,7 @@ lib/
*.pyc
report.xml
resources/Gemfile.lock
+/test/local_run
# Non-template postprocessing scripts
postprocessing/compare_comstock_to_ami.py
diff --git a/measures/comstock_sensitivity_reports/measure.rb b/measures/comstock_sensitivity_reports/measure.rb
index d8fee1fe1..1e6510862 100644
--- a/measures/comstock_sensitivity_reports/measure.rb
+++ b/measures/comstock_sensitivity_reports/measure.rb
@@ -112,6 +112,10 @@ def energyPlusOutputRequests(runner, user_arguments)
# request service water heating use
result << OpenStudio::IdfObject.load('Output:Variable,*,Water Use Connections Hot Water Volume,RunPeriod;').get
+ # request refrigeration defrost energy
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Refrigeration Case Defrost Electricity Energy,RunPeriod;').get # J
+ result << OpenStudio::IdfObject.load('Output:Variable,*,Refrigeration Walk In Defrost Electricity Energy,RunPeriod;').get # J
+
# request coil and fan energy use for HVAC equipment
result << OpenStudio::IdfObject.load('Output:Variable,*,Cooling Tower Make Up Water Volume,RunPeriod;').get # m3
result << OpenStudio::IdfObject.load('Output:Variable,*,Chiller COP,RunPeriod;').get
@@ -193,7 +197,6 @@ def energyPlusOutputRequests(runner, user_arguments)
end
end
-
# result << OpenStudio::IdfObject.load("Output:Variable,*,Fan #{elec} Energy,RunPeriod;").get # J
# result << OpenStudio::IdfObject.load("Output:Variable,*,Humidifier #{elec} Energy,RunPeriod;").get # J
# result << OpenStudio::IdfObject.load("Output:Variable,*,Evaporative Cooler #{elec} Energy,RunPeriod;").get # J
@@ -645,7 +648,7 @@ def run(runner, user_arguments)
end
end
- if ann_env_pd == false
+ if (ann_env_pd.nil?) || (ann_env_pd == false)
runner.registerError('Cannot find a weather runperiod. Make sure you ran an annual simulation, not just the design days.')
return false
end
@@ -1150,7 +1153,7 @@ def run(runner, user_arguments)
unless ts_ahu_ma_flow_rate_kg_s_list.nil?
average_non_zero_loop_mass_flow_kg_s = ts_ahu_ma_flow_rate_kg_s_list.reject(&:zero?).sum.to_f / ts_ahu_ma_flow_rate_kg_s_list.reject(&:zero?).count
else
- average_non_zero_loop_mass_flow_kg_s = -999
+ average_non_zero_loop_mass_flow_kg_s = 0.0
end
# Add to weighted
@@ -1159,8 +1162,8 @@ def run(runner, user_arguments)
air_system_weighted_fan_power_minimum_flow_fraction += fan_minimum_flow_frac * air_loop_mass_flow_rate_kg_s
air_system_weighted_fan_static_pressure += fan_static_pressure * air_loop_mass_flow_rate_kg_s
air_system_weighted_fan_efficiency += fan_efficiency * air_loop_mass_flow_rate_kg_s
- if fan_var_vol
- air_system_total_vav_mass_flow_kg_s += average_non_zero_loop_mass_flow_kg_s # Track VAV airflow separately for SP reset measure
+ if fan_var_vol && average_non_zero_loop_mass_flow_kg_s > 0.0
+ air_system_total_vav_mass_flow_kg_s += average_non_zero_loop_mass_flow_kg_s # Track VAV airflow separately for Static Pressure Reset measure
air_system_total_des_flow_rate_m3_s += des_flow_rate_m3_s
end
end
@@ -3800,6 +3803,46 @@ def system_type_for(pump)
runner.registerValue('com_report_shw_hp_water_heater_unmet_heat_transfer_demand_j', heat_pump_water_heater_unmet_heat_transfer_demand_j)
runner.registerValue('com_report_shw_non_hp_water_heater_unmet_heat_transfer_demand_j', water_heater_unmet_heat_transfer_demand_j)
+ # Refrigeration cases and walk-ins
+ # Medium temperature: caseOperatingTemperature > -3C; Low temperature: <= -3C
+ refrigeration_med_temp_case_count = 0.0
+ refrigeration_med_temp_case_total_defrost_electric_j = 0.0
+ refrigeration_low_temp_case_count = 0.0
+ refrigeration_low_temp_case_total_defrost_electric_j = 0.0
+ model.getRefrigerationCases.sort.each do |ref_case|
+ defrost_electric_j = sql_get_report_variable_data_double(runner, sql, ref_case, 'Refrigeration Case Defrost Electricity Energy')
+ if ref_case.caseOperatingTemperature > -3.0
+ refrigeration_med_temp_case_count += 1.0
+ refrigeration_med_temp_case_total_defrost_electric_j += defrost_electric_j
+ else
+ refrigeration_low_temp_case_count += 1.0
+ refrigeration_low_temp_case_total_defrost_electric_j += defrost_electric_j
+ end
+ end
+ runner.registerValue('com_report_refrigeration_med_temp_case_count', refrigeration_med_temp_case_count)
+ runner.registerValue('com_report_refrigeration_med_temp_case_total_defrost_electric_j', refrigeration_med_temp_case_total_defrost_electric_j, 'J')
+ runner.registerValue('com_report_refrigeration_low_temp_case_count', refrigeration_low_temp_case_count)
+ runner.registerValue('com_report_refrigeration_low_temp_case_total_defrost_electric_j', refrigeration_low_temp_case_total_defrost_electric_j, 'J')
+
+ refrigeration_med_temp_walk_in_count = 0.0
+ refrigeration_med_temp_walk_in_total_defrost_electric_j = 0.0
+ refrigeration_low_temp_walk_in_count = 0.0
+ refrigeration_low_temp_walk_in_total_defrost_electric_j = 0.0
+ model.getRefrigerationWalkIns.sort.each do |walk_in|
+ defrost_electric_j = sql_get_report_variable_data_double(runner, sql, walk_in, 'Refrigeration Walk In Defrost Electricity Energy')
+ if walk_in.operatingTemperature > -3.0
+ refrigeration_med_temp_walk_in_count += 1.0
+ refrigeration_med_temp_walk_in_total_defrost_electric_j += defrost_electric_j
+ else
+ refrigeration_low_temp_walk_in_count += 1.0
+ refrigeration_low_temp_walk_in_total_defrost_electric_j += defrost_electric_j
+ end
+ end
+ runner.registerValue('com_report_refrigeration_med_temp_walk_in_count', refrigeration_med_temp_walk_in_count)
+ runner.registerValue('com_report_refrigeration_med_temp_walk_in_total_defrost_electric_j', refrigeration_med_temp_walk_in_total_defrost_electric_j, 'J')
+ runner.registerValue('com_report_refrigeration_low_temp_walk_in_count', refrigeration_low_temp_walk_in_count)
+ runner.registerValue('com_report_refrigeration_low_temp_walk_in_total_defrost_electric_j', refrigeration_low_temp_walk_in_total_defrost_electric_j, 'J')
+
# Error and Warning count from eplusout.err file (sql does not have data)
err_path = File.join(File.dirname(sql.path.to_s), 'eplusout.err')
File.foreach(err_path).each do |line|
diff --git a/measures/comstock_sensitivity_reports/measure.xml b/measures/comstock_sensitivity_reports/measure.xml
index cc2148c4b..bf7915039 100644
--- a/measures/comstock_sensitivity_reports/measure.xml
+++ b/measures/comstock_sensitivity_reports/measure.xml
@@ -3,8 +3,8 @@
3.1
com_stock_sensitivity_reports
aeb81242-de7e-4613-af47-c1faf19d286a
- 0955d5f5-3a15-4c10-9151-5ea649038f6b
- 2025-09-17T17:07:23Z
+ 77e7e9b0-bc0d-4c7d-941a-f1ef6e059cee
+ 2026-04-07T20:45:33Z
A0069B90
ComStockSensitivityReports
ComStock_Sensitivity_Reports
@@ -76,13 +76,13 @@
measure.rb
rb
script
- 58DAA5CC
+ 2272FBBC
Variable List.xlsx
xlsx
resource
- 3B3560C3
+ F43A7411
8172d17_0000008.osm
@@ -238,7 +238,7 @@
comstock_sensitivity_reports_test.rb
rb
test
- BA366C89
+ 486ECDB4
ground_heat_exchanger.osm
diff --git a/measures/comstock_sensitivity_reports/resources/Variable List.xlsx b/measures/comstock_sensitivity_reports/resources/Variable List.xlsx
index 0da507469..302a54f15 100644
Binary files a/measures/comstock_sensitivity_reports/resources/Variable List.xlsx and b/measures/comstock_sensitivity_reports/resources/Variable List.xlsx differ
diff --git a/measures/comstock_sensitivity_reports/tests/comstock_sensitivity_reports_test.rb b/measures/comstock_sensitivity_reports/tests/comstock_sensitivity_reports_test.rb
index 335ea972a..acacfa6ba 100644
--- a/measures/comstock_sensitivity_reports/tests/comstock_sensitivity_reports_test.rb
+++ b/measures/comstock_sensitivity_reports/tests/comstock_sensitivity_reports_test.rb
@@ -305,7 +305,7 @@ def test_pump_spec
output_txt = JSON.parse(File.read("#{run_dir(__method__)}/output.txt"))
output_txt.each do |output_var|
puts("### DEBUGGING: output_var = #{output_var['name']} | value = #{output_var['value']}")
-
+
# check values with values from example model
if output_var['name'] == 'com_report_pump_flow_weighted_avg_motor_efficiency'
assert_in_delta(0.9086, output_var['value'].to_f, 0.01)
@@ -328,7 +328,6 @@ def test_pump_spec
if output_var['name'] == 'com_report_pump_count_swh_var_spd'
assert_equal(1, output_var['value'])
end
-
end
end
end
diff --git a/postprocessing/comstockpostproc/comstock.py b/postprocessing/comstockpostproc/comstock.py
index e8f2053c0..ce0712d0d 100644
--- a/postprocessing/comstockpostproc/comstock.py
+++ b/postprocessing/comstockpostproc/comstock.py
@@ -2241,6 +2241,7 @@ def plotting_columns(self):
# Universal
pcs += [self.UPGRADE_APPL, self.UPGRADE_NAME, self.BLDG_ID, self.CZ_ASHRAE, self.DATASET, self.BLDG_WEIGHT]
pcs += [self.col_name_to_weighted(c, new_units=UnitsMixin.UNIT.ENERGY.TBTU) for c in self.COLS_ENDUSE_ANN_ENGY]
+ pcs += [self.col_name_to_weighted(c, new_units=UnitsMixin.UNIT.ENERGY.TBTU) for c in self.COLS_GROCERY_REFRIG_DEFROST_ENDUSE]
pcs += [self.col_name_to_weighted(c, UnitsMixin.UNIT.MASS.CO2E_MMT) for c in self.GHG_FUEL_COLS]
cols = self.COLS_UTIL_BILLS + ['out.utility_bills.electricity_bill_max..usd', 'out.utility_bills.electricity_bill_min..usd']
@@ -2326,7 +2327,9 @@ def create_plotting_lazyframe(self):
column_downselection='detailed')
# Select only columns needed for plotting
- wtd_agg_outs = wtd_agg_outs.select(self.plotting_columns())
+ available_cols = set(wtd_agg_outs.collect_schema().names())
+ plot_cols = [c for c in self.plotting_columns() if c in available_cols]
+ wtd_agg_outs = wtd_agg_outs.select(plot_cols)
# Write data to parquet file, hive partition on upgrade to make later processing faster
file_name = f'cached_ComStock_plotting_upgrade{upgrade_id}.parquet'
@@ -3371,6 +3374,7 @@ def add_weighted_area_energy_savings_columns(self, input_lf):
self.COLS_TOT_ANN_ENGY +
self.COLS_GEN_ANN_ENGY +
self.COLS_ENDUSE_ANN_ENGY +
+ self.COLS_GROCERY_REFRIG_DEFROST_ENDUSE +
self.COLS_ENDUSE_GROUP_TOT_ANN_ENGY +
self.COLS_ENDUSE_GROUP_ANN_ENGY +
self.load_component_cols()):
diff --git a/postprocessing/comstockpostproc/comstock_measure_comparison.py b/postprocessing/comstockpostproc/comstock_measure_comparison.py
index a81803bb1..57a561a32 100644
--- a/postprocessing/comstockpostproc/comstock_measure_comparison.py
+++ b/postprocessing/comstockpostproc/comstock_measure_comparison.py
@@ -150,10 +150,12 @@ def make_plots(self, lazy_frame: pl.LazyFrame, column_for_grouping, timeseries_l
plot_method=self.plot_floor_area_and_energy_totals_by_building_type,
lazy_frame=lazy_frame.clone(),
columns=(self.lazyframe_plotter.BASE_COLUMNS + self.lazyframe_plotter.WTD_COLUMNS_SUMMARIZE))(**BASIC_PARAMS)
+ _lf_schema = lazy_frame.collect_schema().names()
+ _grocery_detail_cols = [c for c in self.lazyframe_plotter.WTD_COLS_GROCERY_REFRIG_DETAIL if c in _lf_schema]
LazyFramePlotter.plot_with_lazy(
plot_method=self.plot_end_use_totals_by_building_type,
lazy_frame=lazy_frame.clone(),
- columns=(self.lazyframe_plotter.BASE_COLUMNS + self.lazyframe_plotter.WTD_COLUMNS_ANN_ENDUSE + [self.BLDG_TYPE, self.CEN_DIV]))(**BASIC_PARAMS)
+ columns=(self.lazyframe_plotter.BASE_COLUMNS + self.lazyframe_plotter.WTD_COLUMNS_ANN_ENDUSE + _grocery_detail_cols + [self.BLDG_TYPE, self.CEN_DIV]))(**BASIC_PARAMS)
LazyFramePlotter.plot_with_lazy(plot_method=self.plot_eui_histograms_by_building_type,
lazy_frame=lazy_frame.clone(), columns=(self.lazyframe_plotter.BASE_COLUMNS + self.lazyframe_plotter.EUI_ANN_TOTL_COLUMNS + [self.BLDG_TYPE]))(**BASIC_PARAMS)
LazyFramePlotter.plot_with_lazy(plot_method=self.plot_eui_boxplots_by_building_type,
diff --git a/postprocessing/comstockpostproc/comstock_to_cbecs_comparison.py b/postprocessing/comstockpostproc/comstock_to_cbecs_comparison.py
index 088b6ee0f..34c9086a4 100644
--- a/postprocessing/comstockpostproc/comstock_to_cbecs_comparison.py
+++ b/postprocessing/comstockpostproc/comstock_to_cbecs_comparison.py
@@ -19,7 +19,7 @@
logger = logging.getLogger(__name__)
class ComStockToCBECSComparison(NamingMixin, UnitsMixin, PlottingMixin):
- def __init__(self, comstock_list: List[ComStock], cbecs_list: List[CBECS], upgrade_id=0, image_type='jpg', name=None, make_comparison_plots=True, make_hvac_plots = False):
+ def __init__(self, comstock_list: List[ComStock], cbecs_list: List[CBECS], upgrade_id=0, image_type='jpg', name=None, make_comparison_plots=True, make_hvac_plots = False, building_type: str | None = None):
"""
Creates the ComStock to CBECS comaprison plots.
@@ -30,6 +30,11 @@ def __init__(self, comstock_list: List[ComStock], cbecs_list: List[CBECS], upgra
image_type (str, optional): Image file type to use. Defaults to 'jpg'.
name (str, optional): Name of output directory. If None, a name will be generated. Defaults to None.
make_comparison_plots (bool, optional): Flag to create compairison plots. Defaults to True.
+ building_type (str | None, optional): ComStock building type to filter plots to.
+ Valid values: 'FullServiceRestaurant', 'QuickServiceRestaurant', 'RetailStripmall',
+ 'RetailStandalone', 'SmallOffice', 'MediumOffice', 'LargeOffice', 'PrimarySchool',
+ 'SecondarySchool', 'Outpatient', 'Hospital', 'SmallHotel', 'LargeHotel', 'Warehouse',
+ 'Grocery'. If None, all building types are plotted.
"""
# Initialize members
self.comstock_list = comstock_list
@@ -41,6 +46,9 @@ def __init__(self, comstock_list: List[ComStock], cbecs_list: List[CBECS], upgra
self.column_for_grouping = self.DATASET
self.lazyframe_plotter: LazyFramePlotter = LazyFramePlotter()
+ # Optional building type filter for faster plotting.
+ requested_building_type = self._validate_building_type(building_type)
+
# Concatenate the datasets and create a color map
dfs_to_concat = []
comstock_dfs_to_concat = []
@@ -108,12 +116,25 @@ def __init__(self, comstock_list: List[ComStock], cbecs_list: List[CBECS], upgra
# Combine into a single dataframe for convenience
# self.data = pd.concat(dfs_to_concat, join='inner', ignore_index=True)
- #There is no such a join='inner' in polars.concat, implement it manually
+ # Preserve optional grocery refrigeration detail columns in mixed CBECS/ComStock comparisons
+ # by adding zero-filled placeholders where they are missing before schema intersection.
+ optional_enduse_cols = list(self.lazyframe_plotter.WTD_COLS_GROCERY_REFRIG_DETAIL)
+ dfs_with_optional_cols = []
+ for df in dfs_to_concat:
+ missing_optional_cols = [c for c in optional_enduse_cols if c not in df.collect_schema().names()]
+ if missing_optional_cols:
+ df = df.with_columns([pl.lit(0.0).alias(c) for c in missing_optional_cols])
+ dfs_with_optional_cols.append(df)
+ dfs_to_concat = dfs_with_optional_cols
+
+ # There is no such a join='inner' in polars.concat, implement it manually
common_columns = set(dfs_to_concat[0].collect_schema().names())
for df in dfs_to_concat:
common_columns = common_columns.intersection(set(df.collect_schema().names()))
dfs_to_concat = [df.select(common_columns) for df in dfs_to_concat]
self.data: pl.LazyFrame = pl.concat(dfs_to_concat, how="vertical_relaxed")
+ if requested_building_type is not None:
+ self.data = self._filter_to_building_type(self.data, requested_building_type)
# Add Replicate Weights (CBECS only) for RSE calculations
cbecs_src = cbecs_list[0]
rep_cols = [self.BLDG_ID] + self.list_replicate_weight_cols(cbecs_src.data)
@@ -143,9 +164,12 @@ def __init__(self, comstock_list: List[ComStock], cbecs_list: List[CBECS], upgra
logger.info(f"Not including columns {all_columns - common_columns} in comstock only plots")
comstock_dfs_to_concat = [df.select(common_columns) for df in comstock_dfs_to_concat]
comstock_qoi_columns = [self.DATASET] + self.QOI_MAX_DAILY_TIMING_COLS + self.QOI_MAX_USE_COLS + self.QOI_MIN_USE_COLS + self.QOI_MAX_USE_COLS_NORMALIZED + self.QOI_MIN_USE_COLS_NORMALIZED
- comstock_df: pl.LazyFrame = pl.concat(comstock_dfs_to_concat, how="vertical_relaxed").select(comstock_qoi_columns)
+ comstock_all_df: pl.LazyFrame = pl.concat(comstock_dfs_to_concat, how="vertical_relaxed")
+ if requested_building_type is not None:
+ comstock_all_df = self._filter_to_building_type(comstock_all_df, requested_building_type)
+ comstock_df: pl.LazyFrame = comstock_all_df.select(comstock_qoi_columns)
comstock_enduse_columns = [self.DATASET] + self.lazyframe_plotter.WTD_COLUMNS_ANN_ENDUSE + self.lazyframe_plotter.WTD_COLUMNS_ANN_PV + self.lazyframe_plotter.WTD_COLUMNS_SUMMARIZE
- comstock_enduse_df: pl.LazyFrame = pl.concat(comstock_dfs_to_concat, how="vertical_relaxed").select(comstock_enduse_columns)
+ comstock_enduse_df: pl.LazyFrame = comstock_all_df.select(comstock_enduse_columns)
# Make directories
self.output_dir = os.path.join(current_dir, '..', 'output', self.name)
@@ -211,7 +235,12 @@ def make_plots(self, lazy_frame: pl.LazyFrame, column_for_grouping, color_map: d
LazyFramePlotter.plot_with_lazy(
plot_method=self.plot_end_use_totals_by_building_type,
lazy_frame=lazy_frame.clone(),
- columns=( [column_for_grouping] + self.lazyframe_plotter.WTD_COLUMNS_ANN_ENDUSE + [self.BLDG_TYPE, self.CEN_DIV]))(**BASIC_PARAMS)
+ columns=(
+ [column_for_grouping]
+ + self.lazyframe_plotter.WTD_COLUMNS_ANN_ENDUSE
+ + self.lazyframe_plotter.WTD_COLS_GROCERY_REFRIG_DETAIL
+ + [self.BLDG_TYPE, self.CEN_DIV]
+ ))(**BASIC_PARAMS)
logger.info('Making EUI histogram by building type plots')
LazyFramePlotter.plot_with_lazy(
@@ -291,3 +320,21 @@ def export_to_csv_wide(self):
logger.info(f'Exported comparison data to {file_path}')
except Exception as e:
logger.error(f"CSV export failed: {e}")
+
+ def _validate_building_type(self, building_type: str | None) -> str | None:
+ if building_type is None:
+ return None
+
+ allowed_types = list(self.ORDERED_CATEGORIES[self.BLDG_TYPE])
+ requested = building_type.strip()
+ if requested not in allowed_types:
+ raise ValueError(
+ f"Invalid building_type '{building_type}'. Valid options are: {allowed_types}"
+ )
+ return requested
+
+ def _filter_to_building_type(self, lazy_frame: pl.LazyFrame, building_type: str) -> pl.LazyFrame:
+ schema = lazy_frame.collect_schema().names()
+ if self.BLDG_TYPE not in schema:
+ raise ValueError(f"Cannot filter by building type; missing required column: {self.BLDG_TYPE}")
+ return lazy_frame.filter(pl.col(self.BLDG_TYPE) == building_type)
diff --git a/postprocessing/comstockpostproc/lazyframeplotter.py b/postprocessing/comstockpostproc/lazyframeplotter.py
index 5b9d04b11..8f9e3cbd4 100644
--- a/postprocessing/comstockpostproc/lazyframeplotter.py
+++ b/postprocessing/comstockpostproc/lazyframeplotter.py
@@ -22,6 +22,9 @@ def __init__(self):
self.WTD_COLUMNS_ANN_ENDUSE = [self.col_name_to_weighted(
col_name=c, new_units=UnitsMixin.UNIT.ENERGY.TBTU) for c in self.COLS_ENDUSE_ANN_ENGY]
+ self.WTD_COLS_GROCERY_REFRIG_DETAIL = [self.col_name_to_weighted(
+ col_name=c, new_units=UnitsMixin.UNIT.ENERGY.TBTU) for c in self.COLS_GROCERY_REFRIG_DEFROST_ENDUSE]
+
self.WTD_COLUMNS_ANN_PV = [self.col_name_to_weighted(
col_name=c, new_units=UnitsMixin.UNIT.ENERGY.TBTU) for c in self.COLS_GEN_ANN_ENGY]
diff --git a/postprocessing/comstockpostproc/naming_mixin.py b/postprocessing/comstockpostproc/naming_mixin.py
index e385c142a..00321a01a 100644
--- a/postprocessing/comstockpostproc/naming_mixin.py
+++ b/postprocessing/comstockpostproc/naming_mixin.py
@@ -142,6 +142,10 @@ class NamingMixin():
ANN_ELEC_INTLTG_KBTU = 'out.electricity.interior_lighting.energy_consumption..kwh'
ANN_ELEC_PUMPS_KBTU = 'out.electricity.pumps.energy_consumption..kwh'
ANN_ELEC_REFRIG_KBTU = 'out.electricity.refrigeration.energy_consumption..kwh'
+ ANN_ELEC_REFRIG_MED_TEMP_CASE_DEFROST_KWH = 'out.params.refrigeration_med_temp_case_defrost_energy..kwh'
+ ANN_ELEC_REFRIG_LOW_TEMP_CASE_DEFROST_KWH = 'out.params.refrigeration_low_temp_case_defrost_energy..kwh'
+ ANN_ELEC_REFRIG_MED_TEMP_WALKIN_DEFROST_KWH = 'out.params.refrigeration_med_temp_walkin_defrost_energy..kwh'
+ ANN_ELEC_REFRIG_LOW_TEMP_WALKIN_DEFROST_KWH = 'out.params.refrigeration_low_temp_walkin_defrost_energy..kwh'
ANN_ELEC_SWH_KBTU = 'out.electricity.water_systems.energy_consumption..kwh'
ANN_ELEC_PV_KBTU = 'out.electricity.pv.energy_consumption..kwh' #new?
@@ -751,6 +755,26 @@ class NamingMixin():
ANN_ELEC_REFRIG_KBTU
]
+ # Refrigeration sub-category detail columns for Grocery buildings (subset of refrigeration, not added to COLS_ENDUSE_ANN_ENGY)
+ COLS_GROCERY_REFRIG_DEFROST_ENDUSE = [
+ ANN_ELEC_REFRIG_MED_TEMP_CASE_DEFROST_KWH,
+ ANN_ELEC_REFRIG_LOW_TEMP_CASE_DEFROST_KWH,
+ ANN_ELEC_REFRIG_MED_TEMP_WALKIN_DEFROST_KWH,
+ ANN_ELEC_REFRIG_LOW_TEMP_WALKIN_DEFROST_KWH
+ ]
+
+ # Refrigeration medium temperature detail columns for Grocery buildings
+ COLS_GROCERY_REFRIG_MED_TEMP_DEFROST_ENDUSE = [
+ ANN_ELEC_REFRIG_MED_TEMP_CASE_DEFROST_KWH,
+ ANN_ELEC_REFRIG_MED_TEMP_WALKIN_DEFROST_KWH
+ ]
+
+ # Refrigeration low temperature detail columns for Grocery buildings
+ COLS_GROCERY_REFRIG_LOW_TEMP_DEFROST_ENDUSE = [
+ ANN_ELEC_REFRIG_LOW_TEMP_CASE_DEFROST_KWH,
+ ANN_ELEC_REFRIG_LOW_TEMP_WALKIN_DEFROST_KWH
+ ]
+
# List of HVAC end use group columns
COLS_HVAC_ENERGY = COLS_HVAC_ELEC_ENDUSE + COLS_HVAC_GAS_ENDUSE + COLS_HVAC_PROPANE_ENDUSE + COLS_HVAC_FUELOIL_ENDUSE + COLS_HVAC_DISTHTG_ENDUSE + COLS_HVAC_DISTCLG_ENDUSE
diff --git a/postprocessing/comstockpostproc/plotting_mixin.py b/postprocessing/comstockpostproc/plotting_mixin.py
index 4f2209d15..2f708722d 100644
--- a/postprocessing/comstockpostproc/plotting_mixin.py
+++ b/postprocessing/comstockpostproc/plotting_mixin.py
@@ -1301,6 +1301,16 @@ def plot_end_use_totals_by_building_type(self, df, column_for_grouping, color_ma
end_use_cols = self.COLS_ENDUSE_ANN_ENGY
wtd_end_use_cols = [self.col_name_to_weighted(c, 'tbtu') for c in end_use_cols]
+ # Grocery-specific refrigeration defrost detail columns (subset of refrigeration)
+ grocery_detail_wtd_cols_med_temp = [
+ self.col_name_to_weighted(c, 'tbtu') for c in self.COLS_GROCERY_REFRIG_MED_TEMP_DEFROST_ENDUSE
+ if self.col_name_to_weighted(c, 'tbtu') in df.columns
+ ]
+ grocery_detail_wtd_cols_low_temp = [
+ self.col_name_to_weighted(c, 'tbtu') for c in self.COLS_GROCERY_REFRIG_LOW_TEMP_DEFROST_ENDUSE
+ if self.col_name_to_weighted(c, 'tbtu') in df.columns
+ ]
+
# Disaggregate to these levels (now supports None)
group_bys = [
None,
@@ -1317,13 +1327,20 @@ def plot_end_use_totals_by_building_type(self, df, column_for_grouping, color_ma
hue_order = list(color_map.keys())
palette = [color_map[name] for name in hue_order]
row_name = 'Fuel and End Use'
- row_label_map = {
- col: self.col_name_to_nice_name(col).replace(' Energy Consumption', '')
- for col in wtd_end_use_cols
- }
- row_order = [row_label_map[col] for col in wtd_end_use_cols]
for bldg_type, bldg_type_df in df.groupby(self.BLDG_TYPE, observed=True):
+ # Include refrigeration defrost detail columns for Grocery buildings
+ if bldg_type == 'Grocery' and (grocery_detail_wtd_cols_med_temp or grocery_detail_wtd_cols_low_temp):
+ wtd_end_use_cols_this = wtd_end_use_cols + grocery_detail_wtd_cols_med_temp + grocery_detail_wtd_cols_low_temp
+ else:
+ wtd_end_use_cols_this = wtd_end_use_cols
+
+ row_label_map = {
+ col: self.col_name_to_nice_name(col).replace(' Energy Consumption', '')
+ for col in wtd_end_use_cols_this
+ }
+ row_order = [row_label_map[col] for col in wtd_end_use_cols_this]
+
for group_by in group_bys:
# --- Minimal additions to support None group_by ---
if group_by is None:
@@ -1351,7 +1368,7 @@ def plot_end_use_totals_by_building_type(self, df, column_for_grouping, color_ma
column_for_grouping,
x_col
],
- value_vars=wtd_end_use_cols,
+ value_vars=wtd_end_use_cols_this,
var_name=var_name,
value_name=val_name
)
diff --git a/postprocessing/comstockpostproc/resources/comstock_column_definitions.csv b/postprocessing/comstockpostproc/resources/comstock_column_definitions.csv
index e7a65a3a3..f69af3c42 100644
--- a/postprocessing/comstockpostproc/resources/comstock_column_definitions.csv
+++ b/postprocessing/comstockpostproc/resources/comstock_column_definitions.csv
@@ -662,6 +662,14 @@ results.csv,com_stock_sensitivity_reports.com_report_shw_non_hp_water_heater_gas
results.csv,com_stock_sensitivity_reports.com_report_shw_non_hp_water_heater_other_fuel_j,out.params.non_hp_water_heater_other_fuel,TRUE,FALSE,float,j,j,other fuel energy use by non-heat pump water heaters
results.csv,com_stock_sensitivity_reports.com_report_shw_non_hp_water_heater_total_volume_gal,out.params.non_hp_water_heater_total_volume_gal,TRUE,FALSE,float,gal,gal,combined volume of water heaters
results.csv,com_stock_sensitivity_reports.com_report_shw_non_hp_water_heater_unmet_heat_transfer_demand_j,out.params.non_hp_water_heater_unmet_heat_transfer_demand,TRUE,FALSE,float,j,j,water heater unmet heat transfer demand
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_med_temp_case_count,out.params.refrigeration_med_temp_case_count,FALSE,FALSE,float,,,count of medium temperature refrigerated cases (operating temp > -3C)
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_med_temp_case_total_defrost_electric_j,out.params.refrigeration_med_temp_case_defrost_energy,TRUE,FALSE,float,j,kwh,electric energy use for medium temperature refrigerated case defrost
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_low_temp_case_count,out.params.refrigeration_low_temp_case_count,FALSE,FALSE,float,,,count of low temperature refrigerated cases (operating temp <= -3C)
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_low_temp_case_total_defrost_electric_j,out.params.refrigeration_low_temp_case_defrost_energy,TRUE,FALSE,float,j,kwh,electric energy use for low temperature refrigerated case defrost
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_med_temp_walk_in_count,out.params.refrigeration_med_temp_walkin_count,FALSE,FALSE,float,,,count of medium temperature refrigerated walk-ins (operating temp > -3C)
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_med_temp_walk_in_total_defrost_electric_j,out.params.refrigeration_med_temp_walkin_defrost_energy,TRUE,FALSE,float,j,kwh,electric energy use for medium temperature refrigerated walk-in defrost
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_low_temp_walk_in_count,out.params.refrigeration_low_temp_walkin_count,FALSE,FALSE,float,,,count of low temperature refrigerated walk-ins (operating temp <= -3C)
+results.csv,com_stock_sensitivity_reports.com_report_refrigeration_low_temp_walk_in_total_defrost_electric_j,out.params.refrigeration_low_temp_walkin_defrost_energy,TRUE,FALSE,float,j,kwh,electric energy use for low temperature refrigerated walk-in defrost
results.csv,com_stock_sensitivity_reports.com_report_unitary_sys_cycling_ratio_cooling,out.params.unitary_sys_cycling_ratio_cooling,TRUE,FALSE,float,,,weighted average unitary system cycling ratio for cooling operation
results.csv,com_stock_sensitivity_reports.com_report_unitary_sys_cycling_ratio_heating,out.params.unitary_sys_cycling_ratio_heating,TRUE,FALSE,float,,,weighted average unitary system cycling ratio for heating operation
results.csv,com_stock_sensitivity_reports.com_report_unitary_sys_cycling_excess_electricity_cooling_pcnt,out.params.unitary_sys_cycling_excess_electricity_cooling_pcnt,TRUE,FALSE,float,,,excess electricity used for cycling during cooling operation
diff --git a/postprocessing/comstockpostproc/units_mixin.py b/postprocessing/comstockpostproc/units_mixin.py
index 721b3cc47..9833fccd6 100644
--- a/postprocessing/comstockpostproc/units_mixin.py
+++ b/postprocessing/comstockpostproc/units_mixin.py
@@ -52,6 +52,7 @@ class DIMLESS:
'btu_to_kbtu' : (1.0 / 1e3),
'million_btu_to_kbtu': (1e9 / 1e6),
'million_btu_to_kwh': (1000 / 3.412141633127942),
+ 'j_to_kwh' : 1.0 / 3_600_000,
'gj_to_kbtu' : 947.8171203133173,
'gj_to_kwh' : 277.77777777777777,
'w_per_m2_k_to_btu_per_ft2_f_hr': 0.17611,
diff --git a/resources/Gemfile b/resources/Gemfile
index e73c12495..4c69ab934 100644
--- a/resources/Gemfile
+++ b/resources/Gemfile
@@ -13,7 +13,7 @@ gem 'bcl', '= 0.9.1'
gem 'openstudio-extension', '= 0.9.1'
gem 'openstudio-workflow', '= 2.5.0'
gem 'openstudio-standards', '= 0.8.6'
-# gem 'openstudio-standards', git: 'https://github.com/NREL/openstudio-standards.git', ref: 'bf737839be4512577fd49b4ca5f4e091a718a3bf'
+# gem 'openstudio-standards', git: 'https://github.com/NREL/openstudio-standards.git', ref: 'cd105f8e8f5d0980b5d0bb2468ec89c9aa517f04'
# gem 'openstudio-standards', path: "C:/GitRepos/openstudio-standards" # Use this format when testing openstudio-standards changes locally
gem 'openstudio-geb', git: 'https://github.com/LBNL-ETA/Openstudio-GEB-gem.git', ref: '87da5c2678327b73eef54d2364f46225154bb956'
gem 'tbd', '= 3.4.4'