diff --git a/preproc/hemco_soilnox_v202112_preproc.py b/preproc/hemco_soilnox_v202112_preproc.py new file mode 100755 index 0000000000000000000000000000000000000000..6a157fdb51de23da9bccc6318a2c509124222dac --- /dev/null +++ b/preproc/hemco_soilnox_v202112_preproc.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python + +# Copyright 2018 Earth Sciences Department, BSC-CNS +# +# This file is part of HERMESv3_GR. +# +# HERMESv3_GR is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# HERMESv3_GR is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with HERMESv3_GR. If not, see . + + +import os +import sys +import numpy as np +import pandas as pd +import timeit +from datetime import datetime, timedelta +import xarray as xr + +# ============== README ====================== +""" +downloading website: +reference: +Besides citing HERMESv3_GR, users must also acknowledge the use of the corresponding emission inventories in their works +""" + +# ============== CONFIGURATION PARAMETERS ====================== +# The original emissions are downloaded from the following link: +# downloading website: http://geoschemdata.wustl.edu/ExtData/HEMCO/OFFLINE_SOILNOX/v2021-12/0.25x0.3125/ +# reference: https://doi.org/10.1038/s41597-020-0488-5 + +INPUT_PATH = '/esarchive/recon/pku/hemco_soilnox-v202112/original_files//soilnox_025..nc' +OUTPUT_PATH = '/esarchive/recon/pku/hemco_soilnox-v202112/daily_mean/_/_.nc' +SECTOR_LIST = ['soil'] +POLLUTANT_INFO = {"EmisNO_Fert": "nox_n_fert", "SOIL_NOx": "nox_n_tot"} + +START_DAY = datetime(year=2019, month=1, day=1) +END_DAY = datetime(year=2019, month=12, day=31) +# END_DAY = datetime(year=2019, month=1, day=1) + +XARRAY = True +# ============================================================== + + +def create_bounds(coords, number_vertices=2): + """ + Calculate the vertices coordinates. + + :param coords: Coordinates in degrees (latitude or longitude) + :type coords: numpy.array + + :param number_vertices: Non mandatory parameter that informs the number of vertices that must have the boundaries. + (by default 2) + :type number_vertices: int + + :return: Array with as many elements as vertices for each value of coords. + :rtype: numpy.array + """ + import numpy as np + + interval = coords[1] - coords[0] + + coords_left = coords - interval / 2 + coords_right = coords + interval / 2 + if number_vertices == 2: + bound_coords = np.dstack((coords_left, coords_right)) + elif number_vertices == 4: + bound_coords = np.dstack((coords_left, coords_right, coords_right, coords_left)) + else: + raise ValueError('The number of vertices of the boudaries must be 2 or 4') + + return bound_coords + + +def parse_path(file_path, date_aux=None, sector=None, pollutant=None): + """ + :param file_path: Path to parse + :type file_path: str + + :param date_aux: Date to parse + :type date_aux: datetime, None + + :param sector: Sector name + :type sector: str, None + + :param pollutant: Pollutant name + :type pollutant: str, None + + :return: Complete path + :rtype: str + """ + if date_aux is not None: + file_path = file_path.replace('', date_aux.strftime("%Y%m%d")) + file_path = file_path.replace('', date_aux.strftime("%m")) + if pollutant is not None: + file_path = file_path.replace('', pollutant) + if sector is not None: + file_path = file_path.replace('', sector) + return file_path + + +def make_dir(file_path): + parent_dir = os.path.dirname(file_path) + if not os.path.exists(parent_dir): + os.makedirs(parent_dir) + return True + + +def make_grid(template_path): + grid = xr.open_dataset(template_path) + + grid.coords['cell_area'] = grid['AREA'] + grid.coords['cell_area'].attrs = {"long_name": "area of the grid cell", + "standard_name": "cell_area", + "units": "m2"} + + grid.coords['crs'] = int(0) + grid.coords['crs'].attrs = {"grid_mapping_name": "latitude_longitude", + "semi_major_axis": 6371000., + "inverse_flattening": 0} + + lat_bnds = create_bounds(grid.coords['lat']) + lat_bnds = lat_bnds.reshape((lat_bnds.shape[-2], lat_bnds.shape[-1])) + grid.coords['lat_bnds'] = (('lat', 'nv'), lat_bnds) + grid.coords['lat'].attrs['bounds'] = 'lat_bnds' + + lon_bnds = create_bounds(grid.coords['lon']) + lon_bnds = lon_bnds.reshape((lon_bnds.shape[-2], lon_bnds.shape[-1])) + grid.coords['lon_bnds'] = (('lon', 'nv'), lon_bnds) + grid.coords['lon'].attrs['bounds'] = 'lon_bnds' + + var_list = list(grid.keys()) + for var_name in var_list: + del grid[var_name] + + return grid + + +def main_xarray(): + + grid_nc = make_grid(parse_path(INPUT_PATH, date_aux=START_DAY)) + + day_aux = START_DAY + for sector in SECTOR_LIST: + while day_aux <= END_DAY: + print(day_aux) + in_nc = xr.open_dataset(parse_path(INPUT_PATH, date_aux=day_aux)) + for poll_in_name, poll_out_name in POLLUTANT_INFO.items(): + out_nc = grid_nc.copy() + out_nc[poll_out_name] = (('lat', 'lon'), (in_nc[poll_in_name][:].mean(dim='time').data)) + out_nc[poll_out_name].attrs['cell_measures'] = "area: cell_area" + out_nc[poll_out_name].attrs['grid_mapping'] = "crs" + + out_nc['time'] = [day_aux] + + out_nc.attrs['comment'] = "Re-writing done by Carles Tena (carles.tena@bsc.es) from the BSC-CNS " + \ + "(Barcelona Supercomputing Center)" + + out_path = parse_path(OUTPUT_PATH, date_aux=day_aux, sector=sector, pollutant=poll_out_name) + make_dir(out_path) + out_nc.to_netcdf(out_path) + + day_aux += timedelta(days=1) + + return True + + +def main(): + day_aux = START_DAY + + while day_aux <= END_DAY: + in_path = parse_path(INPUT_PATH, day_aux) + + day_aux += timedelta(days=1) + + return True + + +if __name__ == '__main__': + initime = timeit.default_timer() + + if XARRAY: + main_xarray() + else: + main() + + print("\t{0:.3f}s".format(timeit.default_timer() - initime)) + sys.exit(0)