-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A quasi-monotone flux limiter for isopycnal diffusion (Redi) #53
A quasi-monotone flux limiter for isopycnal diffusion (Redi) #53
Conversation
@dengwirda, this is fantastic! I'll test it now. One thing is that your branch name should have |
@dengwirda, in the testing you posted above, did you use the default |
Testing here in case anyone wants to follow along:
I'm running the usual EC30to60 dynamic adjustment, which has been showing some pretty serious nonmonotonicity even with the top 8 layers excluded from Redi diagonal terms in recent runs. I'm excited to see how it behaves with this branch. |
@xylar, yes, so far I've tried
I also have The behaviour with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great! I think this is going to work really well and I'd love to see it go to E3SM as a stealth feature for now and then as the default soon when we can run some more tests.
In my dynamic adjustment run with config_Redi_quasi_monotone_safety_factor = 0.5
, I see:
As desired, max of temperatureMax: 31.203329075339408 <= 33.0 in
damped_adjustment_1/analysis_members/globalStats.0001-01-01_00.00.00.nc
As desired, max of temperatureMax: 31.189221745144472 <= 33.0 in
damped_adjustment_2/analysis_members/globalStats.0001-01-11_00.00.00.nc
As desired, max of temperatureMax: 31.189627181602162 <= 33.0 in
simulation/analysis_members/globalStats.0001-01-31_00.00.00.nc
Excellent, thanks very much for looking at this so quickly @xylar.
What do you think @vanroekel and all? |
@dengwirda This is indeed great. I was waiting to comment here for testing from @xylar. I think we should get some tests going that move us to full integration to E3SM. If we go stealth this requires a 10 year fully coupled test. But I'd suggest we just plan to run a full 100 years with it. However, it likely makes sense to run some simpler tests first as you suggest. For the second testing (diffusing on isopycnals and such) @lconlon and @mark-petersen have some redi tests that are simple diffusion of passive tracers along fixed T&S gradients that you could leverage / expand upon. While that testing is ongoing I can get a version of the code the coupled team would like to use for PR testing (ie.. what there current baseline config is). |
Based on further QU30km testing I'm finding that running with a With this result seeming suspiciously good, I investigated further and found:
Thanks very much everyone for your feedback on this --- @lconlon and @mark-petersen if there are some idealised verification cases available this would be fantastic, and @vanroekel it'd be great to see what affect this has in coupled runs too. |
@dengwirda here is the guidance for testing or the coupled group
|
@dengwirda when I first implemented the Redi operator, I added these two test cases:
These were originally developed in what is now compass legacy, and I never moved them over. But compass legacy still works if you want to use them. I'm not sure if (1) is relevant for a flux limiter, but I think at least (2) would be helpful for simple qualitative comparisons that can be visualized in 2D. The instructions for creating those test cases are in those comments. |
Thanks @mark-petersen, I'll see if I can get the isopycnal diffusion test up and running and will add results here. |
Ugh! Finding (or creating) a conda environment that works with legacy compass can be quite a chore. Let me know how it goes and if I can help. |
Thanks @xylar, but no problems so far --- I've skipped all of the xml business by hacking the mesh-build step into the python IC builder script, and all can then be run from the cmd-line with a fairly recent set of compass modules. |
@vanroekel, @xylar, @mark-petersen and all, |
(RediKappaScaling(k, iCell)*fluxRediZTop(iTr, k) & | ||
* invAreaCell - RediKappaScaling(k + 1, iCell) & | ||
*fluxRediZTop(iTr, k + 1) * invAreaCell) | ||
flux_term3 = rediKappaCell(iCell) * ( & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dengwirda, the C-grid formula for a dot-product definitely requires a factor of 2.0 to average from edges to cells (I say factor of 1/2 on line 366 above, that should be factor of 2). So here on term 3:
we are computing
The general formula for the dot product at the cell center
$(a \cdot b)c = \frac{2}{N}\sum{e=1}^N a_e b_e$
(sorry, github is not rendering that one...)
You can see that with a two simple examples. Take two identical vectors
The same example on a hex, with
Taking the product of normal components
so again we need the factor of 2 to get the correct solution of
That's not a proof, but it was enough to convince me that the factor of two is required.
Of course, it could be that there is a bug with a factor somewhere else. Next I will redo the convergence test for every term using exact polynomial solutions, and that will tell us if the code is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @mark-petersen I know what you mean, but that extra 2.0 currently seems to be associated with some strange deformation in the test case. I'll revisit this and double check.
! includes weights for edge-to-cell remap | ||
fluxRediZTop(iTr, k) = fluxRediZTop(iTr, k) + 0.125_RKIND*dvEdge(iEdge)*( & | ||
slopeTriadDown(k - 1, iCellSelf, iEdge)*(tracers(iTr, k - 1, cell2) - tracers(iTr, k - 1, cell1)) + & | ||
slopeTriadUp(k, iCellSelf, iEdge)*(tracers(iTr, k, cell2) - tracers(iTr, k, cell1))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dengwirda I think your altered version here is correct. From Griffies 1998:
We are looking at
redi_flux_scale(iTr, k, iCell) + 1.0E-16_RKIND) | ||
|
||
tend(iTr, k, iCell) = tend(iTr, k, iCell) + & | ||
rediKappaCell(iCell) * ( & |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the factor of two in term 3 was also removed here. I just wanted to mark that in this PR, as it would be easy to miss. The factor of two in lines 508 and 514 above are for the harmonic mean only, and is unrelated.
@mark-petersen and @dengwirda, what is the status here? It would be amazing to have this in compass so the dynamic adjustment no longer produces out-of-bounds temperatures (MPAS-Dev/compass#331). |
@xylar and all, currently we're running G-case sensitivity with these changes, and as a result the |
I don't want to do E3SM v3 mesh spin-up with code that isn't on E3SM master. But if the only purpose of merging this would be for initial condition dynamic adjustment in compass, that seems like a lot of work for a stop-gap and it would be better to wait until the reformulation is there. That leaves us just running in compass with what we have an keeping an eye on the temperature extrema in the hope that they're not too serious. Because I don't think we can wait for this work to be completed before we create the meshes. |
@dengwirda @mark-petersen @xylar I think with the slope changes and limiter changes in #65 the redi formulation should be redi for updating. What is necessary to start pushing this one through to master? I think it would be best to try get this PR and the other I just opened pushed through in sequence quickly. |
Testing now. This successfully compiles standalone with |
Using gnu debug on chrysalis on the head of this PR (1184e34), the nightly suite passes all except:
Where the first two simply hang when using report:
|
Are these all related to RK4? Or does the third failure use split explicit? The error message you pasted is very confusing. It seems to suggest an issue with |
This is confusing. The third one, The first two pass with intel debug. Let me rebase on master and retest, and I will post again. |
- Add a new config_Redi_use_quasi_monotone_limiter option for the isopycnal diffusion operator to better control non-monotone departure of tracer values. - Limiter expands on existing strategy of disabling cross-fluxes, but uses a more comprehensive test based on min/max values over stencil of neighbouring cells in the adjacent layers.
- Scale cross-fluxes toward zero proportional to the degree of non-monotonicity. Enables softer limiter compared to default on/off switch. Control ramp with quasi_monotone_safety_factor.
- Ensure fluxes are only scaled once by accumulating scaling on cells and then interpolating scaling to edges/levels. - Change default safety_factor to 1.0, based on QU30km spin-ups showing fully monotone behaviour. - Add local variables to OMP directives.
- Update use of triad slope in Redi term-3. - Fix edge-to-cell remapping weights for Redi term-3. - Switch to module-level config. variables.
I rebased locally. That fixed the problem with
I'll look into that. |
@vanroekel do you mind if I force push the rebased branch? |
This isn't my branch / PR so it is probably a better question for @dengwirda |
@mark-petersen, |
@mark-petersen you can push a rebase here if that helps. |
@mark-petersen I was able to fix the floating point error you show above by adding this block just below the
|
1184e34
to
b8c3c99
Compare
Thanks @vanroekel that solved it. With the rebased code I just pushed up, which includes the code in @vanroekel's last comment, this now passes the full nightly suite on chrysalis with gnu debug and intel debug. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on the above discussion and testing, this is now ready to move to E3SM-Project/E3SM
repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is ready to move to the E3SM repo
moved to E3SM-Project#5945 |
This PR addresses a range of issues concerning the isopycnal diffusion operator (Redi):
Tested on cori-haswell + pm-cpu and gnu + openmp.
Formulation
Isopycnal diffusion of a tracer$\psi$ is achieved via a rotated diffusion operator
where$\kappa$ is the diffusivity and $\mathbf{K}$ is a tensor built from the isopycnal slopes $S$ . Integrating over layers via finite-volumes
which leads to the 'four-term' expression that is implemented in MPAS-O
These four terms are denoted$\tau_{1,2,3,4}$ , with the first three evaluated as part of the horizontal operator and the fourth as part of the implicit vertical mixing.
Evaluating$\tau_{3}$
Evaluating the cross-term fluxes$\tau_{2,3}$ is tricky, and a 'slope-triad' formulation is often used to deal with interactions between the isopycnal slopes and the (active) tracer gradients. MPAS-O uses the triad formulation currently.
This PR updates the way the triad slopes are used to evaluate the$\tau_{3}$ term, which needs to be computed at layer interfaces. The new code averages $S \cdot \nabla \psi$ (with up-down triads) using the two layers either side of an interface, compared to the one-sided approach used previously. Centering the evaluation at the layer interface appears to improve the accuracy of the scheme, helping to maintain the shape of tracer profiles being diffused along isopycnals steeply-sloped with respect to the model grid.
Remapping$\tau_{3}$
The$\tau_{3}$ term is evaluated first on edges, and then remapped onto cells. This PR updates the remapping weights, which previously included an extra factor of
2.0
. This was leading to serious errors which would generate spurious 'stripe' instabilities, and contribute a kind of 'anti-diffusion' effect.Flux limiter
It's well known that the cross-terms$\tau_{2,3}$ can generate non-monotone behaviour under certain conditions, so this PR also adds a cross-term flux limiter that attempts to prevent the development of non-monotone tracer values. Compared to the existing approach that enforces a global lower bound (typically zero) as well as allowing diffusion to be turned off in the upper layers of the ocean (
config_Redi_min_layers_diag_terms
), the new approach assembles a min/max bound for every cell in the ocean and deactivates the (potentially non-monotone) cross-term fluxes if a tracer value would violate these bounds otherwise.The limiter bounds are taken as the min/max tracer values over the stencil of the operator --- all cells that are edge neighbours of a given cell over the upper, self, and lower layers.
The limiter may be configured using the new$\gamma$ ramping more aggressively.
config_Redi_quasi_monotone_safety_factor
option, which enables cross-term fluxes to be ramped toward zero proportional to the size of the monotonicity violation, with smallersafety_factors
A hard on/off limiter may be obtained with
config_Redi_quasi_monotone_safety_factor = 0.0
.Global spin-up
Using the new approach, a 1-yr MPAS-O QU30km standalone spin-up shows effectively no departure from initial temperature and salinity bounds, with e.g. the maximum SST remaining > -2 deg and <= 31 deg throughout. This run used the new
config_Redi_use_quasi_monotone_limiter = .true.
and did not disable any surface layers, withconfig_Redi_min_layers_diag_terms = 0
. Previous spin-ups have shown a strong dependence on the number of surface layers disabled, with runs often developing SSTs in excess of 70 deg, exhibiting spurious temperature hot-spots in shelf regions, and ultimately crashing due to strong T/S gradients.While the previous method + analysis has focused on surface effects / layers, non-monotone T/S behaviour should be prevented throughout the ocean in general. Disabling surface layers may also be undesirable in regions where isopycnals outcrop.
QU30km 1-yr standalone-spinup SST:
Idealised tests
Behaviour in the idealised 2d test case has been significantly improved, with arbitrary, sharp tracer distributions now being diffused smoothly along steeply tilted isopycnals for both linear and nonlinear equations-of-state (
EoS = jm
is used here, with Redi applied to T/S + passive tracers):This compares to previous behaviour, in which issues with the$\tau_{3}$ flux led to instabilities:
Even with the fixes to$\tau_{3}$ it appears the flux limiter is still needed to prevent spurious min/max violations and instabilities. The updated code with
config_Redi_use_quasi_monotone_limiter = .false.
showing instabilities in T/S: