def create_mock_containers_with_results(ureg): mock_containers = create_mock_bldg_containers(ureg) prev_sim_year = 2015 kwh_year=ureg.kW*ureg.h/ureg.year energy_demand_res = EnergyDemandSimulationResults( tot_dhw_demand=10000 * kwh_year, tot_heating_demand=180000 * kwh_year, tot_electricity_demand=80000 * kwh_year, tot_cooling_demand=0 * kwh_year, total_floor_area=250*ureg.m**2) for c in mock_containers.values(): c.get_bldg_model().site.simulation_year = prev_sim_year c.set_energy_demand_sim_res(energy_demand_res) c.set_retrofit_log(RetrofitLog()) retrofit_log_fid3 = RetrofitLog() retrofit_log_fid3.log_retrofit_measure(3, BuildingElement.WALL, None, prev_sim_year, None, None, None, None, "old_wall_constr", "new_wall_constr") mock_containers[3].set_retrofit_log(retrofit_log_fid3) energy_demand_low = EnergyDemandSimulationResults( tot_dhw_demand=5000 * kwh_year, tot_heating_demand=60000 * kwh_year, tot_electricity_demand=5000 * kwh_year, tot_cooling_demand=0 * kwh_year, total_floor_area=250*ureg.m**2) mock_containers[4].set_energy_demand_sim_res(energy_demand_low) return mock_containers
def test_retrofitted_in(): ureg = cesarp.common.init_unit_registry() myLogger = RetrofitLog() # empty log assert myLogger.was_construction_retrofitted_in(2022) == False myLogger.log_retrofit_measure( bldg_fid=22, bldg_element=BuildingElement.ROOF, retrofitted_area=100 * ureg.m**2, year_of_retrofit=2020, retrofit_target="SIA380_MIN", costs=200 * ureg.CHF / ureg.m**2, non_renewable_pen=0.02 * ureg.MJ * ureg.Oileq / ureg.m**2, co2_emission=3 * ureg.kg * ureg.CO2eq / ureg.m**2, old_construction_name="bad_construction", new_construction_name="good_construction", ) assert myLogger.was_construction_retrofitted_in(2022) == False assert myLogger.was_construction_retrofitted_in(2020) == True assert myLogger.was_construction_retrofitted_in(year=2022, bldg_fid=22) == False assert myLogger.was_construction_retrofitted_in(year=2020, bldg_fid=22) == True assert myLogger.was_construction_retrofitted_in(year=2020, bldg_fid=33) == False
def __init__(self, ureg: pint.UnitRegistry, custom_config: Dict[str, Any] = {}): """ Initialize. See set_year_of_retrofit() and set_bldgs_elems_to_retrofit() for further configuration options. :param ureg: pint unit registry """ self._ureg = ureg self._year_of_retrofit: Optional[int] = None self._bldg_elems_to_retrofit = self._retrofittable_bldg_elems self._logger = logging.getLogger(__name__) self._cfg = cesarp.common.load_config_for_package( _default_config_file, __package__, custom_config) # can be changed after initialization if needed... self.construction_retrofitter: ConstructionRetrofitterProtocol = GraphDBFacade( self._ureg, custom_config).get_graph_construction_retrofitter() # can be changed after initialization if needed... self.costs: ConstructionRetrofitCostProtocol = ConstructionRetrofitCosts( ureg=ureg) self.emissions: ConstructionRetrofitEmbodiedEmissionsProtocol = RetrofitEmbodiedEmissions( ureg) # log is not written to disk or anything, it is intended that the caller gets the log after all retrofit # operations are done self.retrofit_log = RetrofitLog() # methods must return the area in m2 (as float, not as pint.Quantity) self.area_calc_methods = { BuildingElement.WALL: area_calculator.calc_wall_area_without_window_glass_area, BuildingElement.ROOF: area_calculator.calc_roof_area, BuildingElement.GROUNDFLOOR: area_calculator.calc_groundfloor_area, } self.area_calc_win_glass_method = area_calculator.calc_window_glass_area self.area_calc_win_frame_method = area_calculator.calc_window_frame_area
class ConstrRetrofitterMock: retrofit_log = RetrofitLog() def set_year_of_retrofit(self, year): pass def set_bldg_elems_to_retrofit(self, bldg_elems): pass def retrofit_bldg_construction(self, bldg_fid: int, bldg_construction: BuildingConstruction, bldg_shape_detailed: BldgShapeDetailed): pass def reset_retrofit_log(self): pass
def run(self) -> pd.DataFrame: """ Do run the project with retrofitting. It does create the retrofit scenarios for each of retrofit periods you passed in the weather files dictionary in the initilization. :return: annual results for all retrofit scenarios. :rtype: pd.DataFrame """ retrofit_period_years = self._retrofitter.get_retrofit_periods() # create base scenario self._current_sim_period_year = retrofit_period_years[0] base_weather_file = self._weather_per_period[self._current_sim_period_year] base_scenario_config = { "MANAGER": {"SINGLE_SITE": {"ACTIVE": True, "WEATHER_FILE": base_weather_file}, "SITE_PER_CH_COMMUNITY": {"ACTIVE": False}}, "SITE": {"SIMULATION_YEAR": self._current_sim_period_year}, } self._proj_mgr.create_scenario(str(self._current_sim_period_year), base_scenario_config) prev_sz_name = str(self._current_sim_period_year) for bldg_c in self._proj_mgr.get_sim_mgr_for(prev_sz_name).bldg_containers.values(): # initialize empty retrofit logs because in retrofit method log is uesed to lookup for previous retrofits... bldg_c.set_retrofit_log(RetrofitLog()) # retrofit needs energy demand from previous simulation to calculate emissions, thus run simulation for # before going to the next retrofit period self._proj_mgr.run_not_simulated_scenarios() # create and run scenario for each retrofit period for sim_year in retrofit_period_years[1:]: sz_name = str(sim_year) self._current_sim_period_year = sim_year self._proj_mgr.derive_scenario(prev_sz_name, sz_name, self._change_sim_year_for_model) self._retrofitter.retrofit_site( sim_year, self._proj_mgr.get_sim_mgr_for(sz_name).bldg_containers, self._proj_mgr.get_sim_mgr_for(prev_sz_name).bldg_containers, ) self._proj_mgr.run_not_simulated_scenarios() prev_sz_name = sz_name self._retrofitter.get_retrofit_log().save(str(self._proj_base_path / Path(RETROFIT_LOG_NAME))) return self._proj_mgr.collect_all_scenario_summaries( metadata_descr_project_summary=f"Retrofit sceanarios created with {__name__}. Simulation year and weather defined in configuarion is not used! " f"following weather files were used: {self._weather_per_period}. For other " f"details please have a look in the metadata of each simulation period" )
def test_basic_log(): ureg = cesarp.common.init_unit_registry() myLogger = RetrofitLog() myLogger.log_retrofit_measure( bldg_fid=33, bldg_element=BuildingElement.WINDOW, retrofitted_area=200 * ureg.m**2, year_of_retrofit=2020, retrofit_target="SIA380_MIN", costs=200 * ureg.CHF / ureg.m**2, non_renewable_pen=0.02 * ureg.MJ * ureg.Oileq / ureg.m**2, co2_emission=3 * ureg.kg * ureg.CO2eq / ureg.m**2, old_construction_name="bad_construction", new_construction_name="good_construction", ) assert (len(myLogger.my_log_entries) == 1) assert (len(myLogger.convert_to_df()) == 1) the_log = "test_retrofit_log.csv" myLogger.save(the_log) assert os.path.isfile(the_log) os.remove(the_log)
def __init__(self, ureg: pint.UnitRegistry, custom_config: Dict[str, Any] = {}): """ :param ureg: :param year_of_retrofit: must match one of cesarp.energy_strategy config "TIME_PERIODS" :param custom_config: """ self._cfg = cesarp.common.load_config_for_package( _default_config_file, __package__, custom_config) self._op_emissions_calculator = OperationalEmissionsAndCosts( ureg, custom_config) self._energy_target = EnergyTargetLookup( self._cfg["ENERGY_TARGETS_LOOKUP_FILE"], ureg) self._supported_bldg_types = [BldgType.MFH, BldgType.SFH] self._retrofit_rates_accessor: RetrofitRates = RetrofitRates( custom_config) self._per_elem_construction_retrofitter = BuildingElementsRetrofitter( ureg) self._retrofit_categories_last_run: Optional[Dict[ BldgType, List[RetrofitCategoryDetails]]] = None self._all_buildings_retrofit_log: RetrofitLog = RetrofitLog() self._logger = logging.getLogger(__name__)
class EnergyPerspective2050BldgElementsRetrofitter: """ Implements constructional retrofit as outlined in the Master Thesis of Jonas Landolt. For Details about the retrofit strategy please check chapter 5.1.6 in CESAR-Tool_Documentation.pdf This class contains the logic to select the buildings for which a retrofit measure should be applied and in case partial retrofit is activated (configuration parameter DO_PARTIAL_RETROFIT) also which building elements shall be retrofitted, e.g. only Roof and Wall or Windows only. In case partial retrofit is not on, all buildings which get a retrofit are fully retrofitted, meaning Roof, Wall, Window, Groundfloor are retrofitted. To carry out the retrofits the cesarp.retrofit.BuildingElementsRetrofitter is used. Retrofit strategy only applied so far for residential buildings! Emission and costs for retrofit can only be calculated for rectangualr footprint shapes, as the area of the groundfloor and roof area are required and calculating the area of polygon area is not yet implemented (e.g. one could use shaply or another lib to do that). In case of non-rectangular footprint shape, retrofit emission and costs for roof and groundfloor are set to None in RetrofitLog The percentages of full and partial retrofit depending on building age and retrofit year/period are configurable through input files and are located in the cesarp.energy_strategy, as they relate to the energy strategy. Taking any retrofit shares that could not be "fulfilled" in one retrofit period to the next is not yet implemented, but was in the Matlab version. See gitlab Issue #109. If the site does not have buildings for a certain building type and age class used in the retrofit rate definition, that retrofit rate get's ignored. For example, if the site defines no single family home (SFH) buildings with year_of_construction in the range of 2001-2005, the assigned retrofit rates for age class 2001-2005 are ignored. """ def __init__(self, ureg: pint.UnitRegistry, custom_config: Dict[str, Any] = {}): """ :param ureg: :param year_of_retrofit: must match one of cesarp.energy_strategy config "TIME_PERIODS" :param custom_config: """ self._cfg = cesarp.common.load_config_for_package( _default_config_file, __package__, custom_config) self._op_emissions_calculator = OperationalEmissionsAndCosts( ureg, custom_config) self._energy_target = EnergyTargetLookup( self._cfg["ENERGY_TARGETS_LOOKUP_FILE"], ureg) self._supported_bldg_types = [BldgType.MFH, BldgType.SFH] self._retrofit_rates_accessor: RetrofitRates = RetrofitRates( custom_config) self._per_elem_construction_retrofitter = BuildingElementsRetrofitter( ureg) self._retrofit_categories_last_run: Optional[Dict[ BldgType, List[RetrofitCategoryDetails]]] = None self._all_buildings_retrofit_log: RetrofitLog = RetrofitLog() self._logger = logging.getLogger(__name__) def retrofit_site( self, year_of_retrofit: int, bldg_containers_current: Dict[int, BuildingContainer], bldg_containers_prev_period: Dict[int, BuildingContainer], ) -> RetrofitLog: """ Retrofit building construction. Buildings meeting one of the following criteria do not get retrofitted: - Operational Emissions below target - Building got retrofitted As for the operational emissions calculation, dhw and heating energy carrier from current building model are used, make sure that if your retrofit strategy involves system retrofit to perform the system retrofit before calling this method. :param bldg_containers_current: dictionary with key fid, value the building container of the bldg for the current retrofit period, no simulation results expected :param bldg_containers_prev_period: dictionary with key fid, value the building container of the bldg for the previos retrofit period, should include simulation results and retrofit log :return: retrofit log for including retrofit measures for all buildings """ retrofit_categories_by_bt = self._define_nr_of_bldgs_to_retrofit( year_of_retrofit, bldg_containers_current.values()) self._all_buildings_retrofit_log = RetrofitLog() self._per_elem_construction_retrofitter.set_year_of_retrofit( year_of_retrofit) for fid, container_current in bldg_containers_current.items(): self._per_elem_construction_retrofitter.reset_retrofit_log() model_current = container_current.get_bldg_model() if (model_current.bldg_construction.installation_characteristics. e_carrier_dhw is not None and model_current.bldg_construction. installation_characteristics.e_carrier_heating is not None): container_prev_sim = bldg_containers_prev_period[fid] energy_demand_last_period = container_prev_sim.get_energy_demand_sim_res( ) emission_target_reached = self._check_emissions_below_target( energy_demand_last_period, model_current.bldg_construction. installation_characteristics.e_carrier_dhw, model_current.bldg_construction. installation_characteristics.e_carrier_heating, model_current.site.simulation_year, ) retrofitted_in_last_period = self._check_retrofitted_in_last_period( container_prev_sim.get_bldg_model().site.simulation_year, container_prev_sim.get_retrofit_log()) if not emission_target_reached and not retrofitted_in_last_period: for ret_category in retrofit_categories_by_bt[ model_current.bldg_type]: if ret_category.constr_ac.isInClass( model_current.year_of_construction): if not ret_category.is_target_nr_of_bldgs_reached( ): self._do_retrofit( model_current, ret_category.bldg_elems_to_retrofit) ret_category.increment_retrofitted_cnt() break if container_current.has_retrofit_log(): container_current.get_retrofit_log().append_log( self._per_elem_construction_retrofitter.retrofit_log) else: container_current.set_retrofit_log( self._per_elem_construction_retrofitter.retrofit_log) self._all_buildings_retrofit_log.append_log( self._per_elem_construction_retrofitter.retrofit_log) else: self._logger.warn( f"energy carrier for DHW and Heating not available for {fid}, thus that building was NOT considered for retrofit" ) return self._all_buildings_retrofit_log def get_retrofit_periods(self): return self._retrofit_rates_accessor.time_periods def get_retrofit_log(self): return self._all_buildings_retrofit_log def reset_retrofit_log(self): return self._per_elem_construction_retrofitter.reset_retrofit_log() def _define_nr_of_bldgs_to_retrofit( self, year_of_retrofit: int, bldg_containers: Iterable[BuildingContainer] ) -> Dict[BldgType, List[RetrofitCategoryDetails]]: """ :param year_of_retrofit: year of this retrofit period :param nr_of_bldgs_on_site: :return: Dict[Building Type, Dict[Construction Age Bucket, List[Tuple(List[Building Elements to Retrofit], nr of bldgs to retrofit, nr of bldgs retrofitted)]]] Building Type: one of the self._supported_bldg_tpyes Construction Age Bucket: age classes as used for the retrofit rate definition in cesarp.energy_strategy.RetrofitRates. Note: do not match with age class used for constructional archetypes Building Elements to Retrofit: Building elements to be retrofitted, for full retrofit this includes all building elements, thus only one Tuple will be in the List. If partial retrofit is active, the list may contain up to 15 entries, for each possible combination of building elements. nr of bldgs to retrofit: number of buildings, according to retrofit rate and total buildings of that type and with it's construction year in the age class, that should get a retrofit for the listed building elements nr of bldgs retrofitte: always 0 when returned by this function, can be used to track how many buildings got that retrofit measure """ retrofit_categories_by_bt = {} age_classes_used_for_ret_rates = self._retrofit_rates_accessor.get_retrofit_rates_age_classes( ) nr_of_bldgs_on_site = self._get_nr_of_bldg_per_bldg_type_and_ac( bldg_containers, age_classes_used_for_ret_rates) for bt in self._supported_bldg_types: if self._cfg["DO_PARTIAL_RETROFIT"]: partial_retrofit_rates = self._retrofit_rates_accessor.get_partial_retrofit_rates_per_age_class( sim_year=year_of_retrofit, bldg_type=bt) ret_cats = [] for ac, rate_per_bldg_elems in partial_retrofit_rates.items(): for (bldg_elems, ret_rate) in rate_per_bldg_elems: target_num_bldgs = int( round(ret_rate * nr_of_bldgs_on_site[bt][ac], ndigits=0)) ret_cats.append( RetrofitCategoryDetails( bldg_type=bt, constr_ac=ac, bldg_elems_to_retrofit=bldg_elems, target_nr_of_bldgs_to_retrofit=target_num_bldgs, )) retrofit_categories_by_bt[bt] = ret_cats else: retrofit_rates = self._retrofit_rates_accessor.get_full_retrofit_rate_per_age_class( sim_year=year_of_retrofit, bldg_type=bt) full_retrofit_elems = [ BuildingElement.ROOF, BuildingElement.WINDOW, BuildingElement.WALL, BuildingElement.GROUNDFLOOR, ] ret_per_ac = [] for ac, ret_rate in retrofit_rates.items(): target_num_bldgs = int( round(ret_rate * nr_of_bldgs_on_site[bt][ac], ndigits=0)) ret_per_ac.append( RetrofitCategoryDetails( bldg_type=bt, constr_ac=ac, bldg_elems_to_retrofit=full_retrofit_elems, target_nr_of_bldgs_to_retrofit=target_num_bldgs, )) retrofit_categories_by_bt[bt] = ret_per_ac self._retrofit_categories_last_run = retrofit_categories_by_bt return retrofit_categories_by_bt def _get_nr_of_bldg_per_bldg_type_and_ac( self, bldg_containers: Iterable[BuildingContainer], age_buckets: List[AgeClass] ) -> Dict[BldgType, Dict[AgeClass, int]]: nr_of_bldgs = { bt: {ac: 0 for ac in age_buckets} for bt in self._supported_bldg_types } for bldg_c in bldg_containers: model = bldg_c.get_bldg_model() for bucket in age_buckets: if bucket.isInClass(model.year_of_construction): if model.bldg_type not in self._supported_bldg_types: raise Exception( f"{__file__} does not support bldg type {model.bldg_type} of bldg fid {model.fid}" ) nr_of_bldgs[model.bldg_type][bucket] += 1 break return nr_of_bldgs def _do_retrofit(self, model: BuildingModel, elems_to_retrofit: List[BuildingElement]) -> None: self._per_elem_construction_retrofitter.set_bldg_elems_to_retrofit( elems_to_retrofit) self._per_elem_construction_retrofitter.retrofit_bldg_construction( model.fid, model.bldg_construction, model.bldg_shape) def _check_emissions_below_target( self, energy_demand: EnergyDemandSimulationResults, dhw_carrier: EnergySource, heating_carrier: EnergySource, year_for_emission_calc, ): """ Returns True if operational costs and emissions are below the required SIA target Translated from Matlab CESAR script constret_decision.m """ op_emissions_costs = self._op_emissions_calculator.get_operational_emissions_and_costs( specific_dhw_demand=energy_demand.specific_dhw_demand, total_dhw_demand=energy_demand.tot_dhw_demand, dhw_carrier=dhw_carrier, specific_heating_demand=energy_demand.specific_heating_demand, total_heating_demand=energy_demand.tot_dhw_demand, heating_carrier=heating_carrier, specific_electricity_demand=energy_demand. specific_electricity_demand, total_electricity_demand=energy_demand.tot_electricity_demand, sim_year=year_for_emission_calc, ) bldg_op_pen = op_emissions_costs.total_pen.to( self._energy_target.pen_unit) bldg_op_co2 = op_emissions_costs.total_co2_emission.to( self._energy_target.co2_unit) if bldg_op_pen.m <= self._energy_target.get_resi_op_pen_target( new_bldg=False ).m and bldg_op_co2.m <= self._energy_target.get_resi_op_co2_target( new_bldg=False).m: return True return False def _check_retrofitted_in_last_period(self, last_period_year: int, last_sim_retrofit: RetrofitLog): # TODO should it really only look at the last year? (see issue 109 on gitlab) return last_sim_retrofit.was_construction_retrofitted_in( last_period_year)
def _check_retrofitted_in_last_period(self, last_period_year: int, last_sim_retrofit: RetrofitLog): # TODO should it really only look at the last year? (see issue 109 on gitlab) return last_sim_retrofit.was_construction_retrofitted_in( last_period_year)
def retrofit_site( self, year_of_retrofit: int, bldg_containers_current: Dict[int, BuildingContainer], bldg_containers_prev_period: Dict[int, BuildingContainer], ) -> RetrofitLog: """ Retrofit building construction. Buildings meeting one of the following criteria do not get retrofitted: - Operational Emissions below target - Building got retrofitted As for the operational emissions calculation, dhw and heating energy carrier from current building model are used, make sure that if your retrofit strategy involves system retrofit to perform the system retrofit before calling this method. :param bldg_containers_current: dictionary with key fid, value the building container of the bldg for the current retrofit period, no simulation results expected :param bldg_containers_prev_period: dictionary with key fid, value the building container of the bldg for the previos retrofit period, should include simulation results and retrofit log :return: retrofit log for including retrofit measures for all buildings """ retrofit_categories_by_bt = self._define_nr_of_bldgs_to_retrofit( year_of_retrofit, bldg_containers_current.values()) self._all_buildings_retrofit_log = RetrofitLog() self._per_elem_construction_retrofitter.set_year_of_retrofit( year_of_retrofit) for fid, container_current in bldg_containers_current.items(): self._per_elem_construction_retrofitter.reset_retrofit_log() model_current = container_current.get_bldg_model() if (model_current.bldg_construction.installation_characteristics. e_carrier_dhw is not None and model_current.bldg_construction. installation_characteristics.e_carrier_heating is not None): container_prev_sim = bldg_containers_prev_period[fid] energy_demand_last_period = container_prev_sim.get_energy_demand_sim_res( ) emission_target_reached = self._check_emissions_below_target( energy_demand_last_period, model_current.bldg_construction. installation_characteristics.e_carrier_dhw, model_current.bldg_construction. installation_characteristics.e_carrier_heating, model_current.site.simulation_year, ) retrofitted_in_last_period = self._check_retrofitted_in_last_period( container_prev_sim.get_bldg_model().site.simulation_year, container_prev_sim.get_retrofit_log()) if not emission_target_reached and not retrofitted_in_last_period: for ret_category in retrofit_categories_by_bt[ model_current.bldg_type]: if ret_category.constr_ac.isInClass( model_current.year_of_construction): if not ret_category.is_target_nr_of_bldgs_reached( ): self._do_retrofit( model_current, ret_category.bldg_elems_to_retrofit) ret_category.increment_retrofitted_cnt() break if container_current.has_retrofit_log(): container_current.get_retrofit_log().append_log( self._per_elem_construction_retrofitter.retrofit_log) else: container_current.set_retrofit_log( self._per_elem_construction_retrofitter.retrofit_log) self._all_buildings_retrofit_log.append_log( self._per_elem_construction_retrofitter.retrofit_log) else: self._logger.warn( f"energy carrier for DHW and Heating not available for {fid}, thus that building was NOT considered for retrofit" ) return self._all_buildings_retrofit_log
class BuildingElementsRetrofitter: """ Handles retrofit for all or part of the building elements. In case of window retrofitting the infiltration rate is changed to the value set in configuration (INFILRATION_RATE_AFTER_WINDOW_RETROFIT), the actual window construction used for retrofitting has no influence on that value. Depending on the retrofit target (initialization parameter retrofit_target) using the cesarp.retrofit.ConstructionRetrofitter the retrofited consruction is assigend. Furthermore, costs for retrofit and embodied emissions (non-renewable PEN & CO2) are calculated and saved in the retrofit log. All retrofit measures are logged, which is accessible as member "retrofit_log" as instance of cesarp.retrofit.RetrofitLog class. It includes the embodied costs and emissions. Depending on your needs, you can reset the log by calling reset_retrofit_log() before calling retrofit_bldg_construction(....) and retrieving the log right afterwards, which gives you the log only for that one building. Otherwise, log entries for the different buildings are appended (log entries contain building fid). """ _retrofittable_bldg_elems = [ BuildingElement.ROOF, BuildingElement.WALL, BuildingElement.GROUNDFLOOR, BuildingElement.WINDOW, ] def __init__(self, ureg: pint.UnitRegistry, custom_config: Dict[str, Any] = {}): """ Initialize. See set_year_of_retrofit() and set_bldgs_elems_to_retrofit() for further configuration options. :param ureg: pint unit registry """ self._ureg = ureg self._year_of_retrofit: Optional[int] = None self._bldg_elems_to_retrofit = self._retrofittable_bldg_elems self._logger = logging.getLogger(__name__) self._cfg = cesarp.common.load_config_for_package( _default_config_file, __package__, custom_config) # can be changed after initialization if needed... self.construction_retrofitter: ConstructionRetrofitterProtocol = GraphDBFacade( self._ureg, custom_config).get_graph_construction_retrofitter() # can be changed after initialization if needed... self.costs: ConstructionRetrofitCostProtocol = ConstructionRetrofitCosts( ureg=ureg) self.emissions: ConstructionRetrofitEmbodiedEmissionsProtocol = RetrofitEmbodiedEmissions( ureg) # log is not written to disk or anything, it is intended that the caller gets the log after all retrofit # operations are done self.retrofit_log = RetrofitLog() # methods must return the area in m2 (as float, not as pint.Quantity) self.area_calc_methods = { BuildingElement.WALL: area_calculator.calc_wall_area_without_window_glass_area, BuildingElement.ROOF: area_calculator.calc_roof_area, BuildingElement.GROUNDFLOOR: area_calculator.calc_groundfloor_area, } self.area_calc_win_glass_method = area_calculator.calc_window_glass_area self.area_calc_win_frame_method = area_calculator.calc_window_frame_area def reset_retrofit_log(self): self.retrofit_log = RetrofitLog() def save_retrofit_log(self, filepath: str): self.retrofit_log.save(filepath) def get_retrofit_log_as_df(self) -> pd.DataFrame: return self.retrofit_log.convert_to_df() def set_year_of_retrofit(self, year_of_retrofit: int): self._year_of_retrofit = year_of_retrofit def set_bldg_elems_to_retrofit( self, bldg_elems_to_retrofit: List[BuildingElement]): self._bldg_elems_to_retrofit = bldg_elems_to_retrofit def retrofit_bldg_construction(self, bldg_fid: int, bldg_construction: BuildingConstruction, bldg_shape_detailed: BldgShapeDetailed): """ Modifies building construction in place according to set parameters in constructor. :param bldg_fid: currently only used for logging :param bldg_construction: bldg construction model object :return: nothing, bldg_construction is modified in-place """ for bldg_elem in self._bldg_elems_to_retrofit: current_construction = bldg_construction.get_construction_for_bldg_elem( bldg_elem) retrofitted_construction: Union[Construction, WindowConstruction] try: if bldg_elem == BuildingElement.WINDOW: retrofitted_construction = self.construction_retrofitter.get_retrofitted_window( current_construction) bldg_construction.infiltration_rate = self._ureg( self._cfg["INFILRATION_RATE_AFTER_WINDOW_RETROFIT"]) else: retrofitted_construction = self.construction_retrofitter.get_retrofitted_construction( current_construction) except KeyError: self._logger.warning( f"bldg_fid {bldg_fid}: no retrofit construction found for bldg elem {bldg_elem} " f"with current construction {current_construction.name}. no retrofit is applied." ) continue bldg_construction.set_construction_for_bldg_elem( bldg_elem, retrofitted_construction) try: (area_for_elem, co2_emission, costs, pen) = self._get_emission_and_costs(bldg_elem, bldg_shape_detailed, retrofitted_construction) except CesarGeometryException as cge: self._logger.warning( f"no emission and costs calculated for fid {bldg_fid}, element {bldg_elem.name}", exc_info=cge) area_for_elem, co2_emission, costs, pen = None, None, None, None self.retrofit_log.log_retrofit_measure( bldg_fid=bldg_fid, bldg_element=bldg_elem, retrofitted_area=area_for_elem, year_of_retrofit=self._year_of_retrofit, retrofit_target=self.construction_retrofitter. get_retrofit_target_info(), costs=costs, non_renewable_pen=pen, co2_emission=co2_emission, old_construction_name=current_construction.name, new_construction_name=retrofitted_construction.name, ) def _get_emission_and_costs(self, bldg_elem, bldg_shape_detailed, retrofitted_constr): """ Calculates retrofit emission and costs for the given building element and building shape. """ if bldg_elem == BuildingElement.WINDOW: # glass and frame area for all windows of building win_glass_area = self.area_calc_win_glass_method( bldg_shape_detailed) * self._ureg.m**2 win_frame_area = self.area_calc_win_frame_method( bldg_shape_detailed) * self._ureg.m**2 costs = self.costs.get_costs_for_window_retrofit( retrofitted_constr) * win_glass_area co2_emission = ( self.emissions.get_win_ret_glass_emb_co2(retrofitted_constr) * win_glass_area + self.emissions.get_win_ret_frame_emb_co2(retrofitted_constr) * win_frame_area) pen = (self.emissions.get_win_ret_glass_emb_non_renewable_pen( retrofitted_constr) * win_glass_area + self.emissions.get_win_ret_frame_emb_non_renewable_pen( retrofitted_constr) * win_frame_area) elem_area = win_glass_area + win_frame_area else: # area e.g. for all walls of building elem_area = self.area_calc_methods[bldg_elem]( bldg_shape_detailed) * self._ureg.m**2 costs = self.costs.get_costs_for_construction_retrofit( retrofitted_constr) * elem_area co2_emission = self.emissions.get_constr_ret_emb_co2( retrofitted_constr) * elem_area pen = self.emissions.get_constr_ret_emb_non_renewable_pen( retrofitted_constr) * elem_area return elem_area, co2_emission, costs, pen
def reset_retrofit_log(self): self.retrofit_log = RetrofitLog()