From 6618b9c06d9084ea8c6b9da1941b1e64ce4e0e68 Mon Sep 17 00:00:00 2001 From: Ted Wong Date: Sat, 14 Dec 2024 16:03:10 -0500 Subject: [PATCH 1/7] Create cams_ghg.py --- city_metrix/layers/cams_ghg.py | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 city_metrix/layers/cams_ghg.py diff --git a/city_metrix/layers/cams_ghg.py b/city_metrix/layers/cams_ghg.py new file mode 100644 index 0000000..9271d4d --- /dev/null +++ b/city_metrix/layers/cams_ghg.py @@ -0,0 +1,78 @@ +import xarray as xr +import ee + +from .layer import Layer + +class CamsGhg(Layer): + # Returned units: metric tonnes of GHG species or tonnes CO2e + + GWP = { + 'co2': 1 # by definition + 'ch4': 28, # https://www.ipcc.ch/site/assets/uploads/2018/02/WG1AR5_Chapter08_FINAL.pdf + 'chlorinated-hydrocarbons': 400, # Table A2 https://onlinelibrary.wiley.com/doi/pdf/10.1002/0470865172.app2 + 'n2o': 265 # https://www.ipcc.ch/site/assets/uploads/2018/02/WG1AR5_Chapter08_FINAL.pdf + } + SUPPORTED_SPECIES = ['co2', 'ch4', 'n2o', 'chlorinated-hydrocarbons'] + SUPPORTED_YEARS = [2010, 2015, 2020, 2023] + + def __init__(self, bands, species=None, sector='sum', co2e=True, year=2023, **kwargs): + super().__init__(**kwargs) + if species is not None and not species in SUPPORTED_SPECIES: + raise Except(f'Unsupported species: {species}') + if not year in SUPPORTED_YEARS: + raise Except(f'Unsupported year: {year}') + if species is None and co2e==False: + raise Except('If sector is unspecified, all supported species will be summed and co2e must be True.') + if species is None and sector != 'sum': + raise Except('If sector is unspecified, sector must be \"sum.\"') + if species is not None and sector != 'sum': + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}').filter('year', year) + sectors = data_ic.aggregate_array('sector').getInfo() + if not sector in sectors: + raise Except(f'Sector \"{sector}\" not available for {species} in {year}.') + self.species = species # None means all, summed + self.sector = sector + self.co2e = co2e # Want results in CO2e? If so, multiplies by 100-year GWP. + self.year = year # Currently supported: 2010, 2015, 2020, 2023 + + def get_data(self, bbox): + if self.species is not None: + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{self.species}') + data_im = data_ic.filter(ee.Filter.eq('year', self.year)).filter(ee.Filter.eq('sector', self.sector)).first() + scale = data_im.projection().getInfo()['transform'][0] + data_im = data_im.multiply(GWP[self.species]) + if self.co2e: + data_im = data_im.multiply(GWP[self.species]) + data_im = data_im.multiply(1000000) # Tg to tonne + ic = ee.ImageCollection(data_im) + scale = data_im.projection().getInfo()['transform'][0] + ds = xr.open_dataset( + ic, + engine = 'ee', + geometry = bbox, + crs = 'EPSG:4326', + scale = scale + ) + else: # Sum over all species + allrasters_ic = ee.ImageCollection([]) + for species in SUPPORTED_SPECIES[1:]: + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}') + data_im = data_ic.filter(ee.Filter.eq('year', self.year)).filter(ee.Filter.eq('sector', 'sum')).first() + data_im = data_im.multiply(GWP[species]) + data_im = data_im.multiply(1000000) # Tg to tonne + allrasters_ic = summed_rasters.add(data_im) + sum_im = allrasters_ic.sum() + scale = sum_im.projection().getInfo()['transform'][0] + ic = ee.ImageCollection(sum_im) + ds = xr.open_dataset( + ic, + engine = 'ee', + geometry = bbox, + crs = 'EPSG:4326', + scale = scale + ) + ds = ds.transpose('time', 'lat', 'lon') + ds = ds.squeeze() + ds = ds.rio.set_spatial_dims('lon', 'lat') + return ds + \ No newline at end of file From 530a6cd92df9a4a9cbe3279f3f1cf0c5b36fe4aa Mon Sep 17 00:00:00 2001 From: Ted Wong Date: Sat, 14 Dec 2024 16:48:38 -0500 Subject: [PATCH 2/7] define metric --- city_metrix/layers/cams_ghg.py | 2 +- city_metrix/metrics/ghg_emissions.py | 35 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 city_metrix/metrics/ghg_emissions.py diff --git a/city_metrix/layers/cams_ghg.py b/city_metrix/layers/cams_ghg.py index 9271d4d..e1926e5 100644 --- a/city_metrix/layers/cams_ghg.py +++ b/city_metrix/layers/cams_ghg.py @@ -15,7 +15,7 @@ class CamsGhg(Layer): SUPPORTED_SPECIES = ['co2', 'ch4', 'n2o', 'chlorinated-hydrocarbons'] SUPPORTED_YEARS = [2010, 2015, 2020, 2023] - def __init__(self, bands, species=None, sector='sum', co2e=True, year=2023, **kwargs): + def __init__(self, species=None, sector='sum', co2e=True, year=2023, **kwargs): super().__init__(**kwargs) if species is not None and not species in SUPPORTED_SPECIES: raise Except(f'Unsupported species: {species}') diff --git a/city_metrix/metrics/ghg_emissions.py b/city_metrix/metrics/ghg_emissions.py new file mode 100644 index 0000000..ae34557 --- /dev/null +++ b/city_metrix/metrics/ghg_emissions.py @@ -0,0 +1,35 @@ +import geopandas as gpd +import numpy as np +from city_metrix.layers import Layer, CamsGhg + +SUPPORTED_SPECIES = CamsGhg.SUPPORTED_SPECIES +SUPPORTED_YEARS = CamsGhg.SUPPORTED_YEARS + +def ghg_emissions(zones, years=[2023]): + # species is one of 'co2', 'ch4', 'n2o', 'chlorinated-hydrocarbons' + # supported years: 2010, 2015, 2020, 2023 + + for year in years: + if not year in SUPPORTED_YEARS: + raise Exception(f'Unsupported year {year}') + + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}') + zones_copy = zones.copy(deep=True) + + centroids = [zones.iloc[[i]].centroid for i in range(len(zones))] + geoms = [ee.Geometry.Point(c.x[i], c.y[i]) for i, c in enumerate(centroids)] + + for year in years: + year_total = gpd.Series([0] * len(zones)) + year_results = data_ic.filter(ee.Filter.eq('year', year)) + sectors = list(set(year_results.aggregate_array('sector').getInfo())) + sectors.sort() + for sector in sectors: + results = year_results.filter(ee.Filter.eq('sector', sector)).first().reduceRegions(geoms, ee.Reducer.mean()) + result_Tg = gpd.GeoDataFrame([i['properties']['mean'] for i in results.getInfo()['features']]) + result_tonne = result_Tg * 1000000 + zones_copy[f'{species}_{sector}_{year}'] = result_tonne + if sector == 'sum': + year_total += result_tonne + zones_copy[f'total_{year}'] = year_total + return zones_copy From c2fd09440f886366ae648c552d369680b3223a23 Mon Sep 17 00:00:00 2001 From: Ted Wong Date: Sun, 15 Dec 2024 11:07:42 -0500 Subject: [PATCH 3/7] bug fixes --- city_metrix/layers/__init__.py | 1 + city_metrix/layers/cams_ghg.py | 139 ++++++++++++++------------- city_metrix/metrics/ghg_emissions.py | 31 +++--- 3 files changed, 88 insertions(+), 83 deletions(-) diff --git a/city_metrix/layers/__init__.py b/city_metrix/layers/__init__.py index 421b975..544c1de 100644 --- a/city_metrix/layers/__init__.py +++ b/city_metrix/layers/__init__.py @@ -26,3 +26,4 @@ from .glad_lulc import LandCoverHabitatGlad from .glad_lulc import LandCoverHabitatChangeGlad from .cams import Cams +from .cams_ghg import CamsGhg diff --git a/city_metrix/layers/cams_ghg.py b/city_metrix/layers/cams_ghg.py index e1926e5..a31f458 100644 --- a/city_metrix/layers/cams_ghg.py +++ b/city_metrix/layers/cams_ghg.py @@ -4,75 +4,78 @@ from .layer import Layer class CamsGhg(Layer): - # Returned units: metric tonnes of GHG species or tonnes CO2e - - GWP = { - 'co2': 1 # by definition - 'ch4': 28, # https://www.ipcc.ch/site/assets/uploads/2018/02/WG1AR5_Chapter08_FINAL.pdf - 'chlorinated-hydrocarbons': 400, # Table A2 https://onlinelibrary.wiley.com/doi/pdf/10.1002/0470865172.app2 - 'n2o': 265 # https://www.ipcc.ch/site/assets/uploads/2018/02/WG1AR5_Chapter08_FINAL.pdf - } - SUPPORTED_SPECIES = ['co2', 'ch4', 'n2o', 'chlorinated-hydrocarbons'] - SUPPORTED_YEARS = [2010, 2015, 2020, 2023] + # Returned units: metric tonnes of GHG species or tonnes CO2e + GWP = { + 'co2': 1, # by definition + 'ch4': 28, # https://www.ipcc.ch/site/assets/uploads/2018/02/WG1AR5_Chapter08_FINAL.pdf + 'chlorinated-hydrocarbons': 400, # Table A2 https://onlinelibrary.wiley.com/doi/pdf/10.1002/0470865172.app2 + 'n2o': 265 # https://www.ipcc.ch/site/assets/uploads/2018/02/WG1AR5_Chapter08_FINAL.pdf + } + SUPPORTED_SPECIES = ['co2', 'ch4', 'n2o', 'chlorinated-hydrocarbons'] + SUPPORTED_YEARS = [2010, 2015, 2020, 2023] def __init__(self, species=None, sector='sum', co2e=True, year=2023, **kwargs): super().__init__(**kwargs) - if species is not None and not species in SUPPORTED_SPECIES: - raise Except(f'Unsupported species: {species}') - if not year in SUPPORTED_YEARS: - raise Except(f'Unsupported year: {year}') - if species is None and co2e==False: - raise Except('If sector is unspecified, all supported species will be summed and co2e must be True.') - if species is None and sector != 'sum': - raise Except('If sector is unspecified, sector must be \"sum.\"') - if species is not None and sector != 'sum': - data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}').filter('year', year) - sectors = data_ic.aggregate_array('sector').getInfo() - if not sector in sectors: - raise Except(f'Sector \"{sector}\" not available for {species} in {year}.') - self.species = species # None means all, summed - self.sector = sector - self.co2e = co2e # Want results in CO2e? If so, multiplies by 100-year GWP. - self.year = year # Currently supported: 2010, 2015, 2020, 2023 + if species is not None and not species in self.SUPPORTED_SPECIES: + raise Except(f'Unsupported species: {species}') + if not year in self.SUPPORTED_YEARS: + raise Except(f'Unsupported year: {year}') + if species is None and co2e==False: + raise Except('If sector is unspecified, all supported species will be summed and co2e must be True.') + if species is None and sector != 'sum': + raise Except('If sector is unspecified, sector must be \"sum.\"') + if species is not None and sector != 'sum': + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}').filter('year', year) + sectors = data_ic.aggregate_array('sector').getInfo() + if not sector in sectors: + raise Except(f'Sector \"{sector}\" not available for {species} in {year}.') + self.species = species # None means all, summed + self.sector = sector + self.co2e = co2e # Want results in CO2e? If so, multiplies by 100-year GWP. + self.year = year # Currently supported: 2010, 2015, 2020, 2023 - def get_data(self, bbox): - if self.species is not None: - data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{self.species}') - data_im = data_ic.filter(ee.Filter.eq('year', self.year)).filter(ee.Filter.eq('sector', self.sector)).first() - scale = data_im.projection().getInfo()['transform'][0] - data_im = data_im.multiply(GWP[self.species]) - if self.co2e: - data_im = data_im.multiply(GWP[self.species]) - data_im = data_im.multiply(1000000) # Tg to tonne - ic = ee.ImageCollection(data_im) - scale = data_im.projection().getInfo()['transform'][0] - ds = xr.open_dataset( - ic, - engine = 'ee', - geometry = bbox, - crs = 'EPSG:4326', - scale = scale - ) - else: # Sum over all species - allrasters_ic = ee.ImageCollection([]) - for species in SUPPORTED_SPECIES[1:]: - data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}') - data_im = data_ic.filter(ee.Filter.eq('year', self.year)).filter(ee.Filter.eq('sector', 'sum')).first() - data_im = data_im.multiply(GWP[species]) - data_im = data_im.multiply(1000000) # Tg to tonne - allrasters_ic = summed_rasters.add(data_im) - sum_im = allrasters_ic.sum() - scale = sum_im.projection().getInfo()['transform'][0] - ic = ee.ImageCollection(sum_im) - ds = xr.open_dataset( - ic, - engine = 'ee', - geometry = bbox, - crs = 'EPSG:4326', - scale = scale - ) - ds = ds.transpose('time', 'lat', 'lon') - ds = ds.squeeze() - ds = ds.rio.set_spatial_dims('lon', 'lat') - return ds - \ No newline at end of file + def get_data(self, bbox): + bbox = list(bbox) + + if self.species is not None: + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{self.species}') + data_im = data_ic.filter(ee.Filter.eq('year', self.year)).filter(ee.Filter.eq('sector', self.sector)).first() + scale = data_im.projection().getInfo()['transform'][0] + data_im = data_im.multiply(self.GWP[self.species]) + if self.co2e: + data_im = data_im.multiply(self.GWP[self.species]) + data_im = data_im.multiply(1000000) # Tg to tonne + ic = ee.ImageCollection(data_im) + scale = data_im.projection().getInfo()['transform'][0] + ds = xr.open_dataset( + ic, + engine = 'ee', + geometry = bbox, + crs = 'EPSG:4326', + scale = scale + ) + else: # Sum over all species + allrasters_list = [] + for species in self.SUPPORTED_SPECIES: + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}') + data_im = data_ic.filter(ee.Filter.eq('year', self.year)).filter(ee.Filter.eq('sector', 'sum')).first() + data_im = data_im.multiply(self.GWP[species]) + data_im = data_im.multiply(1000000) # Tg to tonne + allrasters_list.append(data_im) + allrasters_ic = ee.ImageCollection(allrasters_list) + sum_im = allrasters_ic.sum() + scale = data_im.projection().getInfo()['transform'][0] + ic = ee.ImageCollection(sum_im) + ds = xr.open_dataset( + ic, + engine = 'ee', + geometry = bbox, + crs = 'EPSG:4326', + scale = scale + ) + print(ds) + ds = ds.transpose('time', 'lat', 'lon') + ds = ds.squeeze() + ds = ds.rio.set_spatial_dims('lon', 'lat') + return ds + diff --git a/city_metrix/metrics/ghg_emissions.py b/city_metrix/metrics/ghg_emissions.py index ae34557..1199700 100644 --- a/city_metrix/metrics/ghg_emissions.py +++ b/city_metrix/metrics/ghg_emissions.py @@ -1,3 +1,4 @@ +import ee import geopandas as gpd import numpy as np from city_metrix.layers import Layer, CamsGhg @@ -13,23 +14,23 @@ def ghg_emissions(zones, years=[2023]): if not year in SUPPORTED_YEARS: raise Exception(f'Unsupported year {year}') - data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}') zones_copy = zones.copy(deep=True) centroids = [zones.iloc[[i]].centroid for i in range(len(zones))] geoms = [ee.Geometry.Point(c.x[i], c.y[i]) for i, c in enumerate(centroids)] - - for year in years: - year_total = gpd.Series([0] * len(zones)) - year_results = data_ic.filter(ee.Filter.eq('year', year)) - sectors = list(set(year_results.aggregate_array('sector').getInfo())) - sectors.sort() - for sector in sectors: - results = year_results.filter(ee.Filter.eq('sector', sector)).first().reduceRegions(geoms, ee.Reducer.mean()) - result_Tg = gpd.GeoDataFrame([i['properties']['mean'] for i in results.getInfo()['features']]) - result_tonne = result_Tg * 1000000 - zones_copy[f'{species}_{sector}_{year}'] = result_tonne - if sector == 'sum': - year_total += result_tonne - zones_copy[f'total_{year}'] = year_total + for species in SUPPORTED_SPECIES: + data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}') + for year in years: + year_results = data_ic.filter(ee.Filter.eq('year', year)) + year_total = gpd.GeoDataFrame([0] * len(zones)) + sectors = year_results.aggregate_array('sector').getInfo() + sectors.sort() + for sector in sectors: + results = year_results.filter(ee.Filter.eq('sector', sector)).first().reduceRegions(geoms, ee.Reducer.mean()) + result_Tg = gpd.GeoDataFrame([i['properties']['mean'] for i in results.getInfo()['features']]) + result_tonne = result_Tg * 1000000 + zones_copy[f'{species}_{sector}_{year}'] = result_tonne + if sector == 'sum': + year_total += result_tonne + zones_copy[f'total_{year}'] = year_total return zones_copy From f338b3a12f3c5606dd4d63e1cff88121881de70e Mon Sep 17 00:00:00 2001 From: Ted Wong Date: Sun, 15 Dec 2024 11:16:57 -0500 Subject: [PATCH 4/7] add test --- tests/test_layers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/test_layers.py b/tests/test_layers.py index 7875ab9..d01edf1 100644 --- a/tests/test_layers.py +++ b/tests/test_layers.py @@ -6,6 +6,7 @@ AverageNetBuildingHeight, BuiltUpHeight, Cams, + CamsGhg, Era5HottestDay, EsaWorldCover, EsaWorldCoverClass, @@ -58,6 +59,10 @@ def test_cams(): data = Cams().get_data(BBOX) assert np.size(data) > 0 +def test_camsghg(): + data = CamsGhg().get_data(BBOX) + assert np.size(data) > 0 + @pytest.mark.skip(reason="CDS API needs personal access token file to run") def test_era_5_hottest_day(): data = Era5HottestDay().get_data(BBOX) From 3946d5577da63d7aa94954288f143237f8972bc2 Mon Sep 17 00:00:00 2001 From: Ted Wong Date: Sun, 15 Dec 2024 11:40:18 -0500 Subject: [PATCH 5/7] output column name change --- city_metrix/metrics/ghg_emissions.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/city_metrix/metrics/ghg_emissions.py b/city_metrix/metrics/ghg_emissions.py index 1199700..232a469 100644 --- a/city_metrix/metrics/ghg_emissions.py +++ b/city_metrix/metrics/ghg_emissions.py @@ -5,6 +5,7 @@ SUPPORTED_SPECIES = CamsGhg.SUPPORTED_SPECIES SUPPORTED_YEARS = CamsGhg.SUPPORTED_YEARS +GWP = CamsGhg.GWP def ghg_emissions(zones, years=[2023]): # species is one of 'co2', 'ch4', 'n2o', 'chlorinated-hydrocarbons' @@ -29,8 +30,8 @@ def ghg_emissions(zones, years=[2023]): results = year_results.filter(ee.Filter.eq('sector', sector)).first().reduceRegions(geoms, ee.Reducer.mean()) result_Tg = gpd.GeoDataFrame([i['properties']['mean'] for i in results.getInfo()['features']]) result_tonne = result_Tg * 1000000 - zones_copy[f'{species}_{sector}_{year}'] = result_tonne + zones_copy[f'{species}_{sector}_{year}_tonnes'] = result_tonne if sector == 'sum': - year_total += result_tonne - zones_copy[f'total_{year}'] = year_total + year_total += (result_tonne * GWP[species]) + zones_copy[f'all-species_{year}_tonnes-CO2e'] = year_total return zones_copy From 17c498de65fff73a1aa4cafa004e6f222945f4ff Mon Sep 17 00:00:00 2001 From: Ted Wong Date: Sun, 15 Dec 2024 11:52:44 -0500 Subject: [PATCH 6/7] add output columns in tonnes CO2e --- city_metrix/metrics/ghg_emissions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/city_metrix/metrics/ghg_emissions.py b/city_metrix/metrics/ghg_emissions.py index 232a469..ca236b8 100644 --- a/city_metrix/metrics/ghg_emissions.py +++ b/city_metrix/metrics/ghg_emissions.py @@ -31,6 +31,7 @@ def ghg_emissions(zones, years=[2023]): result_Tg = gpd.GeoDataFrame([i['properties']['mean'] for i in results.getInfo()['features']]) result_tonne = result_Tg * 1000000 zones_copy[f'{species}_{sector}_{year}_tonnes'] = result_tonne + zones_copy[f'{species}_{sector}_{year}_tonnes-CO2e'] = (result_tonne * GWP[species]) if sector == 'sum': year_total += (result_tonne * GWP[species]) zones_copy[f'all-species_{year}_tonnes-CO2e'] = year_total From 2a7107e29c54dfc96881f525ee626befe5af3f65 Mon Sep 17 00:00:00 2001 From: Ted Wong Date: Sun, 15 Dec 2024 12:13:42 -0500 Subject: [PATCH 7/7] Fix exception bug, squeeze bug --- city_metrix/layers/cams_ghg.py | 13 ++++++------- city_metrix/metrics/ghg_emissions.py | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/city_metrix/layers/cams_ghg.py b/city_metrix/layers/cams_ghg.py index a31f458..cf77522 100644 --- a/city_metrix/layers/cams_ghg.py +++ b/city_metrix/layers/cams_ghg.py @@ -17,18 +17,18 @@ class CamsGhg(Layer): def __init__(self, species=None, sector='sum', co2e=True, year=2023, **kwargs): super().__init__(**kwargs) if species is not None and not species in self.SUPPORTED_SPECIES: - raise Except(f'Unsupported species: {species}') + raise Exception(f'Unsupported species: {species}') if not year in self.SUPPORTED_YEARS: - raise Except(f'Unsupported year: {year}') + raise Exception(f'Unsupported year: {year}') if species is None and co2e==False: - raise Except('If sector is unspecified, all supported species will be summed and co2e must be True.') + raise Exception('If sector is unspecified, all supported species will be summed and co2e must be True.') if species is None and sector != 'sum': - raise Except('If sector is unspecified, sector must be \"sum.\"') + raise Exception('If sector is unspecified, sector must be \"sum.\"') if species is not None and sector != 'sum': data_ic = ee.ImageCollection(f'projects/wri-datalab/cams-glob-ant/{species}').filter('year', year) sectors = data_ic.aggregate_array('sector').getInfo() if not sector in sectors: - raise Except(f'Sector \"{sector}\" not available for {species} in {year}.') + raise Exception(f'Sector \"{sector}\" not available for {species} in {year}.') self.species = species # None means all, summed self.sector = sector self.co2e = co2e # Want results in CO2e? If so, multiplies by 100-year GWP. @@ -73,9 +73,8 @@ def get_data(self, bbox): crs = 'EPSG:4326', scale = scale ) - print(ds) ds = ds.transpose('time', 'lat', 'lon') - ds = ds.squeeze() + ds = ds.squeeze(['time']) ds = ds.rio.set_spatial_dims('lon', 'lat') return ds diff --git a/city_metrix/metrics/ghg_emissions.py b/city_metrix/metrics/ghg_emissions.py index ca236b8..91c5c53 100644 --- a/city_metrix/metrics/ghg_emissions.py +++ b/city_metrix/metrics/ghg_emissions.py @@ -8,9 +8,9 @@ GWP = CamsGhg.GWP def ghg_emissions(zones, years=[2023]): - # species is one of 'co2', 'ch4', 'n2o', 'chlorinated-hydrocarbons' # supported years: 2010, 2015, 2020, 2023 - + if not isinstance(years, (list, set, tuple)): + raise Exception('Parameter years must be list, set, or tuple.') for year in years: if not year in SUPPORTED_YEARS: raise Exception(f'Unsupported year {year}')