From ae130ce18d70c41dc6c41583539b937795c7b2ef Mon Sep 17 00:00:00 2001 From: Katherine Fleming <2205659+kflemin@users.noreply.github.com> Date: Tue, 9 Jul 2024 09:44:25 -0600 Subject: [PATCH] BETTER v1.7 updates (#4679) * better v1.7 updates * Lint --------- Co-authored-by: Alex Swindler --- .../analysis_pipelines/better/buildingsync.py | 3 + seed/analysis_pipelines/better/pipeline.py | 88 +++++++++++-------- seed/analysis_pipelines/utils.py | 14 ++- seed/models/analyses.py | 4 +- 4 files changed, 66 insertions(+), 43 deletions(-) diff --git a/seed/analysis_pipelines/better/buildingsync.py b/seed/analysis_pipelines/better/buildingsync.py index c18c87536f..d52ac260a9 100644 --- a/seed/analysis_pipelines/better/buildingsync.py +++ b/seed/analysis_pipelines/better/buildingsync.py @@ -32,9 +32,12 @@ "Retail Store": "Retail", "Senior Care Community": "Health care-Skilled nursing facility", "Supermarket/Grocery Store": "Food sales-Grocery store", + "Restaurant": "Food service", + "Public Library": "Assembly-Public", "Other": "Other", } + # maps SEED Meter types to BuildingSync ResourceUse types # NOTE: this is semi-redundant with to_energy_type dict in building_sync/mappings.py SEED_TO_BSYNC_RESOURCE_TYPE = { diff --git a/seed/analysis_pipelines/better/pipeline.py b/seed/analysis_pipelines/better/pipeline.py index 1a9538e00e..992749d271 100644 --- a/seed/analysis_pipelines/better/pipeline.py +++ b/seed/analysis_pipelines/better/pipeline.py @@ -296,7 +296,6 @@ def _start_analysis(self, analysis_id): progress_data = pipeline.set_analysis_status_to_running() progress_data.step("Sending requests to BETTER service") analysis = Analysis.objects.get(id=analysis_id) - client = BETTERClient(analysis.organization.better_analysis_api_key) context = BETTERPipelineContext(analysis, progress_data, client) @@ -310,9 +309,7 @@ def _start_analysis(self, analysis_id): context, fail_on_error=True, ) - better_building_analyses, better_portfolio_building_analyses = _create_better_buildings(better_portfolio_id, context) - if better_portfolio_id is not None: better_portfolio_building_analyses = _run_better_portfolio_analysis( better_portfolio_id, @@ -350,38 +347,44 @@ def _process_results(self, analysis_id): """Store results from the analysis in the original PropertyState""" pipeline = BETTERPipeline(analysis_id) analysis = Analysis.objects.get(id=analysis_id) - progress_data = pipeline.get_progress_data(analysis) progress_data.step("Processing results") - # store all measure recommendations - # - # Updated measure list 10/21/2023. There were several added and 4 removed/renamed which include removal of: - # 'Check Fossil Baseload', 'Decrease Ventilation', 'Eliminate Electric Heating', 'Upgrade Windows', - # The data will still exist in the database for historic reason, but new runs will not include those. + # store all (LEVEL 1) measure recommendations + + # Updated measure list 05/20/2024 - BETTER workflow has changed in v1.7: The json data returned from the BA and PBA + # endpoints used to have a ee_measures key in the "assessments" dictionary with a dictionary of true / false values + # for every measure. Now, that same ee_measures key points to a list with the tokens for each measure that applies. + # There is no need to check for true or false...if the measure is in the list, it applies. + + # switch to a list of "Level 1 measure" tokens here. Tokens can be found here (grab the top level "token" in each dictionary): + # https://better-lbnl-development.herokuapp.com/api/v1/measures/ + # updating this list to a list of dictionary to keep the column names as close to the existing ones as possible ee_measure_names = [ - "Add/Fix Economizers", - "Add Wall/Ceiling/Roof Insulation", - "Decrease Heating Setpoints", - "Decrease Infiltration", - "Ensure Adequate Ventilation Rate", - "Increase Cooling Setpoints", - "Increase Cooling System Efficiency", - "Increase Heating System Efficiency", - "Reduce Equipment Schedules", - "Reduce Lighting Load", - "Reduce Plug Loads", - "Upgrade Windows to Improve Thermal Efficiency", - "Upgrade Windows to Reduce Solar Heat Gain", - "Upgrade to Sustainable Resources for Water Heating", - "Use High Efficiency Heat Pump for Heating", + {"token": "REDUCE_EQUIPMENT_SCHEDULES", "name": "Reduce Equipment Schedules"}, + {"token": "REDUCE_LIGHTING_LOAD", "name": "Reduce Lighting Load"}, + {"token": "REDUCE_PLUG_LOADS", "name": "Reduce Plug Loads"}, + {"token": "INCREASE_COOLING_SYSTEM_EFFICIENCY", "name": "Increase Cooling System Efficiency"}, + {"token": "DECREASE_HEATING_SETPOINTS", "name": "Decrease Heating Setpoints"}, + {"token": "ENSURE_ADEQUATE_VENTILATION_RATE", "name": "Ensure Adequate Ventilation Rate"}, + {"token": "DECREASE_INFILTRATION", "name": "Decrease Infiltration"}, + {"token": "INCREASE_HEATING_SYSTEM_EFFICIENCY", "name": "Increase Heating System Efficiency"}, + {"token": "ADD_WALL_CEILING_ROOF_INSULATION", "name": "Add Wall/Ceiling/Roof Insulation"}, + {"token": "UPGRADE_TO_SUSTAINABLE_RESOURCES_FOR_WATER_HEATING", "name": "Upgrade to Sustainable Resources for Water Heating"}, + {"token": "UPGRADE_WINDOWS_TO_REDUCE_SOLAR_HEAT_GAIN", "name": "Upgrade Windows to Reduce Solar Heat Gain"}, + {"token": "USE_HIGH_EFFICIENCY_HEAT_PUMP_FOR_HEATING", "name": "Use High Efficiency Heat Pump for Heating"}, + {"token": "INCREASE_COOLING_SETPOINTS", "name": "Increase Cooling Setpoints"}, + {"token": "ADD_FIX_ECONOMIZERS", "name": "Add/Fix Economizers"}, + {"token": "UPGRADE_WINDOWS_TO_IMPROVE_THERMAL_EFFICIENCY", "name": "Upgrade Windows to Improve Thermal Efficiency"}, + {"token": "OTHER_AREAS", "name": "Other Areas"}, ] + ee_measure_column_data_paths = [ ExtraDataColumnPath( - f'better_recommendation_{ee_measure_name.lower().replace(" ", "_")}', - f"BETTER Recommendation: {ee_measure_name}", + f'better_recommendation_{ee_measure_name["name"].lower().replace(" ", "_")}', + f'BETTER Recommendation: {ee_measure_name["name"]}', 1, - f"assessment.ee_measures.{ee_measure_name}", + f'assessment.ee_measures.{ee_measure_name["token"]}', ) for ee_measure_name in ee_measure_names ] @@ -393,64 +396,71 @@ def _process_results(self, analysis_id): # if user is at root level and has role member or owner, columns can be created # otherwise set the 'missing_columns' flag for later missing_columns = False - column_data_paths = [ # Combined Savings ExtraDataColumnPath( "better_cost_savings_combined", "BETTER Potential Cost Savings (USD)", 1, - "assessment.assessment_energy_use.cost_savings_combined", + "assessment.assessment_results.assessment_energy_use.cost_savings_combined", ), ExtraDataColumnPath( "better_energy_savings_combined", "BETTER Potential Energy Savings (kWh)", 1, - "assessment.assessment_energy_use.energy_savings_combined", + "assessment.assessment_results.assessment_energy_use.energy_savings_combined", ), ExtraDataColumnPath( "better_ghg_reductions_combined", "BETTER Potential GHG Emissions Reduction (MtCO2e)", 0.001, - "assessment.assessment_energy_use.ghg_reductions_combined", + "assessment.assessment_results.assessment_energy_use.ghg_reductions_combined", ), # Energy-specific Savings ExtraDataColumnPath( - BETTER_VALID_MODEL_E_COL, "BETTER Valid Electricity Model", 1, "assessment.assessment_energy_use.valid_model_e" + BETTER_VALID_MODEL_E_COL, + "BETTER Valid Electricity Model", + 1, + "assessment.assessment_results.assessment_energy_use.valid_model_e", + ), + ExtraDataColumnPath( + BETTER_VALID_MODEL_F_COL, "BETTER Valid Fuel Model", 1, "assessment.assessment_results.assessment_energy_use.valid_model_f" ), - ExtraDataColumnPath(BETTER_VALID_MODEL_F_COL, "BETTER Valid Fuel Model", 1, "assessment.assessment_energy_use.valid_model_f"), ExtraDataColumnPath( "better_cost_savings_electricity", "BETTER Potential Electricity Cost Savings (USD)", 1, - "assessment.assessment_energy_use.cost_savings_e", + "assessment.assessment_results.assessment_energy_use.cost_savings_e", ), ExtraDataColumnPath( - "better_cost_savings_fuel", "BETTER Potential Fuel Cost Savings (USD)", 1, "assessment.assessment_energy_use.cost_savings_f" + "better_cost_savings_fuel", + "BETTER Potential Fuel Cost Savings (USD)", + 1, + "assessment.assessment_results.assessment_energy_use.cost_savings_f", ), ExtraDataColumnPath( "better_energy_savings_electricity", "BETTER Potential Electricity Energy Savings (kWh)", 1, - "assessment.assessment_energy_use.energy_savings_e", + "assessment.assessment_results.assessment_energy_use.energy_savings_e", ), ExtraDataColumnPath( "better_energy_savings_fuel", "BETTER Potential Fuel Energy Savings (kWh)", 1, - "assessment.assessment_energy_use.energy_savings_f", + "assessment.assessment_results.assessment_energy_use.energy_savings_f", ), ExtraDataColumnPath( "better_ghg_reductions_electricity", "BETTER Potential Electricity GHG Emissions Reduction (MtCO2e)", 0.001, - "assessment.assessment_energy_use.ghg_reductions_e", + "assessment.assessment_results.assessment_energy_use.ghg_reductions_e", ), ExtraDataColumnPath( "better_ghg_reductions_fuel", "BETTER Potential Fuel GHG Emissions Reduction (MtCO2e)", 0.001, - "assessment.assessment_energy_use.ghg_reductions_f", + "assessment.assessment_results.assessment_energy_use.ghg_reductions_f", ), ExtraDataColumnPath( # we will manually add this to the data later (it's not part of BETTER's results) diff --git a/seed/analysis_pipelines/utils.py b/seed/analysis_pipelines/utils.py index 15289e4a0d..888c6ad5e9 100644 --- a/seed/analysis_pipelines/utils.py +++ b/seed/analysis_pipelines/utils.py @@ -22,8 +22,18 @@ def get_json_path(json_path, data): json_path = json_path.split(".") result = data for key in json_path: - result = result.get(key, {}) - + if isinstance(result, dict): + result = result.get(key, {}) + elif isinstance(result, list): + # check if it's just a list of strings or a list of objects + if any(isinstance(val, dict) for val in result): + # it's a list of dicts, keep as before + result = result.get(key, {}) + # it's a list of values, modify (mostly for new ee_measures syntax) + elif key in result: + result = 1 + else: + result = 0 if isinstance(result, dict) and not result: # path was probably not valid in the data... return None diff --git a/seed/models/analyses.py b/seed/models/analyses.py index 66ca21d00f..16678b91ab 100644 --- a/seed/models/analyses.py +++ b/seed/models/analyses.py @@ -119,12 +119,12 @@ def get_highlights(self, property_id=None): { "name": ["Potential Cost Savings (USD)"], "value_template": ["${json_value:,.2f}"], - "json_path": ["assessment.assessment_energy_use.cost_savings_combined"], + "json_path": ["assessment.assessment_results.assessment_energy_use.cost_savings_combined"], }, { "name": ["Potential Energy Savings"], "value_template": ["{json_value:,.2f} kWh"], - "json_path": ["assessment.assessment_energy_use.energy_savings_combined"], + "json_path": ["assessment.assessment_results.assessment_energy_use.energy_savings_combined"], }, { "name": ["BETTER Inverse Model R^2 (Electricity", "Fossil Fuel)"],