Skip to content
Open
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
4f48070
Add experiment ID for R2D2
mranst Feb 24, 2026
d32c3b9
Change location that registry happens in
mranst Feb 24, 2026
28be5ba
add key for experiment lifetime
mranst Feb 24, 2026
3d571cf
pycodestyle
mranst Feb 24, 2026
1e65b35
Refactor
mranst Feb 25, 2026
f69dbe5
Load r2d2 modules during experiment creation (#701).
ftgoktas Feb 25, 2026
7041a44
few touches
mranst Feb 25, 2026
07714ea
fix mistake
mranst Feb 26, 2026
07add94
Hard-code debug
mranst Feb 26, 2026
d3abcca
Add option to skip R2D2
mranst Feb 26, 2026
b742b84
Merge branch 'develop' into feature/mranst/skip_r2d2
mranst Mar 10, 2026
08e8674
Fixes
mranst Mar 10, 2026
e42e3b9
remove comma
mranst Mar 10, 2026
a97c229
code_test fix
mranst Mar 10, 2026
51cecfe
Merge branch 'develop' into feature/mranst/skip_r2d2
metdyn Mar 18, 2026
5f332cd
fix templating
mranst Mar 19, 2026
2a5a0f8
Clean cycle after move da restart
mranst Mar 19, 2026
987bbaf
Fixes to workflows
mranst Mar 19, 2026
9119709
Add suite creation test
mranst Mar 20, 2026
4b1a98c
Add to code tests
mranst Mar 20, 2026
eb58146
Add jedi config comparison tests
mranst Mar 23, 2026
912b3f0
Change name of runTest
mranst Mar 23, 2026
7430617
Merge branch 'feature/mranst/code_tests' of discover.nccs.nasa.gov:/h…
mranst Mar 23, 2026
9c342ca
Separate into utility
mranst Mar 23, 2026
13247a2
Add 3dvar_cf
mranst Mar 23, 2026
a0a9d28
Fix update_dict
mranst Mar 23, 2026
4ccbc63
Merge branch 'feature/mranst/skip_r2d2' into feature/mranst/code_tests
mranst Mar 23, 2026
05f8a7d
Add option to mock cycle dir
mranst Mar 23, 2026
1ff3b24
Fix dictionary
mranst Mar 23, 2026
d5602da
Working
mranst Mar 24, 2026
8cc96f8
Refactor and add to other suites
mranst Mar 24, 2026
df0d9df
add test
mranst Mar 24, 2026
3e9a44f
staging
mranst Mar 24, 2026
3d9a7f2
Add to utility scripts
mranst Mar 24, 2026
b25a6dd
Functional
mranst Mar 25, 2026
7a20636
Add script
mranst Mar 26, 2026
cc4cd94
Merge branch 'develop' into feature/mranst/code_tests
mranst Mar 26, 2026
e6a8e05
add to package data
mranst Mar 26, 2026
9edbcff
Add xarray to requirements
mranst Mar 26, 2026
96e9e20
Merge branch 'develop' into feature/mranst/code_tests
mranst Mar 26, 2026
5b7bed3
Update mock configs
mranst Mar 26, 2026
6ffd59b
Remove print statement
mranst Mar 30, 2026
63dac86
Move override file read
mranst Mar 30, 2026
9a5b995
PR review
mranst Mar 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/code_tests/code_tests.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,11 @@ By default, swell will create several directories in the working directory that
```yaml
test_cache_location: /discover/nobackup/<user>/swell-test-cache
```

## Code tests

### Suite creation test
The suite creation test attempts to construct experiments for all suites within swell in a temporary directory. If one fails, try creating the suite on its own to make sure it is configured properly. Ensure all values are valid and are not filled by the templates `defer_to_model` or `defer_to_platform`.

### JEDI Config test
The JEDI config test generates mock configs for jedi executables in a dry-run mode, where obs will not be checked and placeholders will be used for experiment filepaths. These configs are compared against reference files located in `src/swell/test/jedi_configs/`, and named `jedi_<suite>_config.yaml`. Any difference in values in these yamls will cause this test to fail, so ensure any differences created are intentional, then run `swell utility CreateMockConfigs` to automatically generate new reference files for all suites. These new files are placed in the `jedi_config` location in the source code.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that chaning something like start_cycle_point or final_cycle_point in suite_config.py doesn't result in failure. So perhaps it's worth mentioning it here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, added a note for this. I didn't realize this as I was writing this test, but changing the cycle times does not have an effect on the configs, since the cycle directory is replaced with a placeholder and swell is not checking for obs

6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ dependencies = [
"h5py>=3.7.0",
"flake8==6.1.0",
"netCDF4",
"ruamel.yaml==0.17.16"
"ruamel.yaml==0.17.16",
"xarray==2024.7.0"
]

[project.optional-dependencies]
Expand All @@ -58,7 +59,7 @@ github = [
"isodate==0.6.1",
"f90nml==1.4.4",
"questionary==1.10.0",
"netCDF4==1.6.5",
"netCDF4==1.6.5"
]

[project.urls]
Expand All @@ -74,6 +75,7 @@ swell = [
'deployment/platforms/*/*.yaml',
'suites/**',
'test/suite_tests/*.yaml',
'test/jedi_configs/*.yaml',
'configuration/**',
'utilities/pinned_versions/*.yaml'
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,9 @@ observations:
- tropomi_s5p_no2_tropo
- tempo_no2_total

obs_experiment:
default_value: None

observing_system_records_path:
default_value: None

Expand Down
23 changes: 3 additions & 20 deletions src/swell/deployment/create_experiment.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,6 @@
# --------------------------------------------------------------------------------------------------


def read_override_file(override_path: str | None) -> dict:

yaml = YAML(typ='safe')

if override_path is None:
return {}
else:
with open(override_path, 'r') as f:
return yaml.load(f)

# --------------------------------------------------------------------------------------------------


def clone_config(
configuration: str,
experiment_id: str,
Expand Down Expand Up @@ -233,7 +220,7 @@ def create_experiment_directory(
suite_config: str,
method: str,
platform: str,
override: str,
override: dict,
advanced: bool,
slurm: str | None,
skip_r2d2: bool
Expand All @@ -247,21 +234,17 @@ def create_experiment_directory(
# ---------------
logger = get_logger('SwellCreateExperiment')

# Read override file
# ------------------
override_dict = read_override_file(override)

# Specify whether to skip registering and storing in R2D2
# -------------------------------------------------------
if skip_r2d2:

# Only override this if it is true, otherwise let the suite decide
override_dict['skip_r2d2'] = skip_r2d2
override['skip_r2d2'] = skip_r2d2

# Call the experiment config and suite generation
# ------------------------------------------------
experiment_dict_str = prepare_config(suite, suite_config, method, platform,
override_dict, advanced, slurm)
override, advanced, slurm)

# Load the string using yaml
# --------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ existing_jedi_source_directory:
existing_jedi_source_directory_pinned:
default_value: /discover/nobackup/projects/gmao/advda/jedi_bundles_sles15/current_pinned_jedi_bundle/source/

existing_perllib_path:
default_value: /discover/nobackup/projects/gmao/advda/perllib_opt/GMAO_perllib/g1.0.1/

geos_homdir:
default_value: /discover/nobackup/projects/gmao/advda/SwellStaticFiles/geos/homdirs/coupled_5deg

initial_restarts_method:
default_value: geos_expdir

gmao_perllib_path:
default_value: /discover/nobackup/projects/gmao/advda/perllib_opt/GMAO_perllib/g1.0.1/

path_to_bufr:
default_value: None

Expand Down
2 changes: 1 addition & 1 deletion src/swell/suites/geosadas/flow.cylc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@
[[ GetGeosAdasBackground ]]
script = "swell task GetGeosAdasBackground $config -d $datetime -m geos_atmosphere"

[[RenderJediObservations-{{model_component}}]]
[[RenderJediObservations-geos_atmosphere]]
script = "swell task RenderJediObservations $config -d $datetime -m geos_atmosphere"

[[RunJediVariationalExecutable]]
Expand Down
7 changes: 6 additions & 1 deletion src/swell/swell.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from swell.suites.all_suites import AllSuites
from swell.utilities.welcome_message import write_welcome_message
from swell.utilities.scripts.utility_driver import get_utilities, utility_wrapper
from swell.utilities.suite_utils import read_override_file


# --------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -117,8 +118,12 @@ def create(

"""

# Read override file
override_dict = read_override_file(override)

# Create the experiment directory
create_experiment_directory(suite, input_method, platform, override, advanced, slurm, skip_r2d2)
create_experiment_directory(suite, input_method, platform, override_dict,
advanced, slurm, skip_r2d2)


# --------------------------------------------------------------------------------------------------
Expand Down
5 changes: 5 additions & 0 deletions src/swell/tasks/render_jedi_observations.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ def execute(self) -> None:

cwd = os.getcwd()

if self.config.mock_experiment(False):
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('experiment_root', 'experiment_root')

observations = []

# Iterate through list
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ def execute(self) -> None:
self.jedi_rendering.add_key('analysis_time', analysis_time)
self.jedi_rendering.add_key('analysis_time_iso', analysis_time_iso)

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Geometry
# --------
self.jedi_rendering.add_key('total_processors', self.config.total_processors(None))
Expand Down
7 changes: 7 additions & 0 deletions src/swell/tasks/run_jedi_ensemble_mean_variance.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ def execute(self) -> None:
# Ensemble
self.jedi_rendering.add_key('ensemble_num_members', self.config.ensemble_num_members(None))

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Jedi configuration file
# -----------------------
jedi_config_file = os.path.join(self.cycle_dir(), f'jedi_{jedi_application}_config.yaml')
Expand Down
7 changes: 7 additions & 0 deletions src/swell/tasks/run_jedi_fgat_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ def execute(self) -> None:
background_frequency = self.config.background_frequency()
self.jedi_rendering.add_key('background_frequency', background_frequency)

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Use GEOS utility to generate states
# -----------------------------------
states = self.geos.states_generator(background_frequency, window_length,
Expand Down
7 changes: 7 additions & 0 deletions src/swell/tasks/run_jedi_hofx_ensemble_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ def execute(self) -> None:
self.jedi_rendering.add_key('ensemble_hofx_packets', ensemble_hofx_packets)
self.jedi_rendering.add_key('packet_ensemble_members', packet_ensemble_members)

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Jedi configuration file
# -----------------------
jedi_config_file = os.path.join(self.cycle_dir(),
Expand Down
15 changes: 14 additions & 1 deletion src/swell/tasks/run_jedi_hofx_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,13 @@ def execute(self, ensemble_members: Optional[list] = None) -> None:
self.jedi_rendering.add_key('crtm_coeff_dir', self.config.crtm_coeff_dir(None))
self.jedi_rendering.add_key('window_begin', window_begin)

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Model
# -----
if window_type == '4D':
Expand Down Expand Up @@ -157,6 +164,7 @@ def execute(self, ensemble_members: Optional[list] = None) -> None:
jedi_config_file, output_log_file)
else:
self.logger.info('YAML generated, now exiting.')
return

# If saving the geovals they need to be combined
# ----------------------------------------------
Expand Down Expand Up @@ -262,14 +270,19 @@ def append_gomsaver(
# Add mem to the filename if it is not None
mem_str = f'_mem{mem}' if mem is not None else ''

if not self.config.mock_experiment(False):
cycle_dir = self.cycle_dir()
else:
cycle_dir = 'cycle_dir'

for observer in jedi_config_dict['observations']['observers']:

observation = observer['observation_name']

# Define the GeoVaLs saver dictionary
gom_saver_dict = {
'filter': 'GOMsaver',
'filename': os.path.join(self.cycle_dir(),
'filename': os.path.join(cycle_dir,
f'{observation}-geovals.{window_begin}{mem_str}.nc4')
}

Expand Down
7 changes: 7 additions & 0 deletions src/swell/tasks/run_jedi_local_ensemble_da_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,13 @@ def execute(self) -> None:
self.config.local_ensemble_use_linear_observer())
self.jedi_rendering.add_key('skip_ensemble_hofx', self.config.skip_ensemble_hofx())

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Prevent both 'local_ensemble_save_posterior_mean' and
# 'local_ensemble_save_posterior_ensemble' from being true
# --------------------------------------------------------
Expand Down
7 changes: 7 additions & 0 deletions src/swell/tasks/run_jedi_obsfilters_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ def execute(self, ensemble_members: Optional[list] = None) -> None:
self.jedi_rendering.add_key('crtm_coeff_dir', self.config.crtm_coeff_dir(None))
self.jedi_rendering.add_key('window_begin', window_begin)

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Model
# -----
if window_type == '4D':
Expand Down
7 changes: 7 additions & 0 deletions src/swell/tasks/run_jedi_ufo_tests_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ def execute(self) -> None:
self.jedi_rendering.add_key('crtm_coeff_dir', self.config.crtm_coeff_dir(None))
self.jedi_rendering.add_key('window_begin', window_begin)

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Open the JEDI config file and fill templates
# --------------------------------------------
jedi_config_dict = self.jedi_rendering.render_oops_file(f'{jedi_application}', '3D')
Expand Down
7 changes: 7 additions & 0 deletions src/swell/tasks/run_jedi_variational_executable.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,13 @@ def execute(self) -> None:
self.jedi_rendering.add_key('crtm_coeff_dir', self.config.crtm_coeff_dir(None))
self.jedi_rendering.add_key('window_begin', window_begin)

# Add placeholder names if mock experiment
# ----------------------------------------
if self.config.mock_experiment(False):
self.jedi_rendering.add_key('experiment_root', 'experiment_root')
self.jedi_rendering.add_key('experiment_id', 'experiment_id')
self.jedi_rendering.add_key('cycle_dir', 'cycle_dir')

# Atmosphere background error model
# ---------------------------------
if gsibec_configuration is not None:
Expand Down
Loading
Loading