You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This merge contains final fixes to the ismip7_forcing test group. These include:
A one-line bug fix in config parser when determining fracture forcing verison.
A check on the existence of the final processed forcing file before beginning processing each step. This will be very helpful for restarts in which compass run is executed anywhere higher than the individual step level. Without this, early steps risk being re-run if they had completed in the previous run.
Checklist
Document (in a comment titled Testing in this PR) any testing that was used to verify the changes
When an ismip7_forcing processing step runs, it previously always
regenerated and overwrote its final output. The only resume logic was
at the temporary remapped_* level, which is deleted once a step
completes. This meant re-running a test case (after a partial timeout,
or to process a different scenario) re-did all expensive extrapolate +
ncremap work for steps that already finished.
This commit adds an early 'final output already exists -> info-log and
skip' guard to every forcing step that produces a final output, making
re-runs cheap and idempotent.
Changes:
- Add os.path.exists(dst) check at the start of each run() method,
after source resolution but before any remap work
- Hoist output_file/output_path/dst computation to before the guard
so the tail of run() reuses those variables
- Guard placement ensures each output is checked independently (e.g.
ocean_thermal per-job outputs for AIS OCX ocean choices)
Affected steps (10):
- Atmosphere: process_smb, process_temperature, process_runoff,
process_smb_gradient, process_temperature_gradient
- Ocean thermal: process_thermal_forcing (_process_ocean_forcing and
_run_climatology), build_3d_thermal_forcing
- Fracture: process_excess_melt, process_lake_properties,
process_shelf_collapse
The existing per-year remapped_* skip logic is unchanged; these guards
operate at the final canonical output level.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
I ran compass run at the atmosphere level in a directory where process_smb had already completed. process_smb.log contains this:
compass calling: compass.landice.tests.ismip7_forcing.atmosphere.process_smb.ProcessSmb.runtime_setup()
inherited from: compass.step.Step.runtime_setup()
in /global/cfs/cdirs/m4288/users/trhille/compass/compass/step.py
compass calling: compass.landice.tests.ismip7_forcing.atmosphere.process_smb.ProcessSmb.run()
in /global/cfs/cdirs/m4288/users/trhille/compass/compass/landice/tests/ismip7_forcing/atmosphere/process_smb.py
Using atmosphere source /global/cfs/cdirs/m4288/users/trhille/ISMIP7/forcing/GIS/CESM2-WACCM/ctrl/SDBN1-1000m/acabf/v3
Found 286 SMB files for years 2000-2301
Output already exists, skipping: /global/cfs/cdirs/m4288/users/trhille/ISMIP7/process_forcing_20260929/GIS/CESM2-WACCM_ctrl/atmosphere/GIS_1to10km_r03_20260925_SMB_CESM2-WACCM_ctrl_2000-2301.nc
So, this is cleanly skipping the completed step and moving on to the next.
I have also confirmed that the bug fix in landice/ismip7/archive.py fixes an error I was encountering, And I have run the AIS fracture test case successfully.
The greenland_3d.run() function writes per-chunk output files named by
their start year (e.g., GrIS_..._3dThermalForcing_OCX_2007.nc,
..._2017.nc), not a single file with the full year range. The previous
guard checked for the non-existent full-range filename, so it never
skipped even after a successful run.
This commit fixes the guard to check for the first chunk file (with
start_year only, not start_year-end_year), which greenland_3d.run
actually produces. The check is conservative: it only verifies the
first chunk exists, consistent with the per-year remapped file skip
pattern used in the other ismip7_forcing steps.
Addresses Copilot review comment on PR MPAS-Dev#1001.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
When an ismip7_forcing job times out mid-remap, it can leave truncated
or incomplete remapped_* and extrap_* files. The existing per-file
resume logic reused these based purely on os.path.exists(), silently
feeding bad intermediates into the final concatenation, which then
failed with 'ValueError: coordinate time not present in all datasets'.
This commit adds netcdf_file_is_valid() to compass/landice/ismip7/remap.py,
which checks that a file exists, opens cleanly, contains the expected
variable and (optionally) time coordinate, and can actually read its
last time record (catches header-complete but data-truncated files that
open cleanly but fail later). Each step's per-file skip guard is now:
'file exists AND valid → skip; otherwise delete and regenerate.'
Coverage:
- State 1: file never created → os.path.exists catches it
- State 2: truncated header (bad magic bytes) → raises on open
- State 3: header OK but variable/time missing → presence check
- State 4: header complete but data truncated → last-record .load()
raises (this closes the subtle gap where lazy xarray reads only the
header and the truncated file passes an open+presence check)
Changes:
- Add netcdf_file_is_valid() helper to remap.py
- Update all 5 atmosphere steps (SMB, temperature, runoff, gradients)
to validate both remapped_* (require_time=True) and extrap_* files
- Update ocean_thermal/_process_ocean_forcing (tf, require_time=True)
and _run_climatology (tf, require_time=False — static 3-D field)
- Update fracture/process_shelf_collapse (mask, require_time=True)
No change to excess_melt / lake_properties — those regenerate
intermediates unconditionally (no exists-guard to reuse a stale file).
Fixes the reported 'time not present' concat error and covers all four
interrupted-write states at negligible cost (single-slice read).
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
Prevent truncated destinations from being reused on restart
This new guard treats any existing destination as complete, but the destination is populated later with shutil.copy(), which can leave a truncated .nc if the job is interrupted during the copy. A restart then preserves the truncated forcing; publish atomically and/or validate the final NetCDF before skipping.
I ran into an issue restarting processing after a job timed out because the code could not differentiate between complete and existing-but-incomplete files as of 90fc71a. Here's the error I ran into:
Details
Traceback (most recent call last):
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/bin/compass", line 6, in <module>
sys.exit(main())
~~~~^^
File "/global/cfs/cdirs/m4288/users/trhille/compass/compass/__main__.py", line 63, in main
commands[args.command]()
~~~~~~~~~~~~~~~~~~~~~~^^
File "/global/cfs/cdirs/m4288/users/trhille/compass/compass/run/serial.py", line 206, in main
run_single_step(args.step_is_subprocess)
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^
File "/global/cfs/cdirs/m4288/users/trhille/compass/compass/run/serial.py", line 167, in run_single_step
_run_test(test_case, available_resources)
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/global/cfs/cdirs/m4288/users/trhille/compass/compass/run/serial.py", line 419, in _run_test
_run_step(test_case, step, test_case.new_step_log_file,
~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
available_resources)
^^^^^^^^^^^^^^^^^^^^
File "/global/cfs/cdirs/m4288/users/trhille/compass/compass/run/serial.py", line 470, in _run_step
step.run()
~~~~~~~~^^
File "/global/cfs/cdirs/m4288/users/trhille/compass/compass/landice/tests/ismip7_forcing/atmosphere/process_temperature.py", line 141, in run
self._combine_and_rename(remapped_files, output_file)
~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/global/cfs/cdirs/m4288/users/trhille/compass/compass/landice/tests/ismip7_forcing/atmosphere/process_temperature.py", line 170, in _combine_and_rename
ds = xr.open_mfdataset(remapped_files, concat_dim="time",
combine="nested", engine="netcdf4",
drop_variables="time_bnds")
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/lib/python3.14/site-packages/xarray/backends/api.py", line 1675, in open_mfdataset
combined = _nested_combine(
datasets,
...<7 lines>...
fill_value=dtypes.NA,
)
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/lib/python3.14/site-packages/xarray/structure/combine.py", line 397, in _nested_combine
combined = _combine_nd(
combined_ids,
...<6 lines>...
combine_attrs=combine_attrs,
)
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/lib/python3.14/site-packages/xarray/structure/combine.py", line 262, in _combine_nd
combined_ids = _combine_all_along_first_dim(
combined_ids,
...<6 lines>...
combine_attrs=combine_attrs,
)
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/lib/python3.14/site-packages/xarray/structure/combine.py", line 294, in _combine_all_along_first_dim
new_combined_ids[new_id] = _combine_1d(
~~~~~~~~~~~^
datasets,
^^^^^^^^^
...<6 lines>...
combine_attrs=combine_attrs,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
)
^
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/lib/python3.14/site-packages/xarray/structure/combine.py", line 324, in _combine_1d
combined = concat(
datasets,
...<6 lines>...
combine_attrs=combine_attrs,
)
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/lib/python3.14/site-packages/xarray/structure/concat.py", line 325, in concat
return _dataset_concat(
objs,
...<8 lines>...
create_index_for_new_dim=create_index_for_new_dim,
)
File "/global/cfs/cdirs/m4288/users/trhille/compass/pixi-env/.pixi/envs/default/lib/python3.14/site-packages/xarray/structure/concat.py", line 772, in _dataset_concat
raise ValueError(
f"coordinate {name!r} not present in all datasets."
)
ValueError: coordinate 'time' not present in all datasets.
In commit [9994e92](https://github.com//pull/1001/commits/9994e92d6d151c3f79ee324b1edb3fe1432e8cc7), I added additional checks (detailed in the commit message) that find, delete, and reprocess incomplete files. There may still be some edge cases that are not caught, but this should catch the vast majority of cases.
…d; document validation helper
Copilot findings MPAS-Dev#1-4 were valid:
1. Source version not in filename (HIGH): The forcing archive versions each
source (e.g. v1, v2, v2.1) as a directory, and ForcingSource.version
carries it, but output filenames omitted it. Upgrading from v1 to v2 in
the archive caused the 'skip if exists' guard to reuse stale v1 output.
2. 3-D guard mishandles partial runs (HIGH): The first_chunk guard skipped
the whole step when only the first chunk existed, leaving later chunks
unwritten after a timeout. greenland_3d already has its own PER-CHUNK
skip logic that correctly resumes partial runs.
3. Overwrite config ignored (MEDIUM): The first_chunk guard ran before the
JSON was loaded, defeating a user's 'overwrite=true' request.
greenland_3d's own logic honors cfg.overwrite.
4. netcdf_file_is_valid missing from API (LOW): Function had a complete
docstring but was not registered in the Sphinx autosummary.
Changes:
- Embed source.version (or job.version) in all output filenames, placed
BEFORE the year range: {mesh}_SMB_{model}_{scenario}_{version}_{start}-
{end}.nc. Placement before the year range preserves trailing patterns
that downstream regexes anchor to (_\d{4}-\d{4}$, _(\d{4})\.nc$), so no
changes needed in greenland_3d.py or ismip7_run/set_up_experiment.py.
- Remove the step-level first_chunk guard from build_3d_thermal_forcing.py
(the redundant/conflicting guard added in commit 90fc71a). Delegate to
greenland_3d's own per-chunk skip/overwrite logic, which is finer-grained
(handles partial runs correctly) and overwrite-aware (honors the JSON
cfg.overwrite flag).
- Add remap.netcdf_file_is_valid to docs/developers_guide/landice/api.rst
(before remap.extrapolate_source, following source order).
Affected filenames (10 steps):
- Atmosphere: {version}_{start}-{end}.nc for SMB, temperature, runoff,
gradients
- Ocean: {version}_{start}-{end}.nc for 2D/3D thermal forcing; climatology
already embedded version (unchanged)
- Fracture: {stem}_{version}{ext} (no year range)
Downstream globs (*SMB*.nc, *2dThermalForcing_*.nc) still match; no regex
changes needed. Now a version bump produces a new filename -> guard doesn't
fire -> output regenerates (fixes staleness hazard). The GrIS 3-D path now
honors overwrite and resumes partial runs correctly.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
I had Claude draft up a response to the latest co-pilot review: #1001 (review).
Response to Latest Copilot Review (Sept 29)
Thanks for the additional review. After further investigation, findings 1–4 are all valid and have been fixed.
1. ✅ Source version changes (High) - Conceded + Fixed
Finding: Guard doesn't validate whether source data changed; changing to a new version reuses stale output.
Response: Valid. The output filename was missing the source.version tag. The forcing archive versions each source (e.g. v1, v2, v2.1) as a directory level, but that version was never embedded in the output filename, so upgrading from v1 to v2 in the archive caused the skip guard to reuse stale v1 output.
Fixed: Version is now embedded before the year range in all output filenames: {mesh}_SMB_{model}_{scenario}_{version}_{start}-{end}.nc (and similarly for temperature, runoff, gradients, 2D/3D thermal forcing, fracture). Placed before the year range (not at the end) to preserve trailing _{start}-{end}.nc and _{start}.nc patterns that downstream regexes anchor to. Now a version bump naturally produces a new filename → guard doesn't fire → output regenerates.
2. ✅ All-chunks check (High) - Conceded + Fixed
Finding: Only first chunk is checked; if a previous run completed the first chunk but died mid-generation, later chunks are missing but the step still skips.
Response: Valid. The step-level first_chunk guard was coarse-grained (whole-step, first-chunk-only) and broke partial-run resume.
Fixed: Removed the step-level guard entirely. greenland_3d already has its own per-chunk skip logic (_write_forcing_chunk checks output_path.exists() independently for every chunk). It correctly resumes partial runs: skips completed chunks, writes missing ones. The step-level guard was redundant and conflicting; delegating to the finer-grained internal logic fixes both this and finding 3.
Finding: The early-return guard ignores the overwrite config option.
Response: Valid. The greenland_3d JSON config has an "overwrite": true/false key (the committed greenland_3d_tf_config.json sets it to true). The step-level first_chunk guard ran before the JSON was even loaded, so it had no knowledge of overwrite and returned early, defeating a user's overwrite=true request.
Fixed: Removed the step-level guard (same fix as 2). greenland_3d's per-chunk logic already honors cfg.overwrite: when false, it skips existing chunks; when true, it regenerates them (atomic .partial → os.replace). Now the JSON flag takes effect as intended.
4. ✅ Documentation (Low) - Conceded + Fixed
Finding:netcdf_file_is_valid() lacks documentation for the developer API.
Response: The function has a complete docstring (Parameters, Returns, explanation) in the source, but Copilot correctly flagged that it's not registered in the Sphinx autosummary — it won't appear in the rendered developer's guide.
Fixed: Added remap.netcdf_file_is_valid to docs/developers_guide/landice/api.rst under the compass.landice.ismip7 module block (before remap.extrapolate_source, following source order).
The reason will be displayed to describe this comment to others. Learn more.
I ran the atmosphere, ocean_thermal and fracture cases on Chrysalis against a small synthetic AIS archive (v1, then v2). Skipping on rerun and recovering from truncated or empty intermediate files both work. Two things need fixing (inline). Separately, a bug already on main: excess melt and lake properties (Paths A and B) fail with TypeError: extrapolate_source() got an unexpected keyword argument 'decode_times', and removing that argument from the two calls fixes it. I couldn't test the 3-D Greenland step because the EN4 data isn't on Chrysalis.
Posted by Claude Code on @xylar's behalf. The testing, analysis and wording above are AI-authored; please check them accordingly.
The reason will be displayed to describe this comment to others. Learn more.
With the version in the name, a new version writes a second file next to the old one, but ismip7_run expects exactly one of each. When I went from v1 to v2, its setup exited for SMB, temperature and shelf collapse, and gave runoff and the gradients an empty filename. Output written before this commit also won't be recognized, so a resume reprocesses everything and leaves both files. I'd either take the version out of the filenames (and delete outputs to regenerate) or have each step remove other versions' files when it writes. This applies to all the steps.
The reason will be displayed to describe this comment to others. Learn more.
"When I went from v1 to v2, its setup exited for SMB, temperature and shelf collapse, and gave runoff and the gradients an empty filename." Was this for ismip7_run? I'm not sure I follow what happened with runoff and gradients. Is this a bug in ismip7_run?
"Output written before this commit also won't be recognized, so a resume reprocesses everything and leaves both files." I don't think I care about backward compatibility before this commit, since we can easily manually rename previously processed files if necessary to avoid reprocessing. However, I'll think a little more about it.
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is ismip7_run's set_up_experiment.py. It exits unless it finds exactly one SMB, temperature, 3-D TF or shelf-collapse file. For runoff and the gradients, though, it just leaves the filename empty, so those streams get filename_template="". I didn't check what MALI does with that.
The gap is in ismip7_run, but this PR is what triggers it. Before, a rerun after an archive version bump overwrote the output; now it adds a second file next to the old one. If you'd rather clean up by hand when that happens, that's fine, but then ismip7_run should error on extra runoff and gradient files too.
Agreed on outputs from before this commit; renaming by hand is fine.
Posted by Claude Code on @xylar's behalf. The testing, analysis and wording above are AI-authored; please check them accordingly.
The reason will be displayed to describe this comment to others. Learn more.
With the step guard gone, resuming relies on greenland_3d's per-chunk check, which only skips when overwrite is false. greenland_3d_tf_config.json sets it to true, so every rerun rebuilds all the chunks. Also, a chunk interrupted by a timeout leaves a .partial file, and the restart then raises FileExistsError until someone deletes it. Setting "overwrite": false and removing a stale .partial instead of raising would fix both.
@trhille, those comments are all Claude but they seem sensible to me but if it feels like these are situations you won't actually hit in practice, feel free to push back.
I'm also doing some testing on Perlmutter right now. I'll have Claude report back on that soon (or as soon as the queue allows).
I ran ismip7_forcing on Perlmutter (pm-cpu, gnu/mpich) against the real archive, using 2-year runs. Work directories are in /pscratch/sd/x/xylar/ismip7_pr1001.
AIS atmosphere and ocean_thermal (CESM2-WACCM ssp585, AIS_2to20km_r03): passed. Outputs are named ..._v2_2015-2016.nc and ..._v3_2015-2016.nc, and a rerun skips every step.
GrIS build_3d_thermal_forcing (CESM2-WACCM historical, 1-year chunks, existing OCX melt parameters): both points in my review hold. With "overwrite": true every rerun rebuilds all chunks. A job killed during nccopy leaves a .partial that makes the next run raise FileExistsError, even with "overwrite": false if that chunk was never finished. A kill during the HDF5 write is harmless.
AIS fracture (ssp585, v2.1): with decode_times removed, Paths A, B and C all process and skip on rerun. Their filenames repeat the version, e.g. ..._ismip7_8km-v2.1_v2.1.nc. There is no GrIS fracture data to test.
Unrelated failure
Building the Path A conserve mapping file makes ESMF_RegridWeightGen segfault (ESMF 8.9.1, 128 tasks on one node), reproducibly. The bilinear map from the same source grid builds fine, so I used it for Path A to get past this.
Posted by Claude Code on @xylar's behalf. The testing, analysis and wording above are AI-authored; please check them accordingly.
GrIS build_3d_thermal_forcing (CESM2-WACCM historical, 1-year chunks, existing OCX melt parameters): both points in my review hold. With "overwrite": true every rerun rebuilds all chunks. A job killed during nccopy leaves a .partial that makes the next run raise FileExistsError, even with "overwrite": false if that chunk was never finished. A kill during the HDF5 write is harmless.
A job is extremely unlikely to be interrupted during nccopy, since that command should only take a few seconds, compared with multiple hours for the annual remapping, so i think it's safe to ignore this. We can always manually delete a .partial file if that ever occurs, which seems preferable to adding more code complexity.
AIS fracture (ssp585, v2.1): with decode_times removed, Paths A, B and C all process and skip on rerun. Their filenames repeat the version, e.g. ..._ismip7_8km-v2.1_v2.1.nc. There is no GrIS fracture data to test.
Great, I will make this change. For ISMIP7, we are only planning to use Path C.
Unrelated failure
Building the Path A conserve mapping file makes ESMF_RegridWeightGen segfault (ESMF 8.9.1, 128 tasks on one node), reproducibly. The bilinear map from the same source grid builds fine, so I used it for Path A to get past this.
Yep, that's how OOM manifests with ESMF_RegridWeightGenconserve. You would likely need 4 or 8 nodes to create it successfully.
Yep, that's how OOM manifests with ESMF_RegridWeightGen conserve. You would likely need 4 or 8 nodes to create it successfully.
That makes sense.
Thanks for putting up with the AI flailing. It seems to be more all-over-the place with Compass testing than with Polaris and this isn't a workflow I know as well so I wasn't able to rein it in as well as I would have liked.
Set overwrite=false in greenland_3d_tf_config.json so completed 3-D
thermal forcing chunks are skipped on rerun instead of rebuilt. Sweep
stale *.partial files at the start of greenland_3d.run() and drop the
now-redundant FileExistsError guards, so an interrupted write no longer
blocks the next run.
Remove the unsupported decode_times=False argument from the
extrapolate_source calls in process_excess_melt and
process_lake_properties, which raised TypeError on fracture Paths A/B.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
I've decided not to worry about the versioning issue wrt ismip7_run behavior. It would be very fast for a user to move forcings from prior versions to new directories if needed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This merge contains final fixes to the
ismip7_forcingtest group. These include:compass runis executed anywhere higher than the individual step level. Without this, early steps risk being re-run if they had completed in the previous run.Checklist
Testingin this PR) any testing that was used to verify the changes