Fixing a restart file issue with Isca - #310
Draft
sit23 wants to merge 1 commit into
Draft
Conversation
…inconsistency pbltop and gust are one-timestep-lagged coupling variables: vert_turb_driver diagnoses each of them once per step, and the value is consumed by damping_driver (pbltop) or surface_flux (gust) at the start of the *next* step. Neither was ever written to or read from a restart file, so every restarted leg re-entered with gust reset to its cold-start default (1.0) and pbltop reset to whatever was left in freshly allocated (uninitialized) memory, instead of the value a continuous run would have carried forward. This injected a real perturbation at every restart boundary that grew through the coupled nonlinear dynamics, so a moist run split into several restarted legs diverged from the same run executed in one go. Held-Suarez was unaffected because it never exercises this turbulence/diffusion code path (turb=.true.). Confirmed via reproduction: before this change, 2 days run continuously vs. 1+1 days with a restart in between gave bit-identical results for Held-Suarez but substantially different results for the Frierson aquaplanet test case, with the divergence already present after a single post-restart timestep. After restoring pbltop/gust via a new idealized_moist_phys.res restart file (same read_data/write_data pattern already used by mixed_layer.F90), both cases are now bit-for-bit identical either way. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VKDGrWKLSWXdYytsu4Gx8P
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Fix moist-physics restart inconsistency: restore
pbltopandgustProblem
Running Isca's moist idealized physics (e.g. the Frierson aquaplanet test case) for N days in one continuous run gives different results than running the same N days split across multiple restarted legs (e.g. one day at a time). This does not happen for the dry Held-Suarez configuration. This problem was discussed recently with Spencer Hill.
Root cause
In
src/atmos_spectral/driver/solo/idealized_moist_phys.F90, two module-level arrays implement a deliberate one-timestep-lagged coupling between the boundary-layer turbulence scheme and other physics, active wheneverturb=.true.(the default for realistic moist setups like Frierson):pbltop:vert_turb_driverdiagnoses the PBL-top height each timestep; that value is fed intodamping_driver's sponge-layer calculation on the following timestep.gust:vert_turb_driverdiagnoses surface gustiness each timestep; that value is fed intosurface_fluxon the following timestep.Neither variable was ever written to, or read from, a restart file — this driver performed no restart I/O of its own.
gustwas given a fixed cold-start default (1.0);pbltopwas left entirely uninitialized (allocate()with no initializer — whatever bytes happened to be in that memory).Consequently, every restarted leg silently discarded the evolved value of these two variables and substituted the cold-start default for exactly one timestep, injecting a real (not roundoff-level) perturbation right at the restart boundary. That perturbation then propagated through the fully coupled nonlinear dynamics and grew over subsequent timesteps.
This is specific to physics configurations that exercise
vert_turb_driver/vert_diff(turb=.true.), which is why Held-Suarez — which never calls this code path — was unaffected.Fix
Added a proper restart round-trip for both variables, following the same lightweight
read_data/write_datapattern already used elsewhere in this file's sibling driver (mixed_layer.F90):pbltopis now explicitly initialized to0.0at allocation (removing the previous reliance on implicit/uninitialized memory content).INPUT/idealized_moist_phys.res.ncat init, if present.RESTART/idealized_moist_phys.resat shutdown.One file changed:
src/atmos_spectral/driver/solo/idealized_moist_phys.F90(~20 lines).Verification
Reproduction of the bug, and confirmation of the fix
Built a low-resolution Isca and ran each of the following two ways — once as a single continuous run, once split by a restart — comparing the resulting internal model state (restart files) bit-for-bit:
do_diffusivityboundary layer)Bisection (selectively disabling physics components) confirmed the divergence tracked
turbspecifically: disablingturbalone made the moist case bit-identical even before this fix; disabling convection or radiation alone did not.Regression check against
master(trip_test)Ran Isca's
trip_test, comparing this branch againstmaster(d1321ac3), for a normal (non-restarted) 3-day run at full production resolution (T42, 8 cores):All three test cases give bit-identical results to
master, confirming this change does not alter any existing single-run behaviour — it only changes behaviour when a restart file is actually present. (This also empirically confirms thatpbltop's previously-uninitialized memory happened to read as0.0on the platform tested; the fix simply makes that explicit rather than implementation-defined.)Note for reviewers
While tracing this, I also noticed
rough— a separate roughness-length array also passed intovert_turb_driver— is allocated but never assigned anywhere in this file, so it's used with whatever's left in memory. This appears unrelated to the restart bug (the same value would be used consistently throughout any given run, restarted or not) but may be a separate, pre-existing issue worth a follow-up look. Not addressed in this PR.