KE-conserving correction to velocity remap#277
Conversation
This commit introduces a method that corrects the remapped velocity so that it conserves KE. The correction is activated by setting `REMAP_VEL_CONSERVE_KE = True` The commit also introduces two new diagnostics: `ale_u2` and `ale_v2` These track the change in depth-integrated KE of the u and v components of velocity before the correction is applied. They can be used even if the remapping correction is not turned on.
This commit does two main things. - Limit the magnitude of the multiplicative correction applied to the baroclinic velocity to +25%. This prevents rare occasions where the correction creates very large baroclinic velocities. - Move the diagnostic of KE loss/gain from before the correction to after the correction. Without the limit (above) the correction is exact to machine precision, so there was no point in computing it after the correction. With the new limit it makes sense to compute the diagnostic after the correction.
| real :: rescale_coef ! Factor that scales the baroclinic velocity to conserve ke [nondim] | ||
| real :: u_bt, v_bt ! Depth-averaged velocity components [L T-1 ~> m s-1] | ||
| real :: ke_c_src, ke_c_tgt ! \int [u_c or v_c]^2 dz on src and tgt grids [H L T-1 ~> m2 s-1] | ||
| real, dimension(SZIB_(G),SZJ_(G)) :: du2h_tot ! The rate of change of vertically integrated |
There was a problem hiding this comment.
I agree that du2h_tot and dv2h_tot should have units of [R Z L2 T-3 ~> W m-2], but as currently written they actually have units of R H L2 T-3 ~> W m-2 or kg2 m-5 s-3], as is reflected by the consistent conversion factors in the register_diag_field calls for these diagnostics on lines 365 and 371 above.
This is easily corrected, though, if instead of using GV%Rho0 where du2h_tot and dv2h_tot are calculated at lines 1167 and 1235, we were to use GV%H_to_RZ. In Boussinesq mode, GV%H_to_RZ = GV%Rho0*GV%H_to_m*US%m_to_Z, but in non-Boussinesq mode the thicknesses already include the masses and GV%H_to_RZ is just the (constant) rescaling factor to convert them to units of [kg m-2].
This suggested change has the added benefit of not introducing the Boussinesq reference density (GV%Rho0) into non-Boussinesq calculations. In non-Boussinesq mode, I have been working to avoid the use of GV%H_to_m or GV%H_to_Z whereever possible because they imply division by the arbitrary Boussinesq reference density. In this case the various factors would cancel out mathematically, but multiplying and then diving by 1035 kg m-3 changes answers at roundoff, so they can not be cancelled out after people start using the code without changing answers.
| do k=1,nz | ||
| u2h_tot = u2h_tot + h2(k) * (u_tgt(k)**2) | ||
| enddo | ||
| du2h_tot(I,j) = GV%Rho0 * u2h_tot / dt |
There was a problem hiding this comment.
Please revise this expression from du2h_tot(I,j) = GV%Rho0 * u2h_tot / dt to du2h_tot(I,j) = GV%H_to_RZ * u2h_tot * I_dt with the line if (present(dt)) I_dt = 1.0 / dt added somewhere outside the i- and j- loops for this routine.
Changing out GV%Rho0 for this rescaling factor will place du2h_tot into the documented units of [R Z L2 T-3 ~> W m-2], and it avoids using the Boussinesq reference density in non-Boussinesq cases.
An optimizing compiler will replace the divisions by dt with a multiplication by its reciprocal but without optimizations this won't happen. If we explicitly do this replacement ourselves, we help to ensure that the optimized and non-optimized (debugging) versions of the code are closer to giving the same answers.
| do k=1,nz | ||
| v2h_tot = v2h_tot + h2(k) * (v_tgt(k)**2) | ||
| enddo | ||
| dv2h_tot(I,j) = GV%Rho0 * v2h_tot / dt |
There was a problem hiding this comment.
Please revise this expression from dv2h_tot(i,J) = GV%Rho0 * v2h_tot / dt to dv2h_tot(i,J) = GV%H_to_RZ * v2h_tot * I_dt, for the reasons discussed above with the corresponding suggested changes to du2h_tot.
| 'Rate of change in half rho0 times depth integral of squared zonal'//& | ||
| ' velocity by remapping. If REMAP_VEL_CONSERVE_KE is .true. then '//& | ||
| ' this measures the change before the KE-conserving correction is'//& | ||
| ' applied.', 'W m-2', conversion=US%R_to_kg_m3*GV%H_to_m*US%L_T_to_m_s**2 & |
There was a problem hiding this comment.
If the changes suggested below are made, these conversion factors would become conversion=US%R_to_kg_m3*US%Z_to_m*US%L_T_to_m_s**2*US%s_to_T or equivalently conversion=US%RZ3_T3_to_W_m2*US%L_to_Z**2. The same comment also applies to the register_diag_field() call for CS%id_remap_delta_integ_v2.
Also, it would be more convenient for verifying the consistency between the conversion and units arguments could be kept entirely on the same line and not split the conversion factor with line continuation. In this case, this could easily be accommodated within the 100 character recommended line length by moving 'applied .` up to the preceding line. Also note that the spaces before and after the
continuation between lines 369 and 370 will lead to a double space that we might not want.
This commit addresses @Hallberg-NOAA's comments on [the PR](NCAR#277). Computations of `ale_u2` and `ale_v2` are updated to work correctly in both Boussinesq and non-Boussinesq modes.
|
Thanks @Hallberg-NOAA for your review! I am still working on mastering the unit scalings and Boussinesq vs non aspects of MOM6. I think my latest commit addresses all your comments, but please take a look. |
|
With these changes that you just introduced, it is all looking good to me! |
|
Thanks, @iangrooms, for this contribution, and thanks, @Hallberg-NOAA, for reviewing this PR. The New MOM_input parameter: New available diagnostics: |
|
When I was first implementing this I noticed that the subroutine At the time I discussed this with Alistair, who suggested that I add the logical parameter In short, we have 2 logical parameters controlling this feature. Only one parameter can be set by the user, and it turns the feature on or off. The other parameter is only internal, and serves to ensure that the correction only happens in the places we want it to happen. |
|
Thanks for the clarification! |
| intent(inout) :: v !< Meridional velocity [L T-1 ~> m s-1] | ||
| logical, optional, intent(in) :: debug !< If true, show the call tree | ||
| real, optional, intent(in) :: dt !< time step for diagnostics [T ~> s] | ||
| logical, optional, intent(in) :: allow_preserve_variance !< If true, enables ke-conserving |
There was a problem hiding this comment.
Is this logical parameter necessary?
Looks like CS%conserve_ke is enough to determine if the correction should be applied.
This PR does two things:
ale_u2andale_v2, that measure the rate of depth-integrated KE loss (or gain) associated with remapping velocity. The rates are computed separately for the u and v components, and the output units are Watts per square meter.The correction is described in more detail here ke_conserving_remap.pdf