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'