diff --git a/conf/hermes.conf b/conf/hermes.conf index 189868ec06cb2e9817c0ca24b5a7f8898a447a33..37fd0691eb2301f81b19bb86554c602ee3dfce1e 100755 --- a/conf/hermes.conf +++ b/conf/hermes.conf @@ -330,6 +330,7 @@ traffic_speciation_profile_tyre = /profiles/speciation/traffic/tyre_b traffic_speciation_profile_road = /profiles/speciation/traffic/road_base.csv traffic_speciation_profile_brake = /profiles/speciation/traffic/brake_base.csv traffic_speciation_profile_resuspension = /profiles/speciation/traffic/resuspension_base.csv +traffic_scenario = /traffic/shp_ZPE [TRAFFIC AREA SECTOR] traffic_area_pollutants = nox_no2,nmvoc,so2,co,nh3,pm10,pm25 diff --git a/hermesv3_bu/config/config.py b/hermesv3_bu/config/config.py index c3cde1675b942e7c6b517cbf51a881c59bbdd9fe..9e6e07a08831c81fdc8f80d91316a912a4ab8350 100755 --- a/hermesv3_bu/config/config.py +++ b/hermesv3_bu/config/config.py @@ -627,6 +627,8 @@ class Config(ArgParser): p.add_argument('--traffic_speciation_profile_resuspension', required=False, help="Defines the path to the CSV file that contains the speciation profiles for the " + "resuspension emissions.") + p.add_argument('--traffic_scenario', required=False, default=None, + help="Defines the path to the shapefile that contains the traffic scenario by input pollutant.") # ***** TRAFFIC AREA SECTOR ***** p.add_argument('--traffic_area_pollutants', required=False, diff --git a/hermesv3_bu/io_server/io_shapefile.py b/hermesv3_bu/io_server/io_shapefile.py index 59ece649cf221a86df7b49557988fe4114f3affc..bdc397f7040375e05c8810240569c0c85b3c530a 100755 --- a/hermesv3_bu/io_server/io_shapefile.py +++ b/hermesv3_bu/io_server/io_shapefile.py @@ -88,6 +88,33 @@ class IoShapefile(IoServer): return data + def read_shapefile_broadcast(self, path, rank=0, crs=None): + """ + The master process reads the shapefile and broadcast it. + + :param path: Path to the shapefile + :type path: str + + :param rank: Master rank + :type rank: int + + :param crs: Projection desired. + :type crs: None, str + + :return: Shapefile + :rtype: GeoDataFrame + """ + if self.comm.Get_rank() == rank: + data = self.read_shapefile_serial(path) + if crs is not None: + data = data.to_crs(crs) + else: + data = None + + data = self.comm.bcast(data, root=0) + + return data + def split_shapefile(self, data, rank=0): """ diff --git a/hermesv3_bu/sectors/sector_manager.py b/hermesv3_bu/sectors/sector_manager.py index b726d3229b1de9baf3e42333a15446b68c3298d2..575730a6a150eb3c9f30855a7ad815235f3d8d6d 100755 --- a/hermesv3_bu/sectors/sector_manager.py +++ b/hermesv3_bu/sectors/sector_manager.py @@ -188,7 +188,7 @@ class SectorManager(object): arguments.temperature_hourly_files_path, arguments.output_dir, arguments.molecular_weights, arguments.resuspension_correction, arguments.precipitation_files_path, arguments.do_hot, arguments.do_cold, arguments.do_tyre_wear, arguments.do_brake_wear, arguments.do_road_wear, - arguments.do_resuspension, arguments.write_rline) + arguments.do_resuspension, arguments.write_rline, arguments.traffic_scenario) elif sector == 'traffic_area' and comm_world.Get_rank() in sector_procs: from hermesv3_bu.sectors.traffic_area_sector import TrafficAreaSector diff --git a/hermesv3_bu/sectors/traffic_sector.py b/hermesv3_bu/sectors/traffic_sector.py index 65a70a2157337db00d782c58fe0177738ae4aaf5..f2060d57aee4de69ac4e537a043c1bfcecfadde0 100755 --- a/hermesv3_bu/sectors/traffic_sector.py +++ b/hermesv3_bu/sectors/traffic_sector.py @@ -17,7 +17,6 @@ from hermesv3_bu.io_server.io_shapefile import IoShapefile from hermesv3_bu.tools.checker import check_files, error_exit import gc -from memory_profiler import profile from ctypes import cdll, CDLL cdll.LoadLibrary("libc.so.6") libc = CDLL("libc.so.6") @@ -56,7 +55,7 @@ class TrafficSector(Sector): hot_cold_speciation=None, tyre_speciation=None, road_speciation=None, brake_speciation=None, resuspension_speciation=None, temp_common_path=None, output_dir=None, molecular_weights_path=None, resuspension_correction=True, precipitation_path=None, do_hot=True, do_cold=True, do_tyre_wear=True, - do_brake_wear=True, do_road_wear=True, do_resuspension=True, write_rline=False): + do_brake_wear=True, do_road_wear=True, do_resuspension=True, write_rline=False, traffic_scenario=None): spent_time = timeit.default_timer() logger.write_log('===== TRAFFIC SECTOR =====') @@ -136,6 +135,9 @@ class TrafficSector(Sector): hourly_saturday_profiles_path, hourly_sunday_profiles_path) self.check_profiles() self.expanded = self.expand_road_links() + if traffic_scenario in ['=', '', ' ', 'None']: + traffic_scenario = None + self.scenario = self.get_scenario(traffic_scenario) del self.fleet_compo, self.speed_hourly, self.monthly_profiles, self.weekly_profiles, self.hourly_profiles libc.malloc_trim(0) @@ -167,6 +169,30 @@ class TrafficSector(Sector): libc.malloc_trim(0) gc.collect() + def get_scenario(self, scenario_path): + if scenario_path in ['', 'None']: + scenario_path = None + if scenario_path is not None and not os.path.exists(scenario_path): + msg = "ERROR!!! " + msg += "Traffic scenario file '{0}' not found!".format(scenario_path) + error_exit(msg) + + if scenario_path is not None: + self.logger.write_log('\t\tGetting emission scenario', message_level=2) + scenario_shp = IoShapefile(self.comm).read_shapefile_broadcast(scenario_path, crs=self.road_links.crs) + + scenario = gpd.sjoin(GeoDataFrame(index=self.road_links.index, geometry=self.road_links.geometry.centroid, + crs=self.road_links.crs), scenario_shp, how='left') + scenario = scenario.loc[:, scenario_shp.columns] + scenario = pd.DataFrame(scenario.drop(columns='geometry'), index=pd.Index(scenario.index, name='Link_ID')) + + scenario.fillna(1, inplace=True) + + else: + scenario = None + + return scenario + def check_profiles(self): spent_time = timeit.default_timer() # Checking speed profiles IDs @@ -1356,6 +1382,18 @@ class TrafficSector(Sector): self.logger.write_time_log('TrafficSector', 'speciate_traffic', timeit.default_timer() - spent_time) return df_out + def apply_scenario(self, emissions): + emissions.index = emissions.index.set_levels(emissions.index.levels[0].astype(int), level=0) + + self.logger.write_log('\t\tApplying emission scenario', message_level=2) + emis_aux = emissions.join(self.scenario, on='Link_ID', rsuffix='_f') + + for pollutant in self.scenario.columns: + if pollutant in emissions.columns: + self.logger.write_log('\t\t\tApplying emission scenario for {0}'.format(pollutant), message_level=3) + emissions.loc[emis_aux.index, pollutant] *= emis_aux.loc[:, '{0}_f'.format(pollutant)] + return emissions + def calculate_emissions(self): spent_time = timeit.default_timer() self.logger.write_log('\tCalculating Road traffic emissions', message_level=1) @@ -1419,6 +1457,9 @@ class TrafficSector(Sector): libc.malloc_trim(0) df_accum.set_index(['Link_ID', 'tstep'], inplace=True) + if self.scenario is not None: + df_accum = self.apply_scenario(df_accum) + if self.write_rline: self.write_rline_output(df_accum.copy()) self.logger.write_log('\t\tRoad link emissions to grid.', message_level=2)