diff --git a/.gitignore b/.gitignore index ac94c46ff30..f83211291ef 100644 --- a/.gitignore +++ b/.gitignore @@ -150,7 +150,7 @@ sorc/ocnicepost.fd #------------------------------ # jobs symlinks # scripts symlinks -scripts/exglobal_prep_ocean_obs.py +dev/scripts/exglobal_prep_ocean_obs.py # ush symlinks ush/bufr2ioda_insitu_profile_argo.py ush/bufr2ioda_insitu_profile_bathy.py diff --git a/dev/workflow/rocoto/gfs_cycled_xml.py b/dev/workflow/rocoto/gfs_cycled_xml.py index 6b4542251de..f3792ad43eb 100644 --- a/dev/workflow/rocoto/gfs_cycled_xml.py +++ b/dev/workflow/rocoto/gfs_cycled_xml.py @@ -100,7 +100,6 @@ def get_cycledefs(self): interval_metp_str = interval_gfs_str strings.append(f'\t{sdate_metp_str} {edate_metp_str} {interval_metp_str}') - strings.append(f'\t{edate_gfs_str} {edate_gfs_str} 24:00:00') strings.append('') strings.append('') diff --git a/dev/workflow/rocoto/gfs_tasks.py b/dev/workflow/rocoto/gfs_tasks.py index 4f2c52bc4f1..f3e7c3d3e69 100644 --- a/dev/workflow/rocoto/gfs_tasks.py +++ b/dev/workflow/rocoto/gfs_tasks.py @@ -2001,24 +2001,48 @@ def metp(self): deps = [] dep_dict = {'type': 'task', 'name': f'{self.run}_arch_vrfy'} deps.append(rocoto.add_dependency(dep_dict)) - if self._base["interval_gfs"] < to_timedelta("24H"): - n_lookback = self._base["interval_gfs"] // to_timedelta("6H") - for lookback in range(1, n_lookback + 1): - deps2 = [] + interval_gfs = self._base.get('interval_gfs') + assim_freq = self._base['assim_freq'] + + if interval_gfs < to_timedelta("24H"): + n_lookback = int(interval_gfs // to_timedelta(f"{assim_freq}H")) - 1 + # Check if the previous up to `n_lookback` arch_vrfy tasks have completed + # For interval=6, there are no lookbacks + # For interval=12, check lookback=1 + # For interval=18, check lookback=1,2 + # Only lookback if arch_vrfy is not valid for this cycle + if n_lookback > 0: dep_dict = {'type': 'taskvalid', 'name': f'{self.run}_arch_vrfy', 'condition': 'not'} + deps2 = [] deps2.append(rocoto.add_dependency(dep_dict)) - for lookback2 in range(1, lookback): - offset = timedelta_to_HMS(-to_timedelta(f'{6 * lookback2}H')) - dep_dict = {'type': 'cycleexist', 'condition': 'not', 'offset': offset} - deps2.append(rocoto.add_dependency(dep_dict)) - - edate_gfs = self._base['EDATE'] - edate_metp = edate_gfs.replace(hour=18) - edate_metp_diff = edate_metp - edate_gfs - offset = timedelta_to_HMS(-to_timedelta(f'{edate_metp_diff}H')) - dep_dict = {'type': 'task', 'name': f'{self.run}_arch_vrfy', 'offset': offset} + deps3 = [] + for lookback in range(n_lookback): + offset = timedelta_to_HMS(-to_timedelta(f'{assim_freq * (lookback+1)}H')) + dep_dict = {'type': 'task', 'name': f'{self.run}_arch_vrfy', 'offset': offset} + deps3.append(rocoto.add_dependency(dep_dict)) + + deps2.append(rocoto.create_dependency(dep=deps3, dep_condition='or')) + deps.append(rocoto.create_dependency(dep=deps2, dep_condition='and')) + + # Lastly, check that the last arch_vrfy job is done + # This only happens if the metp cycle is not aligned with the last_gfs cycle + sdate_gfs = self._base.get('SDATE_GFS') + edate = self._base.get('EDATE') + edate_metp = self._base.get('EDATE').replace(hour=(24 - assim_freq)) + n_intervals = int((edate - sdate_gfs) // interval_gfs) + edate_gfs = sdate_gfs + n_intervals * interval_gfs + metp_gfs_offset = edate_metp - edate_gfs + if metp_gfs_offset > to_timedelta("0H") and metp_gfs_offset < to_timedelta("24H"): + deps2 = [] + dep_dict = {'type': 'taskvalid', 'name': f'{self.run}_arch_vrfy', 'condition': 'not'} + deps2.append(rocoto.add_dependency(dep_dict)) + dep_dict = {'type': 'task', 'name': f'{self.run}_arch_vrfy', 'offset': timedelta_to_HMS(-metp_gfs_offset)} + deps2.append(rocoto.add_dependency(dep_dict)) + for i in range(1, int((metp_gfs_offset.seconds / 3600) // assim_freq)): + dep_dict = {'type': 'cycleexist', 'offset': timedelta_to_HMS(-to_timedelta(f'{assim_freq * i}H')), 'condition': 'not'} deps2.append(rocoto.add_dependency(dep_dict)) - deps.append(rocoto.create_dependency(dep_condition='and', dep=deps2)) + + deps.append(rocoto.create_dependency(dep=deps2, dep_condition='and')) dependencies = rocoto.create_dependency(dep_condition='or', dep=deps) diff --git a/dev/workflow/rocoto/tasks.py b/dev/workflow/rocoto/tasks.py index 5a892af4d21..b5d48e994bb 100644 --- a/dev/workflow/rocoto/tasks.py +++ b/dev/workflow/rocoto/tasks.py @@ -415,7 +415,7 @@ def get_resource(self, task_name): service_task = task_name in Tasks.SERVICE_TASKS if task_name not in Tasks.VALID_TASKS: - raise KeyError(f"ERROR {task_name} is not a valid tasks!") + raise KeyError(f"ERROR {task_name} is not a valid task!") # Combine the task configuration with the system configuration if service_task: