diff --git a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_Bio_interpolate.py b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_Bio_interpolate.py index bd3a213..2609eda 100644 --- a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_Bio_interpolate.py +++ b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_Bio_interpolate.py @@ -8,16 +8,13 @@ load_cmip7_aerosol_biomass_list, save_cmip7_aerosol_biomass, ) -from aerosol.cmip7_HI_aerosol import ( - CMIP7_HI_AEROSOL_BEG_YEAR, - CMIP7_HI_AEROSOL_END_YEAR, - esm_hi_aerosol_save_dirpath, -) +from aerosol.cmip7_HI_aerosol import esm_hi_aerosol_save_dirpath from cmip7_ancil_argparse import ( common_parser, percent_parser, ) from cmip7_ancil_common import cmip7_date_constraint_from_years +from cmip7_HI import CMIP7_HI_BEG_YEAR, CMIP7_HI_END_YEAR def parse_args(): @@ -42,8 +39,8 @@ def load_cmip7_hi_aerosol_biomass(args, species): species, args.dataset_date_range_list, cmip7_date_constraint_from_years( - CMIP7_HI_AEROSOL_BEG_YEAR, - CMIP7_HI_AEROSOL_END_YEAR, + CMIP7_HI_BEG_YEAR, + CMIP7_HI_END_YEAR, ), ) @@ -54,8 +51,8 @@ def load_cmip7_hi_aerosol_biomass_percentage(args, species): species, args.percent_date_range, cmip7_date_constraint_from_years( - CMIP7_HI_AEROSOL_BEG_YEAR, - CMIP7_HI_AEROSOL_END_YEAR, + CMIP7_HI_BEG_YEAR, + CMIP7_HI_END_YEAR, ), ) diff --git a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_SO2_interpolate.py b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_SO2_interpolate.py index e3aea5d..05b9aed 100644 --- a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_SO2_interpolate.py +++ b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_SO2_interpolate.py @@ -4,8 +4,6 @@ from ast import literal_eval from aerosol.cmip7_HI_aerosol import ( - CMIP7_HI_AEROSOL_BEG_YEAR, - CMIP7_HI_AEROSOL_END_YEAR, esm_hi_aerosol_ancil_dirpath, esm_hi_aerosol_save_dirpath, ) @@ -18,7 +16,11 @@ common_parser, dms_filename_parser, ) -from cmip7_HI import fix_esm15_hi_ancil_date +from cmip7_HI import ( + CMIP7_HI_BEG_YEAR, + CMIP7_HI_END_YEAR, + fix_esm15_hi_ancil_date, +) def parse_args(): @@ -41,8 +43,8 @@ def load_cmip7_hi_so2_aerosol_anthro(args, species): return load_cmip7_hi_aerosol_anthro( args, species, - beg_year=CMIP7_HI_AEROSOL_BEG_YEAR, - end_year=CMIP7_HI_AEROSOL_END_YEAR, + beg_year=CMIP7_HI_BEG_YEAR, + end_year=CMIP7_HI_END_YEAR, ) diff --git a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol.py b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol.py index 8cfb60d..7bd9c1f 100644 --- a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol.py +++ b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol.py @@ -1,10 +1,6 @@ from pathlib import Path from cmip7_ancil_constants import ANCIL_TODAY -from cmip7_HI import CMIP7_HI_BEG_YEAR, CMIP7_HI_END_YEAR - -CMIP7_HI_AEROSOL_BEG_YEAR = CMIP7_HI_BEG_YEAR - 1 -CMIP7_HI_AEROSOL_END_YEAR = CMIP7_HI_END_YEAR def esm_hi_aerosol_ancil_dirpath(ancil_root_dirname): diff --git a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol_anthro.py b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol_anthro.py index 3bccd6a..734a167 100644 --- a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol_anthro.py +++ b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_HI_aerosol_anthro.py @@ -5,13 +5,10 @@ cmip7_aerosol_anthro_interpolate, load_cmip7_aerosol_anthro_list, ) -from aerosol.cmip7_HI_aerosol import ( - CMIP7_HI_AEROSOL_BEG_YEAR, - CMIP7_HI_AEROSOL_END_YEAR, - esm_hi_aerosol_save_dirpath, -) +from aerosol.cmip7_HI_aerosol import esm_hi_aerosol_save_dirpath from cmip7_ancil_argparse import common_parser from cmip7_ancil_common import cmip7_date_constraint_from_years +from cmip7_HI import CMIP7_HI_BEG_YEAR, CMIP7_HI_END_YEAR def parse_args(species): @@ -30,8 +27,8 @@ def parse_args(species): def load_cmip7_hi_aerosol_anthro( args, species, - beg_year=CMIP7_HI_AEROSOL_BEG_YEAR, - end_year=CMIP7_HI_AEROSOL_END_YEAR, + beg_year=CMIP7_HI_BEG_YEAR, + end_year=CMIP7_HI_END_YEAR, ): return load_cmip7_aerosol_anthro_list( args, diff --git a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_SO2_interpolate.py b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_SO2_interpolate.py index b9f594f..38ee7e8 100644 --- a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_SO2_interpolate.py +++ b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_SO2_interpolate.py @@ -12,6 +12,7 @@ from cmip7_ancil_common import ( INTERPOLATION_SCHEME, esm_grid_mask_cube, + extend_years, save_ancil, ) @@ -97,6 +98,12 @@ def save_cmip7_so2_aerosol_anthro( # Need to remove the sector coordinate before saving # because high doesn't have it so2_low.remove_coord("sector") + + # Extend the historical time series, if any, + # by duplicating the first and last years + so2_low = extend_years(so2_low) + so2_high = extend_years(so2_high) + # Use the CMIP6 DMS cmip6_dms = dms_load_fn(args) diff --git a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_anthro.py b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_anthro.py index 8189bc8..4f35578 100644 --- a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_anthro.py +++ b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_anthro.py @@ -9,6 +9,7 @@ from cmip7_ancil_common import ( INTERPOLATION_SCHEME, esm_grid_mask_cube, + extend_years, fix_coords, save_ancil, ) @@ -74,4 +75,7 @@ def cmip7_aerosol_anthro_interpolate( esm_cube.attributes["STASH"] = iris.fileformats.pp.STASH( model=1, section=0, item=stash_item ) + # Extend the historical time series, if any, + # by duplicating the first and last years + esm_cube = extend_years(esm_cube) save_ancil(esm_cube, save_dirpath, args.save_filename) diff --git a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_biomass.py b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_biomass.py index 1793a22..b35dcef 100644 --- a/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_biomass.py +++ b/CMIP7/esm1p6/atmosphere/aerosol/cmip7_aerosol_biomass.py @@ -11,6 +11,7 @@ from cmip7_ancil_common import ( INTERPOLATION_SCHEME, esm_grid_mask_cube, + extend_years, save_ancil, set_coord_system, ) @@ -140,6 +141,11 @@ def save_cmip7_aerosol_biomass(args, load_pc_fn, load_fn, save_dirpath): model=1, section=0, item=131 ) + # Extend the historical time series, if any, + # by duplicating the first and last years + low_esm = extend_years(low_esm) + high_esm = extend_years(high_esm) + save_ancil([low_esm, high_esm], save_dirpath, args.save_filename) now = datetime.now() diff --git a/CMIP7/esm1p6/atmosphere/cmip7_HI.py b/CMIP7/esm1p6/atmosphere/cmip7_HI.py index 9e04159..b8d103c 100644 --- a/CMIP7/esm1p6/atmosphere/cmip7_HI.py +++ b/CMIP7/esm1p6/atmosphere/cmip7_HI.py @@ -1,11 +1,9 @@ import calendar from pathlib import Path -import iris import mule from cmip7_ancil_constants import ( ANCIL_TODAY, - MONTHS_IN_A_YEAR, UM_VERSION, ) from cmip7_PI import CMIP7_PI_YEAR @@ -46,39 +44,3 @@ def fix_esm15_hi_ancil_date(ifile, ofile): field.lbdatd = calendar.monthrange(field.lbyr, field.lbmon)[1] ff.to_file(ofile) - - -def extend_hi_years(cube): - """ - Extend a cube representing a monthly time series by duplicating - and adjusting the first and last years. - Based on Crown copyright code from ozone_cmip6_ancillary_for_suite.py - by Steven Hardiman of the UK Met Office. - """ - time_coord = cube.coord("time") - time_points = time_coord.points - if (months := len(time_points)) <= MONTHS_IN_A_YEAR: - raise ValueError( - f"Cannot extend a cube containing {months} months of data. " - f"More than {MONTHS_IN_A_YEAR} months are required." - ) - - # Duplicate the first year. - length_one_year = time_points[MONTHS_IN_A_YEAR] - time_points[0] - beg_year = cube[:MONTHS_IN_A_YEAR].copy() - beg_year_tc = beg_year.coord("time") - beg_year_tc.points = beg_year_tc.points - length_one_year - if time_coord.has_bounds(): - beg_year_tc.bounds = beg_year_tc.bounds - length_one_year - - # Duplicate the last year. - length_one_year = time_points[-1] - time_points[-1 - MONTHS_IN_A_YEAR] - end_year = cube[-MONTHS_IN_A_YEAR:].copy() - end_year_tc = end_year.coord("time") - end_year_tc.points = end_year_tc.points + length_one_year - if time_coord.has_bounds(): - end_year_tc.bounds = end_year_tc.bounds + length_one_year - - # Return a cube with extended years. - cubelist = iris.cube.CubeList((beg_year, cube, end_year)) - return cubelist.concatenate_cube() diff --git a/CMIP7/esm1p6/atmosphere/cmip7_ancil_common.py b/CMIP7/esm1p6/atmosphere/cmip7_ancil_common.py index 2829aba..f4cf260 100644 --- a/CMIP7/esm1p6/atmosphere/cmip7_ancil_common.py +++ b/CMIP7/esm1p6/atmosphere/cmip7_ancil_common.py @@ -10,7 +10,10 @@ import iris import mule import numpy as np -from cmip7_ancil_constants import UM_VERSION +from cmip7_ancil_constants import ( + MONTHS_IN_A_YEAR, + UM_VERSION, +) INTERPOLATION_SCHEME = iris.analysis.AreaWeighted(mdtol=0.5) @@ -72,6 +75,40 @@ def set_gregorian(var): time.units = newunits +def extend_years(cube): + """ + Extend a cube representing a monthly time series by duplicating + and adjusting the first and last years. + Based on Crown copyright code from ozone_cmip6_ancillary_for_suite.py + by Steven Hardiman of the UK Met Office. + """ + time_coord = cube.coord("time") + time_points = time_coord.points + # Do not extend a cube containing less than two years of data. + if len(time_points) < MONTHS_IN_A_YEAR * 2: + return cube + + # Duplicate the first year. + length_one_year = time_points[MONTHS_IN_A_YEAR] - time_points[0] + beg_year = cube[:MONTHS_IN_A_YEAR].copy() + beg_year_tc = beg_year.coord("time") + beg_year_tc.points = beg_year_tc.points - length_one_year + if time_coord.has_bounds(): + beg_year_tc.bounds = beg_year_tc.bounds - length_one_year + + # Duplicate the last year. + length_one_year = time_points[-1] - time_points[-1 - MONTHS_IN_A_YEAR] + end_year = cube[-MONTHS_IN_A_YEAR:].copy() + end_year_tc = end_year.coord("time") + end_year_tc.points = end_year_tc.points + length_one_year + if time_coord.has_bounds(): + end_year_tc.bounds = end_year_tc.bounds + length_one_year + + # Return a cube with extended years. + cubelist = iris.cube.CubeList((beg_year, cube, end_year)) + return cubelist.concatenate_cube() + + def set_coord_system(cube): coord_system = iris.coord_systems.GeogCS(6371229.0) cube.coord("latitude").coord_system = coord_system diff --git a/CMIP7/esm1p6/atmosphere/nitrogen/cmip7_HI_nitrogen_generate.py b/CMIP7/esm1p6/atmosphere/nitrogen/cmip7_HI_nitrogen_generate.py index 2cedc97..d4bcf92 100644 --- a/CMIP7/esm1p6/atmosphere/nitrogen/cmip7_HI_nitrogen_generate.py +++ b/CMIP7/esm1p6/atmosphere/nitrogen/cmip7_HI_nitrogen_generate.py @@ -2,8 +2,8 @@ from pathlib import Path from cmip7_ancil_argparse import common_parser +from cmip7_ancil_common import extend_years from cmip7_ancil_constants import ANCIL_TODAY -from cmip7_HI import extend_hi_years from nitrogen.cmip7_nitrogen import ( cmip7_nitrogen_dirpath, load_cmip7_nitrogen, @@ -54,6 +54,6 @@ def esm_hi_nitrogen_save_dirpath(args): # Load the CMIP7 datasets nitrogen_cube = load_cmip7_nitrogen(args, cmip7_hi_nitrogen_filepath) # Regrid to match the ESM1.5 mask and extend the time series - esm_cube = extend_hi_years(regrid_cmip7_nitrogen(args, nitrogen_cube)) + esm_cube = extend_years(regrid_cmip7_nitrogen(args, nitrogen_cube)) # Save the ancillary save_cmip7_nitrogen(args, esm_cube, esm_hi_nitrogen_save_dirpath)