diff --git a/parm/config/gfs/config.aeroanl b/parm/config/gfs/config.aeroanl index 52bc14c9e3..ecbdc485f2 100644 --- a/parm/config/gfs/config.aeroanl +++ b/parm/config/gfs/config.aeroanl @@ -20,6 +20,7 @@ export io_layout_y=@IO_LAYOUT_Y@ export JEDIEXE="${EXECgfs}/gdas.x" export BMATEXE="${EXECgfs}/gdasapp_chem_diagb.x" +export DIFFUSIONEXE="${EXECgfs}/gdas_fv3jedi_error_covariance_toolbox.x" if [[ "${DOIAU}" == "YES" ]]; then export aero_bkg_times="3,6,9" diff --git a/parm/config/gfs/config.aeroanlgenb b/parm/config/gfs/config.aeroanlgenb index 6a2139ad01..706b6314c8 100644 --- a/parm/config/gfs/config.aeroanlgenb +++ b/parm/config/gfs/config.aeroanlgenb @@ -10,8 +10,9 @@ source "${EXPDIR}/config.resources" aeroanlgenb export BMATYAML="${PARMgfs}/gdas/aero/berror/aero_diagb.yaml.j2" export DIFFUSIONYAML="${PARMgfs}/gdas/aero/berror/aero_diffusionparm.yaml.j2" -export iterations=10 -export fixed value=1.0 +export aero_diffusion_iter=10 +export aero_diffusion_horiz_len=2500e3 +export aero_diffusion_fixed_val=1.0 echo "END: config.aeroanlgenb" diff --git a/parm/ufs/gocart/ExtData.other b/parm/ufs/gocart/ExtData.other index 7a0d63d6ca..5d2ddc5102 100644 --- a/parm/ufs/gocart/ExtData.other +++ b/parm/ufs/gocart/ExtData.other @@ -17,12 +17,12 @@ DU_UTHRES '1' Y E - none none uthres ExtData/n #====== Sulfate Sources ================================================= # Anthropogenic (BF & FF) emissions -- allowed to input as two layers -SU_ANTHROL1 NA N Y %y4-%m2-%d2t12:00:00 none none SO2 ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc -SU_ANTHROL2 NA N Y %y4-%m2-%d2t12:00:00 none none SO2_elev ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +SU_ANTHROL1 NA Y Y %y4-%m2-%d2t12:00:00 none none SO2 ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +SU_ANTHROL2 NA Y Y %y4-%m2-%d2t12:00:00 none none SO2_elev ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc # Ship emissions -SU_SHIPSO2 NA N Y %y4-%m2-%d2t12:00:00 none none SO2_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc -SU_SHIPSO4 NA N Y %y4-%m2-%d2t12:00:00 none none SO4_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +SU_SHIPSO2 NA Y Y %y4-%m2-%d2t12:00:00 none none SO2_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +SU_SHIPSO4 NA Y Y %y4-%m2-%d2t12:00:00 none none SO4_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc # Aircraft fuel consumption SU_AIRCRAFT NA Y Y %y4-%m2-%d2t12:00:00 none none none /dev/null @@ -63,11 +63,11 @@ OC_MTPO NA Y Y %y4-%m2-%d2t12:00:00 none none mtpo ExtData/nexus/MEGAN_ OC_BIOFUEL NA Y Y %y4-%m2-%d2t12:00:00 none none biofuel /dev/null # Anthropogenic (BF & FF) emissions -- allowed to input as two layers -OC_ANTEOC1 NA N Y %y4-%m2-%d2t12:00:00 none none OC ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc -OC_ANTEOC2 NA N Y %y4-%m2-%d2t12:00:00 none none OC_elev ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +OC_ANTEOC1 NA Y Y %y4-%m2-%d2t12:00:00 none none OC ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +OC_ANTEOC2 NA Y Y %y4-%m2-%d2t12:00:00 none none OC_elev ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc # EDGAR based ship emissions -OC_SHIP NA N Y %y4-%m2-%d2t12:00:00 none none OC_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +OC_SHIP NA Y Y %y4-%m2-%d2t12:00:00 none none OC_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc # Aircraft fuel consumption OC_AIRCRAFT NA N Y %y4-%m2-%d2t12:00:00 none none oc_aviation /dev/null @@ -88,11 +88,11 @@ pSOA_ANTHRO_VOC NA Y Y %y4-%m2-%d2t12:00:00 none none biofuel /dev/null BC_BIOFUEL NA Y Y %y4-%m2-%d2t12:00:00 none none biofuel /dev/null # Anthropogenic (BF & FF) emissions -- allowed to input as two layers -BC_ANTEBC1 NA N Y %y4-%m2-%d2t12:00:00 none none BC ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc -BC_ANTEBC2 NA N Y %y4-%m2-%d2t12:00:00 none none BC_elev ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +BC_ANTEBC1 NA Y Y %y4-%m2-%d2t12:00:00 none none BC ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +BC_ANTEBC2 NA Y Y %y4-%m2-%d2t12:00:00 none none BC_elev ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc # EDGAR based ship emissions -BC_SHIP NA N Y %y4-%m2-%d2t12:00:00 none none BC_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc +BC_SHIP NA Y Y %y4-%m2-%d2t12:00:00 none none BC_ship ExtData/nexus/CEDS/v2019/monthly/%y4/CEDS_2019_monthly.%y4%m2.nc # Aircraft fuel consumption BC_AIRCRAFT NA N Y %y4-%m2-%d2t12:00:00 none none bc_aviation /dev/null diff --git a/scripts/exglobal_aero_analysis_generate_bmatrix.py b/scripts/exglobal_aero_analysis_generate_bmatrix.py index cd4a60166e..19d5454ba0 100755 --- a/scripts/exglobal_aero_analysis_generate_bmatrix.py +++ b/scripts/exglobal_aero_analysis_generate_bmatrix.py @@ -18,8 +18,9 @@ # Take configuration from environment and cast it as python dictionary config = cast_strdict_as_dtypedict(os.environ) - # Instantiate the aerosol variance tasks + # Instantiate the aerosol variance and diffusion correlation tasks AeroB = AerosolBMatrix(config) AeroB.initialize() AeroB.computeVariance() + AeroB.computeDiffusion() AeroB.finalize() diff --git a/sorc/link_workflow.sh b/sorc/link_workflow.sh index 9bb496c602..a16aa6de5d 100755 --- a/sorc/link_workflow.sh +++ b/sorc/link_workflow.sh @@ -359,6 +359,7 @@ if [[ -d "${HOMEgfs}/sorc/gdas.cd/build" ]]; then declare -a JEDI_EXE=("gdas.x" \ "gdas_soca_gridgen.x" \ "gdas_soca_error_covariance_toolbox.x" \ + "gdas_fv3jedi_error_covariance_toolbox.x" \ "gdas_soca_setcorscales.x" \ "fv3jedi_plot_field.x" \ "gdasapp_chem_diagb.x" \ diff --git a/ush/python/pygfs/task/aero_analysis.py b/ush/python/pygfs/task/aero_analysis.py index 430f7f34fc..0c33122f0a 100644 --- a/ush/python/pygfs/task/aero_analysis.py +++ b/ush/python/pygfs/task/aero_analysis.py @@ -86,6 +86,8 @@ def initialize(self: Analysis) -> None: # copy BUMP files, otherwise it will assume ID matrix if self.task_config.get('STATICB_TYPE', 'identity') in ['bump']: FileHandler(self.get_berror_dict(self.task_config)).sync() + if self.task_config.get('STATICB_TYPE', 'identity') in ['diffusion']: + FileHandler(self.get_berror_dict(self.task_config)).sync() # stage backgrounds FileHandler(self.get_bkg_dict(AttrDict(self.task_config, **self.task_config))).sync() @@ -286,7 +288,6 @@ def get_berror_dict(self, config: Dict[str, Any]) -> Dict[str, List[str]]: a dictionary containing the list of background error files to copy for FileHandler """ # aerosol static-B needs nicas, cor_rh, cor_rv and stddev files. - b_dir = config.BERROR_DATA_DIR b_datestr = to_fv3time(config.BERROR_DATE) analysis_dir = config.COM_CHEM_ANALYSIS cycle_datestr = to_fv3time(config.current_cycle) @@ -305,17 +306,16 @@ def get_berror_dict(self, config: Dict[str, Any]) -> Dict[str, List[str]]: os.path.join(analysis_dir, tracer), os.path.join(config.DATA, 'berror', tracer) ]) - # the remaining B matrix files are fixed and come from a fix directory - radius = 'cor_aero_universe_radius' + # the diffusion correlation files are computed every cycle and are available in COM + diff_hz = 'diffusion_hz.nc' + diff_vt = 'diffusion_vt.nc' berror_list.append([ - os.path.join(b_dir, radius), os.path.join(config.DATA, 'berror', radius) + os.path.join(config.COM_CHEM_ANALYSIS, diff_hz), os.path.join(config.DATA, 'berror', diff_hz) ]) - nproc = config.ntiles * config.layout_x * config.layout_y - for nn in range(1, nproc + 1): - berror_list.append([ - os.path.join(b_dir, f'nicas_aero_nicas_local_{nproc:06}-{nn:06}.nc'), - os.path.join(config.DATA, 'berror', f'nicas_aero_nicas_local_{nproc:06}-{nn:06}.nc') - ]) + berror_list.append([ + os.path.join(config.COM_CHEM_ANALYSIS, diff_vt), os.path.join(config.DATA, 'berror', diff_vt) + ]) + berror_dict = { 'mkdir': [os.path.join(config.DATA, 'berror')], 'copy': berror_list, diff --git a/ush/python/pygfs/task/aero_bmatrix.py b/ush/python/pygfs/task/aero_bmatrix.py index 436142abc1..4a5726ecdf 100644 --- a/ush/python/pygfs/task/aero_bmatrix.py +++ b/ush/python/pygfs/task/aero_bmatrix.py @@ -61,20 +61,26 @@ def initialize(self: BMatrix) -> None: FileHandler(self.get_bkg_dict(AttrDict(self.task_config, **self.task_config))).sync() # generate diagb YAML file - logger.debug(f"Generate bmat YAML file: {self.task_config.bmat_yaml}") + logger.info(f"Generate bmat YAML file: {self.task_config.bmat_yaml}") save_as_yaml(self.task_config.bmat_config, self.task_config.bmat_yaml) logger.info(f"Wrote bmat YAML to: {self.task_config.bmat_yaml}") # generate diffusion parameters YAML file - logger.debug(f"Generate diffusion YAML file: {self.task_config.diffusion_yaml}") + logger.info(f"Generate diffusion YAML file: {self.task_config.diffusion_yaml}") save_as_yaml(self.task_config.diffusion_config, self.task_config.diffusion_yaml) logger.info(f"Wrote diffusion YAML to: {self.task_config.diffusion_yaml}") # create output directory FileHandler({'mkdir': [os.path.join(self.task_config['DATA'], 'stddev')]}).sync() + # create diffusion output directory + FileHandler({'mkdir': [os.path.join(self.task_config['DATA'], 'diffusion')]}).sync() + # link executable to run directory + logger.info(f'before link_bmatexe') self.link_bmatexe() + logger.info(f'before link_diffusion_exe') + self.link_diffusion_exe() @logit(logger) def computeVariance(self) -> None: @@ -96,6 +102,26 @@ def computeVariance(self) -> None: pass + @logit(logger) + def computeDiffusion(self) -> None: + + chdir(self.task_config.DATA) + + exec_cmd_diffusion = Executable(self.task_config.APRUN_AEROGENB) + exec_name_diffusion = os.path.join(self.task_config.DATA, 'gdas_fv3jedi_error_covariance_toolbox.x') + exec_cmd_diffusion.add_default_arg(exec_name_diffusion) + exec_cmd_diffusion.add_default_arg(self.task_config.diffusion_yaml) + + try: + logger.debug(f"Executing {exec_cmd_diffusion}") + exec_cmd_diffusion() + except OSError: + raise OSError(f"Failed to execute {exec_cmd_diffusion}") + except Exception: + raise WorkflowException(f"An error occured during execution of {exec_cmd_diffusion}") + + pass + @logit(logger) def finalize(self) -> None: super().finalize() @@ -106,8 +132,7 @@ def finalize(self) -> None: dest_diffusion = os.path.join(self.task_config.COM_CHEM_ANALYSIS, f"{self.task_config['CDUMP']}.t{self.runtime_config['cyc']:02d}z.chem_diffusion.yaml") yaml_copy = { 'mkdir': [self.task_config.COM_CHEM_ANALYSIS], - 'copy': [[src, dest]], - 'copy': [[src_diffusion, dest_diffusion]] + 'copy': [[src, dest], [src_diffusion, dest_diffusion]] } FileHandler(yaml_copy).sync() @@ -129,6 +154,16 @@ def finalize(self) -> None: FileHandler({'copy': stddevlist}).sync() + # Diffusion files + diff_hz = 'diffusion_hz.nc' + diff_vt = 'diffusion_vt.nc' + src_hz = os.path.join(self.task_config.DATA, 'diffusion', diff_hz) + dest_hz = os.path.join(self.task_config.COM_CHEM_ANALYSIS, diff_hz) + src_vt = os.path.join(self.task_config.DATA, 'diffusion', diff_vt) + dest_vt = os.path.join(self.task_config.COM_CHEM_ANALYSIS, diff_vt) + difflist = [[src_hz, dest_hz], [src_vt, dest_vt]] + FileHandler({'copy': difflist}).sync() + @logit(logger) def link_bmatexe(self) -> None: """ @@ -155,6 +190,34 @@ def link_bmatexe(self) -> None: return + @logit(logger) + def link_diffusion_exe(self) -> None: + """ + + This method links a JEDI (fv3jedi_error_covariance_toolbox.x) + executable to the run directory + + Parameters + ---------- + Task: GDAS task + + Returns + ---------- + None + """ + + exe_src_diffusion = self.task_config.DIFFUSIONEXE + + # TODO: linking is not permitted per EE2. Needs work in JEDI to be able to copy the exec. + logger.info(f"Link executable {exe_src_diffusion} to DATA/") + logger.warn("Linking is not permitted per EE2.") + exe_dest_diffusion = os.path.join(self.task_config.DATA, os.path.basename(exe_src_diffusion)) + if os.path.exists(exe_dest_diffusion): + rm_p(exe_dest_diffusion) + os.symlink(exe_src_diffusion, exe_dest_diffusion) + + return + @logit(logger) def get_bkg_dict(self, task_config: Dict[str, Any]) -> Dict[str, List[str]]: """Compile a dictionary of model background files to copy diff --git a/workflow/applications/gfs_cycled.py b/workflow/applications/gfs_cycled.py index c9f228b4cb..3d33701fa4 100644 --- a/workflow/applications/gfs_cycled.py +++ b/workflow/applications/gfs_cycled.py @@ -152,9 +152,6 @@ def get_task_names(self): gdas_gfs_common_tasks_before_fcst += ['sfcanl', 'analcalc'] - if self.do_aero: - gdas_gfs_common_tasks_before_fcst += ['aeroanlgenb', 'aeroanlinit', 'aeroanlvar', 'aeroanlfinal'] - if self.do_jedisnowda: gdas_gfs_common_tasks_before_fcst += ['prepsnowobs', 'snowanl'] @@ -182,7 +179,7 @@ def get_task_names(self): gdas_tasks += wave_prep_tasks if self.do_aero and 'gdas' in self.aero_anl_cdumps: - gdas_tasks += ['aeroanlinit', 'aeroanlvar', 'aeroanlfinal'] + gdas_tasks += ['aeroanlgenb', 'aeroanlinit', 'aeroanlvar', 'aeroanlfinal'] if self.do_prep_obs_aero: gdas_tasks += ['prepobsaero'] @@ -221,7 +218,7 @@ def get_task_names(self): gfs_tasks += wave_prep_tasks if self.do_aero and 'gfs' in self.aero_anl_cdumps: - gfs_tasks += ['aeroanlinit', 'aeroanlvar', 'aeroanlfinal'] + gfs_tasks += ['aeroanlgenb', 'aeroanlinit', 'aeroanlvar', 'aeroanlfinal'] if self.do_prep_obs_aero: gfs_tasks += ['prepobsaero']