EBT Backscatter#706
Conversation
Backscatter code using the equivalent barotropic (EBT) mode documented in Yankovsky et al. (2024).
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## dev/gfdl #706 +/- ##
============================================
+ Coverage 37.03% 37.04% +0.01%
============================================
Files 273 273
Lines 82552 82725 +173
Branches 15442 15484 +42
============================================
+ Hits 30572 30646 +74
- Misses 46263 46330 +67
- Partials 5717 5749 +32 ☔ View full report in Codecov by Sentry. |
marshallward
left a comment
There was a problem hiding this comment.
I added a few suggestions. The main one was a proposal to reduce the number of divides in the MEKE src_* calculations. I also noticed some indentations and zombie comments which should be cleaned up.
I think that it might be beneficial to move FrictWork and FrictWork_bh into separate loops, and wrap them with individual id_* checks. (Note that find_FrictWork is a proxy for id_FrictWork > 0.) The if (visc_limit_[hq]_flag)` checks could have a negative impact on performance, and I think it would be better to apply them as a mask (see comments).
I noticed the appearance of ** in computing CS%BS_struct but there is probably not much we can do about it at this time.
Overall I think is at a very high level of quality and should be ready to merge soon.
- Separate FrictWork and FrictWork_bh loops - Simplified the computation for MEKE%mom_src and MEKE%mom_src_bh when MEKE%backscatter_Ro_c /= 0. (cherry picked from commit 8ffc6a8)
Modifications to MOM_hor_visc:
This patch modifies the calculation of `src_btm_drag` to avoid
additional division operations.
We first note the following variable renames:
* `Isfac` is now `damping`, since it describes the net damping or
reduction of any damped fields. `sfac` has been removed since it no
longer appears in the expressions.
* `ldamping` is now `damp_rate`. This is primarily to avoid confusion
with `damping`, but also to more accurately describe its role.
* `ldamping_Strang1` is replaced to `damp_rate_s1`. It is used for a
similar purpose (cacheing of values from the first stage) but now
holds a slightly different value.
The following modifications were made.
1. The conditional split of `sdt` into `sdt_damping` substeps is
quantified by a new term, `damp_step` which is equal to 0.5 or 1.
`sdt_damp` is computed as `sdt * damp_step`.
The presence of `sdt_damp / sdt` in our expressions is replaced with
`damp_step`, which avoids an extra division.
2. The first expression (using new notation) was originally
sfac = 1 + sdt_damp * damp_rate
D = M * (1 - sfac) / (sdt * sfac)
where `D` is `src_btm_drag` and `M` is `MEKE_current(i,j)`
This has been transformed to
D = - M * (sdt_damp * damp_rate)
/ (sdt * (1 + sdt_damp * damp_rate))
= - M * (sdt_damp / sft) * damp_rate
* (1 / (1 + sdt_damp * damp_rate))
= - M * damp_step * damp_rate * damping
This new expression for `D` no longer requires a division.
3. In the second stage expression for `src_btm_drag`, we again use
`damp_rate` to replace `ldamping`. We also use `damp_rate1` to
denote the original value of `ldaming_Strang1`.
sfac = (1 + sdt_damp * damp_rate1) * (1 + sdt_damp * damp_rate)
D = M * (1 - sfac) / (sdt * sfac)
Using `damping1` to denote the damping from the first stage, `D` can
be transformed as follows.
D = -M * (sdt_damp * damp_rate + sdt_damp * damp_rate1
+ sdt_damp**2 * damp_rate * damp_rate1)
/ (sdt * (1 + sdt_damp * damp_rate) * (1 + sdt_damp * damp_rate1))
= -M * (sdt_damp / sdt) * (1 / (1 + sdt_damp * damp_rate))
* (damp_rate + damp_rate1 + sdt_damp * damp_rate * damp_rate1)
/ (1 + sdt_damp * damp_rate1)
= -M * damp_step * damping
* (damp_rate * (1 + sdt_damp * damp_rate1) + damp_rate1)
/ (1 + sdt_damp * damp_rate1)
= -M * damp_step * damping * (damp_rate + damp_rate1 * damping1)
We now store `damp_rate1 * damping1` in `damp_rate_s1(:,:)` rather
than just `damping1`, and can reduce this expression to
D = -M * damp_step * damping * (damp_rate + damp_rate_s1(i,j))
which requires no division. It also requires no additional
read or writes.
Assuming there are no mistakes here, this should only cause negligible
bitwise differences in the results.
Also, comments have been added which explain that we cannot modify the
existing expressions for `MEKE%MEKE`, since they would alter the bitwise
results of existing runs.
In the second stage of Strang splitting, there is a check for `sdt > sdt_damping`, following a check for nonzero `KH` or `K4`. However, `sdt_damp` can only be less than `sdt` when these are nonzero. Otherwise, `sdt_damping` equals `sdt`. Best as I can tell, this check is unnecessary and potentially problematic for optimization. This patch removes the redundant check.
MEKE: No-division implementation of src_btm_drag
Resolved conflicts related to if(h_limit_flag) and new FMA-safe parentheses in FrictWork.
Conflicts resolved
|
Gaea regression: https://gitlab.gfdl.noaa.gov/ogrp/mom6ci/MOM6/-/pipelines/24989 ✔️ 🟡 There are new diagnostics and parameters related to EBT, but otherwise no issues. |
marshallward
left a comment
There was a problem hiding this comment.
This PR looks good now.
Some additional work might be needed on the FrictWork loops, but this can be worked on when the mom_src/GME_snk summations are separated from the main k-loop.
* EBT Backscatter Backscatter code using the equivalent barotropic (EBT) mode documented in Yankovsky et al. (2024). * Modifications to MOM_hor_visc: - Separate FrictWork and FrictWork_bh loops - Simplified the computation for MEKE%mom_src and MEKE%mom_src_bh when MEKE%backscatter_Ro_c /= 0. (cherry picked from commit 8ffc6a8) --------- Co-authored-by: Wenda Zhang <zhangwenda33@hotmail.com> Co-authored-by: Marshall Ward <marshall.ward@noaa.gov>
Backscatter code using the equivalent barotropic (EBT) mode documented in Yankovsky et al. (2024).