Add submesoscale eddy parametrization - #438
Conversation
|
The parametrization unit tests are passing. However, after turning it on in the baroclinic channel polaris test with the default parameters, I see NaNs after about 3 hours of simulation time, so there is still some debugging to be done. Moreover, user and developer documentation needs to be added. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a new submesoscale eddy parameterization module (Fox-Kemper
et al. 2011) into Omega’s ocean model, wires it into initialization/finalization
and tendency/auxiliary-state workflows, and adds a dedicated unit test plus
broad test-harness updates to support new analytic-field helper signatures.
Changes:
- Add
SubmesoEddiesmodule (config-driven) and integrate it into ocean module
init/finalize and auxiliary-state computation. - Introduce
TransportAuxVars::NormalTransportVelocityand use it in thickness
and tracer tendency computations as the transport velocity (optionally
including submesoscale-induced velocity). - Update unit test utilities and many tests to accommodate updated analytic
field setters; addSubmesoEddiesTest.
Reviewed changes
Copilot reviewed 21 out of 21 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| components/omega/test/timeStepping/TimeStepperTest.cpp | Initialize/destroy SubmesoEddies in the time stepper test harness. |
| components/omega/test/ocn/TendencyTermsTest.cpp | Update analytic-field lambdas to match updated setScalar/setVectorEdge signatures. |
| components/omega/test/ocn/TendenciesTest.cpp | Initialize/destroy SubmesoEddies; update analytic-field lambdas and setScalar/setVectorEdge call signatures. |
| components/omega/test/ocn/SubmesoEddiesTest.cpp | New unit test covering mixed-layer depth, buoyancy gradient, and eddy velocity computations. |
| components/omega/test/ocn/OceanTestCommon.h | Extend setScalar/setVectorEdge helpers to pass element indices and optional Z coordinates. |
| components/omega/test/ocn/HorzOperatorsTest.cpp | Update analytic-field lambdas to match updated helper signatures. |
| components/omega/test/ocn/AuxiliaryVarsTest.cpp | Update analytic-field lambdas to match updated helper signatures. |
| components/omega/test/ocn/AuxiliaryStateTest.cpp | Initialize/destroy SubmesoEddies; update analytic-field lambdas and helper call signatures. |
| components/omega/test/CMakeLists.txt | Register new SUBMESOEDDIES_TEST. |
| components/omega/src/timeStepping/ForwardBackwardStepper.cpp | Pass tracer array into thickness tendency computation. |
| components/omega/src/ocn/Tendencies.h | Extend thickness tendency API to accept a tracer array (for aux-state computations). |
| components/omega/src/ocn/Tendencies.cpp | Route thickness/tracer tendencies through new aux-state compute routines and use NormalTransportVelocity. |
| components/omega/src/ocn/SubmesoEddies.h | New SubmesoEddies public interface. |
| components/omega/src/ocn/SubmesoEddies.cpp | New implementation and IO field registration for SubmesoEddies. |
| components/omega/src/ocn/OceanInit.cpp | Initialize SubmesoEddies during ocean module init. |
| components/omega/src/ocn/OceanFinal.cpp | Destroy SubmesoEddies during ocean finalize. |
| components/omega/src/ocn/auxiliaryVars/TransportAuxVars.h | New aux-var container for NormalTransportVelocity. |
| components/omega/src/ocn/auxiliaryVars/TransportAuxVars.cpp | Register/unregister IO field for NormalTransportVelocity. |
| components/omega/src/ocn/AuxiliaryState.h | Add TransportAuxVars member and new aux compute entry points. |
| components/omega/src/ocn/AuxiliaryState.cpp | Compute Brunt–Väisälä frequency, compute transport velocity (optionally + submeso), and use it for vertical pseudo-velocity. |
| components/omega/configs/Default.yml | Add Omega.Submeso configuration group and defaults. |
| KOKKOS_LAMBDA(int IEdge, const TeamMember &Team) { | ||
| const int KMin = MinLayerEdgeBot(IEdge); | ||
| const int KMax = MaxLayerEdgeTop(IEdge); | ||
| const int KRange = vertRangeChunked(KMin, KMax); | ||
|
|
||
| parallelForInner( | ||
| Team, KRange, INNER_LAMBDA(int KChunk) { | ||
| LocPseudoThicknessAux.computeVarsOnEdge( | ||
| IEdge, KChunk, PseudoThick, NormalVelEdge); | ||
| }); |
| /// Destroy instance of SubmesoEddies | ||
| void SubmesoEddies::destroyInstance() { | ||
| delete Instance; | ||
| Instance = nullptr; | ||
| } |
1d3f283 to
9825eda
Compare
TestingCTest unit tests
Polaris
|
|
The baroclinic channel test is now running stably with the submesoscale eddy parametrization turned on. This PR is ready for review. However, I haven't checked that the parametrization has the intended effect, and I'm not sure that I'm the best person to do that. @vanroekel could you help with this kind of testing ? |
|
@mwarusz I ran a couple tests with baroclinic channel and it's too hard to tell what the effects must be. We need to add a mixed layer. Let me look and see how straight forward that might be. |
|
update - I have a mixed layer variant of baroclinic channel I have a test run in the queue on frontier. Hopefully will have results by Monday |
| PseudoThickML, GradBuoyML, BVFreqML); | ||
|
|
||
| GradBuoyML /= PseudoThickML; | ||
| BVFreqML /= PseudoThickML; |
There was a problem hiding this comment.
@mwarusz for small ML this could be be problematic, it's not clear above in the MLD code if there is a floor. maybe it's not an issue though
There was a problem hiding this comment.
I agree that we should probably add a tiny value here. MPAS-O has it.
| Team, Range{MinLyrEdgeBot, IndexMLEdge}, | ||
| INNER_LAMBDA(int K, Real &AccumThick, Real &AccumGradBuoy, | ||
| Real &AccumBVFreq) { | ||
| const Real PseudoThickKm1 = |
There was a problem hiding this comment.
If your function starts at MinLyrEdgeBot can this lead to values lower than min layer edge?
There was a problem hiding this comment.
No, this variable is set to
((K - 1) >= MinLyrEdgeBot ? MeanPseudoThickEdge(IEdge, K - 1) : 0)
which is 0 for K = MinLyrEdgeBot. In the end an average of PseudoThickKm1 and PseudoThickK is used. This means that for K = MinLyrEdgeBot you get
PseudoThickAvg = 0.5 * (0 + MeanPseudoThickEdge(IEdge, MinLyrEdgeBot));
This is a kinda hacky treatment of the first half layer. I will add a comment to explain this.
|
@mwarusz in testing I'm getting NaN for EddyVelocity quickly. CoPilot added some guards on the ML average and zero initializing and it fixed the NaN issue. I can point you at what the changes made were if you'd like |
Please do. |
|
here it is - https://github.com/vanroekel/E3SM/tree/temp-submeso-branch There is some extra stuff that is adding more diagnostics as well. |
|
Hmm, Copilot added this check but afterwards it is also explicitly checking for NaNs and skipping calculations if it finds any. It would good to see if the first check is enough. |
89aae38 to
3660296
Compare
3660296 to
a7bd36d
Compare
This PR adds the submesoscale eddy parametrization in the form presented in Fox-Kemper et al. 2011. The parametrization class provides three main methods that
respectively. A new auxiliary variable named
NormalTransportVelocityhas been added. This velocity variable is used to advect pseudo-thickness and tracers, and can optionally include the submesocale induced velocity.Checklist
Testingwith the following:have been run on and indicate that are all passing.
has passed, using the Polaris
e3sm_submodules/Omegabaseline-pfor both the baseline (Polarise3sm_submodules/Omega) and the PR build