From f1f7f5b3e3fdb08644d2f2f32c8c21cfc97d0dbd Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Wed, 17 Dec 2025 19:01:32 +0000 Subject: [PATCH 01/12] Initial commit --- sorc/gdas.cd | 2 +- ush/python/pygfs/task/analysis.py | 11 +++++- ush/python/pygfs/task/marine_analysis.py | 47 ++++++++++++++++++------ ush/python/pygfs/task/marine_bmat.py | 14 +++---- ush/python/pygfs/task/marine_letkf.py | 6 +-- ush/python/pygfs/task/marine_recenter.py | 6 +-- 6 files changed, 60 insertions(+), 26 deletions(-) diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 58da1e3bcc8..4b16faa74a4 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 58da1e3bcc863fddaf32319efe6b409565dd568b +Subproject commit 4b16faa74a41811210789f9e5082aa1f94fef790 diff --git a/ush/python/pygfs/task/analysis.py b/ush/python/pygfs/task/analysis.py index 0111fca0444..2a16ed30937 100644 --- a/ush/python/pygfs/task/analysis.py +++ b/ush/python/pygfs/task/analysis.py @@ -65,6 +65,14 @@ def __init__(self, config: Dict[str, Any]): else: _da_prefix = 'gdas' + # Map ocean resolution to number of vertical levels + _ocnres_to_nlev = { + '500': 25, + '100': 75, + '050': 75, + '025': 75, + } + # Extend task_config with variables that are repeatedly used across this class self.task_config.update(AttrDict( { @@ -78,10 +86,11 @@ def __init__(self, config: Dict[str, Any]): 'APREFIX_ENS': f"enkf{self.task_config.RUN.replace('enkf', '')}.t{self.task_config.cyc:02d}z.", 'GPREFIX': f"{_da_prefix}.t{self.task_config.previous_cycle.hour:02d}z.", 'GPREFIX_ENS': f"enkf{_da_prefix}.t{self.task_config.previous_cycle.hour:02d}z.", - 'OCNRES': f"{self.task_config.OCNRES:03d}", 'iau_times_iso': _iau_times_iso, 'observations': _observations, 'bias_files': _bias_files, + 'MOM6_LEVS': _ocnres_to_nlev[f"{self.task_config.OCNRES:03d}"], + 'mom_domain_stack_size': 116640000, # TODO: Make the stack size resolution dependent } )) diff --git a/ush/python/pygfs/task/marine_analysis.py b/ush/python/pygfs/task/marine_analysis.py index 872be06d2ab..3943d83f47c 100644 --- a/ush/python/pygfs/task/marine_analysis.py +++ b/ush/python/pygfs/task/marine_analysis.py @@ -3,7 +3,6 @@ from datetime import datetime from logging import getLogger import os -import pygfs.utils.marine_da_utils as mdau from pygfs.jedi import Jedi from pygfs.task.analysis import Analysis from wxflow import (AttrDict, FileHandler, @@ -60,6 +59,17 @@ def __init__(self, config): _rst_date = to_fv3time(self.task_config.current_cycle) _cice_rst_date = to_fv3time(self.task_config.current_cycle) + # + dt_pseudo = 3 + fcst_hour_list = list(range(6, 10, dt_pseudo)) + _marine_pseudo_model_states = [] + for fcst_hour in fcst_hour_list: + _marine_pseudo_model_states.append({'date': to_isotime(self.task_config.WINDOW_BEGIN + to_timedelta(hours=fcst_hour)), + 'basename': './bkg/', + 'ocn_filename': f"ocean.bkg.f{str(fcst_hour).zfill(3)}.nc" + 'ice_filename': f"ice.bkg.f{str(fcst_hour).zfill(3)}.nc", + 'read_from_file': 1}) + # Create a local dictionary that is repeatedly used across this class self.task_config.update(AttrDict( { @@ -68,10 +78,7 @@ def __init__(self, config): 'berror_model': _berror_model, 'rst_date': _rst_date, 'cice_rst_date': _cice_rst_date, - 'MOM6_LEVS': mdau.get_mom6_levels(str(self.task_config.OCNRES).zfill(3)), - 'DOMAIN_STACK_SIZE': 116640000, # TODO: Make the stack size resolution dependent - 'marine_pseudo_model_states': mdau.gen_bkg_list(bkg_path='./bkg', - window_begin=self.task_config.WINDOW_BEGIN) + 'marine_pseudo_model_states': _marine_pseudo_model_states } )) @@ -109,18 +116,21 @@ def initialize(self) -> None: # prepare the deterministic MOM6 input.nml logger.info(f"Preparing deterministic MOM6 input namelist") - mdau.prep_input_nml(self.task_config) + parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + self.task_config, + output_file="mom_input.nml") # prepare the input.nml for the analysis geometry logger.info(f"Preparing analysis geometry input namelist") - mdau.prep_input_nml(self.task_config, output_nml="./anl_geom/mom_input.nml", - simple_geom=True, mom_input="./anl_geom/MOM_input") + parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input_anlgeom.nml.j2'), + self.task_config, + output_file="./anl_geom/mom_input.nml") # assert that dates of the history files are correct - mdau.test_hist_date('./INPUT/MOM.res.nc', self.task_config.WINDOW_BEGIN) + test_hist_date('./INPUT/MOM.res.nc', self.task_config.WINDOW_BEGIN) for state in self.task_config.marine_pseudo_model_states: - mdau.test_hist_date(state['basename'] + state['ocn_filename'], - datetime.strptime(state['date'], '%Y-%m-%dT%H:%M:%SZ')) + test_hist_date(state['basename'] + state['ocn_filename'], + to_isotime(state['date'])) # initialize JEDI applications logger.info(f"Initializing JEDI applications") @@ -214,3 +224,18 @@ def initialize_obs_stats(self) -> None: # Initialize the observation statistics logger.info(f"Initializing JEDI SOCA observation statistics application") self.jedi_dict['soca_diag_stats'].initialize(self.task_config) + +@logit(logger) +def test_hist_date(histfile: str, ref_date: datetime) -> None: + """ + Check that the date in the MOM6 history file is the expected one for the cycle. + TODO: Implement the same for seaice + """ + + ncf = Dataset(histfile, 'r') + hist_date = dparser.parse(ncf.variables['time'].units, fuzzy=True) + timedelta(hours=int(ncf.variables['time'][0])) + ncf.close() + logger.info(f"*** history file date: {hist_date} expected date: {ref_date}") + + if hist_date != ref_date: + raise ValueError(f"FATAL ERROR: Inconsistent bkg date'") diff --git a/ush/python/pygfs/task/marine_bmat.py b/ush/python/pygfs/task/marine_bmat.py index 297d5e608a4..a611977daf2 100644 --- a/ush/python/pygfs/task/marine_bmat.py +++ b/ush/python/pygfs/task/marine_bmat.py @@ -3,7 +3,6 @@ import os import glob from logging import getLogger -import pygfs.utils.marine_da_utils as mdau from pygfs.task.analysis import Analysis from wxflow import (AttrDict, FileHandler, Executable, add_to_datetime, to_timedelta, to_isotime, @@ -53,8 +52,6 @@ def __init__(self, config): 'CALC_SCALE_EXEC': _calc_scale_exec, 'ENSPERT_RELPATH': _enspert_relpath, 'CALC_SCALE_EXEC': _calc_scale_exec, - 'MOM6_LEVS': mdau.get_mom6_levels(str(self.task_config.OCNRES)), - 'DOMAIN_STACK_SIZE': 116640000, # TODO: Make the stack size resolution dependent } )) @@ -91,11 +88,14 @@ def initialize(self) -> None: FileHandler(self.task_config.data_in).sync() # prepare the deterministic MOM6 input.nml - mdau.prep_input_nml(self.task_config) + parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + self.task_config, + output_file="mom_input.nml") # prepare the input.nml for the analysis geometry - mdau.prep_input_nml(self.task_config, output_nml="./anl_geom/mom_input.nml", - simple_geom=True, mom_input="./anl_geom/MOM_input") + parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input_anlgeom.nml.j2'), + self.task_config, + output_file="./anl_geom/mom_input.nml") # initialize vtscales python script vtscales_config = self.jedi_dict['soca_parameters_diffusion_vt'].render_jcb(self.task_config, 'soca_vtscales') @@ -147,7 +147,7 @@ def execute(self) -> None: exec_name = self.task_config.CALC_SCALE_EXEC exec_cmd.add_default_arg(exec_name) exec_cmd.add_default_arg('soca_vtscales.yaml') - mdau.run(exec_cmd) + exec_cmd() self.jedi_dict['soca_parameters_diffusion_vt'].execute() diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 79f87fa1e72..52afc6a7bfa 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import os -import pygfs.utils.marine_da_utils as mdau from logging import getLogger from pygfs.task.analysis import Analysis from pygfs.jedi import Jedi @@ -51,7 +50,6 @@ def __init__(self, config: Dict) -> None: 'ENSPERT_RELPATH': _enspert_relpath, 'letkf_app': 'true', 'DIST_HALO_SIZE': 3500000, - 'DOMAIN_STACK_SIZE': 116640000, # TODO: Make the stack size resolution dependent } )) @@ -86,7 +84,9 @@ def initialize(self): # prepare the ensemble MOM6 input.nml logger.info(f"Preparing ensemble MOM6 input namelist") - mdau.prep_input_nml(self.task_config) + parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + self.task_config, + output_file="mom_input.nml") # initialize JEDI applications logger.info(f"Initializing JEDI applications") diff --git a/ush/python/pygfs/task/marine_recenter.py b/ush/python/pygfs/task/marine_recenter.py index d66a47e7202..3a821c6f153 100644 --- a/ush/python/pygfs/task/marine_recenter.py +++ b/ush/python/pygfs/task/marine_recenter.py @@ -3,7 +3,6 @@ from logging import getLogger import os from typing import Dict -import pygfs.utils.marine_da_utils as mdau from pygfs.jedi import Jedi from pygfs.task.analysis import Analysis from wxflow import (AttrDict, FileHandler, @@ -55,7 +54,6 @@ def __init__(self, config: Dict) -> None: 'PARMmarine': os.path.join(self.task_config.PARMgfs, 'gdas', 'marine'), 'ENSPERT_RELPATH': _enspert_relpath, 'cice_rst_date': _cice_rst_date, - 'DOMAIN_STACK_SIZE': 116640000, # TODO: Make the stack size resolution dependent } )) @@ -89,7 +87,9 @@ def initialize(self): FileHandler(self.task_config.data_in).sync() # prepare the MOM6 input.nml - mdau.prep_input_nml(self.task_config) + parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + self.task_config, + output_file="mom_input.nml") # initialize JEDI applications logger.info(f"Initializing JEDI applications") From 78ee18da9c53eb558a4bb48460b67e5c8ed1e543 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Wed, 17 Dec 2025 19:07:05 +0000 Subject: [PATCH 02/12] Missed something --- ush/python/pygfs/task/marine_analysis.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ush/python/pygfs/task/marine_analysis.py b/ush/python/pygfs/task/marine_analysis.py index 3943d83f47c..ecb7b066e18 100644 --- a/ush/python/pygfs/task/marine_analysis.py +++ b/ush/python/pygfs/task/marine_analysis.py @@ -6,7 +6,7 @@ from pygfs.jedi import Jedi from pygfs.task.analysis import Analysis from wxflow import (AttrDict, FileHandler, - to_timedelta, to_fv3time, + to_timedelta, to_fv3time, to_isotime, parse_j2yaml, logit) @@ -130,7 +130,7 @@ def initialize(self) -> None: test_hist_date('./INPUT/MOM.res.nc', self.task_config.WINDOW_BEGIN) for state in self.task_config.marine_pseudo_model_states: test_hist_date(state['basename'] + state['ocn_filename'], - to_isotime(state['date'])) + datetime.strptime(state['date'], '%Y-%m-%dT%H:%M:%SZ')) # initialize JEDI applications logger.info(f"Initializing JEDI applications") From 68b86194f34c3aaf72356f9396c8be07934d8f9d Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Wed, 17 Dec 2025 21:07:29 +0000 Subject: [PATCH 03/12] Debug --- sorc/wxflow | 2 +- ush/python/pygfs/task/marine_analysis.py | 4 ++-- ush/python/pygfs/task/marine_bmat.py | 2 +- ush/python/pygfs/task/marine_letkf.py | 2 +- ush/python/pygfs/task/marine_recenter.py | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sorc/wxflow b/sorc/wxflow index afbbf2da25e..de88f849241 160000 --- a/sorc/wxflow +++ b/sorc/wxflow @@ -1 +1 @@ -Subproject commit afbbf2da25ed8f8e539fc379dff96b7956448f95 +Subproject commit de88f849241a7e5d7563d99d6543544f7faf785d diff --git a/ush/python/pygfs/task/marine_analysis.py b/ush/python/pygfs/task/marine_analysis.py index ecb7b066e18..6c8e7877b23 100644 --- a/ush/python/pygfs/task/marine_analysis.py +++ b/ush/python/pygfs/task/marine_analysis.py @@ -7,7 +7,7 @@ from pygfs.task.analysis import Analysis from wxflow import (AttrDict, FileHandler, to_timedelta, to_fv3time, to_isotime, - parse_j2yaml, + parse_j2yaml, parse_j2tmpl, logit) logger = getLogger(__name__.split('.')[-1]) @@ -59,7 +59,7 @@ def __init__(self, config): _rst_date = to_fv3time(self.task_config.current_cycle) _cice_rst_date = to_fv3time(self.task_config.current_cycle) - # + # Generate list of pseudo model states dt_pseudo = 3 fcst_hour_list = list(range(6, 10, dt_pseudo)) _marine_pseudo_model_states = [] diff --git a/ush/python/pygfs/task/marine_bmat.py b/ush/python/pygfs/task/marine_bmat.py index a611977daf2..611da43d925 100644 --- a/ush/python/pygfs/task/marine_bmat.py +++ b/ush/python/pygfs/task/marine_bmat.py @@ -7,7 +7,7 @@ from wxflow import (AttrDict, FileHandler, Executable, add_to_datetime, to_timedelta, to_isotime, chdir, - parse_j2yaml, save_as_yaml, + parse_j2yaml, parse_j2tmpl, save_as_yaml, logit) from pygfs.jedi import Jedi diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 52afc6a7bfa..67fc19e8113 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -6,7 +6,7 @@ from pygfs.jedi import Jedi from typing import Dict from wxflow import (AttrDict, Executable, FileHandler, - parse_j2yaml, save_as_yaml, + parse_j2yaml, parse_j2tmpl, save_as_yaml, to_timedelta, to_YMDH, logit) diff --git a/ush/python/pygfs/task/marine_recenter.py b/ush/python/pygfs/task/marine_recenter.py index 3a821c6f153..9ac17974072 100644 --- a/ush/python/pygfs/task/marine_recenter.py +++ b/ush/python/pygfs/task/marine_recenter.py @@ -7,7 +7,7 @@ from pygfs.task.analysis import Analysis from wxflow import (AttrDict, FileHandler, add_to_datetime, to_timedelta, to_fv3time, to_isotime, - parse_j2yaml, + parse_j2yaml, parse_j2tmpl, logit) logger = getLogger(__name__.split('.')[-1]) From 05261758204a14a5f55937b7c6e3cc60ac1f6cc8 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Thu, 18 Dec 2025 15:00:27 +0000 Subject: [PATCH 04/12] Debug --- ush/python/pygfs/task/analysis.py | 22 +++++++++++++++++++++- ush/python/pygfs/task/marine_analysis.py | 14 +++++++++----- ush/python/pygfs/task/marine_bmat.py | 6 +++--- ush/python/pygfs/task/marine_letkf.py | 2 +- ush/python/pygfs/task/marine_recenter.py | 2 +- 5 files changed, 35 insertions(+), 11 deletions(-) diff --git a/ush/python/pygfs/task/analysis.py b/ush/python/pygfs/task/analysis.py index 2a16ed30937..3fd0ef928b8 100644 --- a/ush/python/pygfs/task/analysis.py +++ b/ush/python/pygfs/task/analysis.py @@ -6,7 +6,7 @@ import os import tarfile from typing import Any, Dict -from wxflow import (AttrDict, Task, WorkflowException, +from wxflow import (AttrDict, Task, WorkflowException, Executable, add_to_datetime, to_timedelta, to_isotime, parse_j2yaml, logit) @@ -106,6 +106,26 @@ def finalize(self) -> None: def clean(self) -> None: super().clean() + @staticmethod + @logit(logger) + def run(exec_cmd: Executable) -> None: + """Run the executable command + This method will run the executable command + Parameters + ---------- + exec_cmd: Executable + executable command to run + Returns + ---------- + None + """ + + logger.info(f"Executing {exec_cmd}") + try: + exec_cmd() + except WorkflowException as e: + raise WorkflowException(f"An error occurred during execution of {exec_cmd}:\n{e}") from e + @logit(logger) def untar_bias_corrections(self) -> None: """Extract bias correction files from tarballs diff --git a/ush/python/pygfs/task/marine_analysis.py b/ush/python/pygfs/task/marine_analysis.py index 6c8e7877b23..25ed1e849da 100644 --- a/ush/python/pygfs/task/marine_analysis.py +++ b/ush/python/pygfs/task/marine_analysis.py @@ -1,6 +1,8 @@ #!/usr/bin/env python3 -from datetime import datetime +from datetime import datetime, timedelta +import dateutil.parser as dparser +from netCDF4 import Dataset from logging import getLogger import os from pygfs.jedi import Jedi @@ -63,10 +65,12 @@ def __init__(self, config): dt_pseudo = 3 fcst_hour_list = list(range(6, 10, dt_pseudo)) _marine_pseudo_model_states = [] + bkg_date = self.task_config.WINDOW_BEGIN for fcst_hour in fcst_hour_list: - _marine_pseudo_model_states.append({'date': to_isotime(self.task_config.WINDOW_BEGIN + to_timedelta(hours=fcst_hour)), + bkg_date = bkg_date + timedelta(hours=dt_pseudo) + _marine_pseudo_model_states.append({'date': to_isotime(bkg_date), 'basename': './bkg/', - 'ocn_filename': f"ocean.bkg.f{str(fcst_hour).zfill(3)}.nc" + 'ocn_filename': f"ocean.bkg.f{str(fcst_hour).zfill(3)}.nc", 'ice_filename': f"ice.bkg.f{str(fcst_hour).zfill(3)}.nc", 'read_from_file': 1}) @@ -116,13 +120,13 @@ def initialize(self) -> None: # prepare the deterministic MOM6 input.nml logger.info(f"Preparing deterministic MOM6 input namelist") - parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + parse_j2tmpl(os.path.join(self.task_config.PARMmarine, 'mom_input.nml.j2'), self.task_config, output_file="mom_input.nml") # prepare the input.nml for the analysis geometry logger.info(f"Preparing analysis geometry input namelist") - parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input_anlgeom.nml.j2'), + parse_j2tmpl(os.path.join(self.task_config.PARMmarine, 'mom_input_anlgeom.nml.j2'), self.task_config, output_file="./anl_geom/mom_input.nml") diff --git a/ush/python/pygfs/task/marine_bmat.py b/ush/python/pygfs/task/marine_bmat.py index 611da43d925..b499ce8fd13 100644 --- a/ush/python/pygfs/task/marine_bmat.py +++ b/ush/python/pygfs/task/marine_bmat.py @@ -88,12 +88,12 @@ def initialize(self) -> None: FileHandler(self.task_config.data_in).sync() # prepare the deterministic MOM6 input.nml - parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + parse_j2tmpl(os.path.join(self.task_config.PARMmarine, 'mom_input.nml.j2'), self.task_config, output_file="mom_input.nml") # prepare the input.nml for the analysis geometry - parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input_anlgeom.nml.j2'), + parse_j2tmpl(os.path.join(self.task_config.PARMmarine, 'mom_input_anlgeom.nml.j2'), self.task_config, output_file="./anl_geom/mom_input.nml") @@ -147,7 +147,7 @@ def execute(self) -> None: exec_name = self.task_config.CALC_SCALE_EXEC exec_cmd.add_default_arg(exec_name) exec_cmd.add_default_arg('soca_vtscales.yaml') - exec_cmd() + self.run(exec_cmd) self.jedi_dict['soca_parameters_diffusion_vt'].execute() diff --git a/ush/python/pygfs/task/marine_letkf.py b/ush/python/pygfs/task/marine_letkf.py index 67fc19e8113..5a98d45d2e3 100644 --- a/ush/python/pygfs/task/marine_letkf.py +++ b/ush/python/pygfs/task/marine_letkf.py @@ -84,7 +84,7 @@ def initialize(self): # prepare the ensemble MOM6 input.nml logger.info(f"Preparing ensemble MOM6 input namelist") - parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + parse_j2tmpl(os.path.join(self.task_config.PARMmarine, 'mom_input.nml.j2'), self.task_config, output_file="mom_input.nml") diff --git a/ush/python/pygfs/task/marine_recenter.py b/ush/python/pygfs/task/marine_recenter.py index 9ac17974072..ed35934169c 100644 --- a/ush/python/pygfs/task/marine_recenter.py +++ b/ush/python/pygfs/task/marine_recenter.py @@ -87,7 +87,7 @@ def initialize(self): FileHandler(self.task_config.data_in).sync() # prepare the MOM6 input.nml - parse_j2tmpl(os.path.join(task_config.PARMmarine, 'mom_input.nml.j2'), + parse_j2tmpl(os.path.join(self.task_config.PARMmarine, 'mom_input.nml.j2'), self.task_config, output_file="mom_input.nml") From 840843c11aa5a8005ac918f8af3b19c35f62e1b9 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Thu, 18 Dec 2025 15:24:14 +0000 Subject: [PATCH 05/12] pynorms --- ush/python/pygfs/task/analysis.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ush/python/pygfs/task/analysis.py b/ush/python/pygfs/task/analysis.py index 3fd0ef928b8..c89722f49e1 100644 --- a/ush/python/pygfs/task/analysis.py +++ b/ush/python/pygfs/task/analysis.py @@ -66,12 +66,13 @@ def __init__(self, config: Dict[str, Any]): _da_prefix = 'gdas' # Map ocean resolution to number of vertical levels - _ocnres_to_nlev = { - '500': 25, - '100': 75, - '050': 75, - '025': 75, - } + _ocnres_to_nlev = + { + '500': 25, + '100': 75, + '050': 75, + '025': 75 + } # Extend task_config with variables that are repeatedly used across this class self.task_config.update(AttrDict( From 8134709b20432c39c90dff6f7a35518ffd4490db Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Thu, 18 Dec 2025 15:25:26 +0000 Subject: [PATCH 06/12] pynorms --- ush/python/pygfs/task/marine_analysis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ush/python/pygfs/task/marine_analysis.py b/ush/python/pygfs/task/marine_analysis.py index 25ed1e849da..68c24da9631 100644 --- a/ush/python/pygfs/task/marine_analysis.py +++ b/ush/python/pygfs/task/marine_analysis.py @@ -229,6 +229,7 @@ def initialize_obs_stats(self) -> None: logger.info(f"Initializing JEDI SOCA observation statistics application") self.jedi_dict['soca_diag_stats'].initialize(self.task_config) + @logit(logger) def test_hist_date(histfile: str, ref_date: datetime) -> None: """ From 4b01cdfc6391641182026fe63e5f76f4a7a2914c Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Thu, 18 Dec 2025 15:27:44 +0000 Subject: [PATCH 07/12] pynorms --- ush/python/pygfs/task/analysis.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ush/python/pygfs/task/analysis.py b/ush/python/pygfs/task/analysis.py index c89722f49e1..cb7769f613e 100644 --- a/ush/python/pygfs/task/analysis.py +++ b/ush/python/pygfs/task/analysis.py @@ -66,13 +66,10 @@ def __init__(self, config: Dict[str, Any]): _da_prefix = 'gdas' # Map ocean resolution to number of vertical levels - _ocnres_to_nlev = - { - '500': 25, - '100': 75, - '050': 75, - '025': 75 - } + _ocnres_to_nlev = {'500': 25, + '100': 75, + '050': 75, + '025': 75} # Extend task_config with variables that are repeatedly used across this class self.task_config.update(AttrDict( From e5263d671533f3a4ebbed3a68b9e1ee7aa177753 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Fri, 19 Dec 2025 14:38:58 +0000 Subject: [PATCH 08/12] Update gdas hash --- sorc/gdas.cd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sorc/gdas.cd b/sorc/gdas.cd index 4b16faa74a4..e6202d7c9dc 160000 --- a/sorc/gdas.cd +++ b/sorc/gdas.cd @@ -1 +1 @@ -Subproject commit 4b16faa74a41811210789f9e5082aa1f94fef790 +Subproject commit e6202d7c9dca4bd91fc533adb251df6ead86f302 From 1de3064a2861d9b227128737502e598ce967f828 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Sun, 21 Dec 2025 15:12:13 +0000 Subject: [PATCH 09/12] add back missing lines --- ush/python/pygfs/task/analysis.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ush/python/pygfs/task/analysis.py b/ush/python/pygfs/task/analysis.py index 76f39106fa0..4a1eeb5ad84 100644 --- a/ush/python/pygfs/task/analysis.py +++ b/ush/python/pygfs/task/analysis.py @@ -71,6 +71,8 @@ def __init__(self, config: Dict[str, Any]): 'GPREFIX_ENS': f"enkf{_da_prefix}.t{self.task_config.previous_cycle.hour:02d}z.", 'iau_times_iso': _iau_times_iso, 'snow_bkg_path': os.path.join('.', 'bkg/'), # TODO: remove this line + 'MOM6_LEVS': _ocnres_to_nlev[f"{self.task_config.OCNRES:03d}"], + 'mom_domain_stack_size': 116640000, # TODO: Make the stack size resolution dependent } )) From 1227dc79acc5b4ab62291e587cfea7b20ee4db20 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Sun, 21 Dec 2025 15:15:52 +0000 Subject: [PATCH 10/12] More deconflicting --- ush/python/pygfs/task/analysis.py | 1 - 1 file changed, 1 deletion(-) diff --git a/ush/python/pygfs/task/analysis.py b/ush/python/pygfs/task/analysis.py index 4a1eeb5ad84..a8578a07de2 100644 --- a/ush/python/pygfs/task/analysis.py +++ b/ush/python/pygfs/task/analysis.py @@ -70,7 +70,6 @@ def __init__(self, config: Dict[str, Any]): 'GPREFIX': f"{_da_prefix}.t{self.task_config.previous_cycle.hour:02d}z.", 'GPREFIX_ENS': f"enkf{_da_prefix}.t{self.task_config.previous_cycle.hour:02d}z.", 'iau_times_iso': _iau_times_iso, - 'snow_bkg_path': os.path.join('.', 'bkg/'), # TODO: remove this line 'MOM6_LEVS': _ocnres_to_nlev[f"{self.task_config.OCNRES:03d}"], 'mom_domain_stack_size': 116640000, # TODO: Make the stack size resolution dependent } From 71a9f2cd6dfbc3846c9408cd0c5234ed8c2ec355 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Tue, 6 Jan 2026 14:56:32 +0000 Subject: [PATCH 11/12] More informative ValueError message --- ush/python/pygfs/task/marine_analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ush/python/pygfs/task/marine_analysis.py b/ush/python/pygfs/task/marine_analysis.py index 23734044a65..d64e10abb2c 100644 --- a/ush/python/pygfs/task/marine_analysis.py +++ b/ush/python/pygfs/task/marine_analysis.py @@ -254,4 +254,4 @@ def test_hist_date(histfile: str, ref_date: datetime) -> None: logger.info(f"*** history file date: {hist_date} expected date: {ref_date}") if hist_date != ref_date: - raise ValueError(f"FATAL ERROR: Inconsistent bkg date'") + raise ValueError(f"FATAL ERROR: Inconsistent bkg date, Expected {ref_date}, {histfile} contains {hist_date}" From abd7b7544550d87aa26c43fef6b528a7c84fc215 Mon Sep 17 00:00:00 2001 From: DavidNew-NOAA Date: Tue, 6 Jan 2026 15:00:05 +0000 Subject: [PATCH 12/12] pynorms --- ush/python/pygfs/task/marine_analysis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ush/python/pygfs/task/marine_analysis.py b/ush/python/pygfs/task/marine_analysis.py index d64e10abb2c..6f96014ed0a 100644 --- a/ush/python/pygfs/task/marine_analysis.py +++ b/ush/python/pygfs/task/marine_analysis.py @@ -254,4 +254,4 @@ def test_hist_date(histfile: str, ref_date: datetime) -> None: logger.info(f"*** history file date: {hist_date} expected date: {ref_date}") if hist_date != ref_date: - raise ValueError(f"FATAL ERROR: Inconsistent bkg date, Expected {ref_date}, {histfile} contains {hist_date}" + raise ValueError(f"FATAL ERROR: Inconsistent bkg date, Expected {ref_date}, {histfile} contains {hist_date}")