Skip to content

Neutral Diffusion: Add option for discontinuous reconstruction of T/S#553

Merged
Hallberg-NOAA merged 46 commits into
mom-ocean:dev/gfdlfrom
ashao:ndiff_update_neutral_position
Aug 16, 2017
Merged

Neutral Diffusion: Add option for discontinuous reconstruction of T/S#553
Hallberg-NOAA merged 46 commits into
mom-ocean:dev/gfdlfrom
ashao:ndiff_update_neutral_position

Conversation

@ashao
Copy link
Copy Markdown
Collaborator

@ashao ashao commented Jul 13, 2017

This PR adds the option to connect neutral surfaces using a discontinuous reconstruction of temperature and salinity (after drawing 100s of arrows and surfaces on paper, writing new logic, throwing it away, drawing more arrows, and finally coming up with a consistent algorithm). A notebook demonstrating the algorithm for some simple test cases can be found at: https://github.com/ashao/MOM6_analysis/blob/master/neutral_diffusion/neutral_diffusion_examples.ipynb. This is controlled by the runtime parameter NDIFF_CONTINUOUS which is by default True if using the original continuous parabolic reconstructions and false if doing a discontinuous PPM reconstruction.

The main deficiency of this algorithm as it stands is that T/S in the top and bottom boundary layers are using a piecewise continuous reconstruction. This leads to some odd behavior in the two bottom-most and topmost layers in the ocean_only/tracer_mixing experiment. If you have two columns with a density profile rho(z) and the other with rho(z)+epsilon, the entire top or bottom layer will be skipped whereas in actuality some part of the top and bottom layers should always overlap. However, in the interior the neutral surfaces seem to behave as expected.

Before finalizing this update to the neutral diffusion code, two more improvements could be made:
-Boundary extrapolation (to address the above deficiency) applied to both the T/S reconstructions but also the tracer being diffused.
-Something other than a linear interpolation could be used to find where the neutral surface connects within a layer.

Andrew Shao added 15 commits May 17, 2017 13:38
Some initial code changes to update the neutral_diffusion algorithm to
find neutral surface positions using the discontinuous T and S
reconstructions.

Changes:
- Break out a subroutine to return both the left and right edges of PPM
reconstructions within a cell
- Update logic to neutral_diffusion_calc_coeffs so that either the
continuous or discontinuous reconstructions can be used

ToDo:
- Come up with a search algorithm that works on each subinterface
- Update interpolate_for_nondim_position so that it returns a more accurate
position of the neutral surface within each layer
search for the discontinuous positions can begin now.
of find_neutral_surface_positions_discontinuous routine. Will need to
think about how this works and possibly rewrite the algorithm to loop over
layers instead of by neutral surface index.

ToDo:
-Think about logic in the discontinuous reconstruction neutral surface
algorithm, might need to be kl<=2*nk. Also what it means if neutral surface
connects at a discontinuity

Changes:
-Some defined dimensions are now defined based on the total number of
neutral surfaces, set at runtime to be 2*nk+2 if using a continuous
reconstruction or 4*nk if using discontinuous
find_neutral_surface_positions. Does not give expected results in
tracer_mixing test case, more debugging needed.
still not as expected. Suspect a wrong value when setting position in
either right or left search.
…, so

need to debug. A problem for future Shao
After an examination, the odd behavior is due to the piecewise constant
reconstruction of T and S in the top and bottom layers.

ToDo:
-Implement PPM boundary extrapolation either by replacing the current T/S
reconstruction with the functions in ALE/PPM_functions.F90 or port over the
code so that neutral diffusion code is self-contained.
-Do something other than linear interpolation of the change in density
within a layer to find the neutral surface position.
neutral surface.
Copy link
Copy Markdown
Collaborator

@adcroft adcroft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good.

  • There's one little bug. Otherwise it looks correct.
  • Unit tests are needed.
    • We need to work through each of the thought experiments and build a unit test for each. Some might give the same answer as the continuous (like "left column everywhere denser than right"). Most I think we'll need to do the math on.
    • Unit tests should precede debugging a 3d problem.
  • Does it run in 3d?

(I'm clicking comment rather than approve since you said review-only).

Comment thread src/tracer/MOM_neutral_diffusion.F90 Outdated
real, dimension(:,:,:), allocatable :: dRdS ! dRho/dS (kg/m3/ppt) at interfaces

if (CS%continuous_reconstruction) then
if (.not. ALLOCATED(dRdT)) ALLOCATE(dRdT(SZI_(G),SZJ_(G),SZK_(G)+1))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the _init() routine called more than once? I'm wondering why the if (.not. ALLOCATED(...))?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, this was an oversight before making the PR. I think when I wrote it I was trying to be super-safe that there was no memory leak.

Comment thread src/tracer/MOM_neutral_diffusion.F90 Outdated
endif
call PPM_reconstruction(G%ke, h(i,j,:), S(i,j,:), S_i(i,j,:,:), ppoly_coefficients)
if (CS%boundary_extrapolation) then
call PPM_boundary_extrapolation(G%ke, h(i,j,:), S(i,j,:), S_i(i,j,:,:), ppoly_coefficients)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CS%boundary_extrapolation is false right now. Extrapolation obviously introduces new extrema in the buoyancy profiles but I think the stage where we limit the flux to be down gradient should stop tracers from forming new extrema. This assertion needs to be checked. Does extrapolation not work (wondering since you hard coded it)?

Talk to @Hallberg-NOAA about how the limiter should work and whether it will zero fluxes for extrapolated profiles.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point that I hadn't thought of. My main reason for wanting to do some kind of extrapolation is that it seems somewhat unphysical that you would have a large jump in the sum of hEff in the case between two columns with identical columns versus the case where one is only very slightly lighter or denser than the other because you exclude the entirety of the top and bottom cells.

Comment thread src/tracer/MOM_neutral_diffusion.F90 Outdated
do j = G%jsc,G%jec ; do I = G%isc-1,G%iec
if (G%mask2dCu(I,j)>0.) then
call neutral_surface_flux(nk, h(i,j,:), h(i+1,j,:), &
call neutral_surface_flux(nk, CS%nsurf, h(i,j,:), h(i+1,j,:), &
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why aren't you masking anymore?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mistake, I'll add it back in.

hR = absolute_position(nk,Pr,KoR,PoR,k_surface) - absolute_position(nk,Pr,KoR,PoR,k_surface-1)
if ( hL + hR > 0.) then
hEff(k_surface-1) = 2. * hL * hR / ( hL + hR )
hEff(k_surface-1) = 2. * hL * hR / ( hL + hR ) ! Harmonic mean of layer thicknesses
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why I didn't write this as 2. * hL * hR / ( ( hL + hR ) + h_neglect ) that would avoid the conditional. I'm not sure if doing so now would change answers.


! Identical columns
call find_neutral_surface_positions(3, &
call find_neutral_surface_positions_continuous(3, &
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need units tests for each or your _discontinuous functions.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you noted some time before, the discontinuous reconstructions don't always lend themselves nicely to whole number results. That being said, it's on my to-do list before submitting an actual PR.

Comment thread src/tracer/MOM_neutral_diffusion.F90 Outdated

!> Higher order version of find_neutral_surface_positions. Returns positions within left/right columns
!! of combined interfaces using intracell reconstructions of T/S
subroutine find_neutral_surface_positions_discontinuous(nk, Pres_l, Tl, Sl, dRdT_l, dRdS_l, &
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a shame we can't reuse the same algorithm, or combine them. Debugging these sorts of algorithms is painful. Is this the same algorithm but with different data structures being passed in?

One test to try is to set the discontinuous edge values to the interface values of the "continuous" approach. It should give the same solution as the continuous but with 2*G%ke vanished sub-layers.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spent a bit of time trying to shoehorn your original algorithm into the discontinuous one, but to no avail. What it boiled down to was that the original algorithm relies on the fact that the layer index always corresponds to the top interface. With the discontinuous reconstructions a different mapping between interface and layer exists, plus you may potentially need to search across the discontinuity.

I did do something similar to the test you suggested when I was prototyping the logic for the new one for some really simple cases that produced qualitatively similar results (didn't check for bitwise reproduction). If they do, then I agree that the code could be collapsed so that there's not a huge bit of similar code.

Comment thread src/tracer/MOM_neutral_diffusion.F90 Outdated
if (k<=G%ke) then
Pint(:,j,k+1) = Pint(:,j,k) + h(:,j,k) * GV%H_to_Pa ! Pressure at next interface, k+1 (Pa)
call calculate_density_derivs(T_i(:,j,k,2), S_i(:,j,k,2), Pint(:,j,k+1), &
dRdT_i(:,j,k,1), dRdS_i(:,j,k,2), G%isc-1, G%iec-G%isc+3, EOS)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: there's a 1 here that should be a 2.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PS> For the record, the use of indices 1,2 for left,right in the reconstruction code is not my doing and I don't like it because you can't read the code. One day we'll clean up the reconstruction interfaces...

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch. Also, I agree that it's a little bit difficult for 1,2 to map onto left right edge values. At the same time the solution that I can think of off the top I my head is to have separate variables for the two of them which can lead to a huge amount of input arguments (which was the original I had this algorithm coded).

@ashao
Copy link
Copy Markdown
Collaborator Author

ashao commented Jul 17, 2017

Many thanks for the review. I'll close this PR for now and reopen when it's ready to be looked at again.

@ashao ashao closed this Jul 17, 2017
Andrew Shao added 15 commits July 27, 2017 08:49
Brent's method to do neutral position finding. Need to set it up so that if
either second derivatives of rho aren't available or if the Newton's step
goes out of the interval [0,1], it switches to Brent's method.
derivatives. Also, wrote an extractor routine so that members of the EOS
type are available outside of the MOM_EOS module
-The refinement of the neutral position now includes a different
implementation of Brent's method.
-Also, the refinement is now forced to be bracketed between the last
position within the layer and the bottom interface.
-Update the flux calculation so that the continuous case calculates the
top and bottom bounding neutral surfaces using the parabolic
reconstructions instead of linear interpolation.
To Do:
-Try to combine the discontinuous and continuous find_neutral_position
routines
Maybe think about doing the same direction check regardless of
reached_bottom.
-Rearrange and make optional arguments for
 find_neutral_surface_positions_discontinuous if refine_position is not
 requested
-Simplify some of the logic for search_other_column
…ff_update_neutral_position

# Conflicts:
#	src/equation_of_state/MOM_EOS_TEOS10.F90
seems to pass all tests. Performance in more extreme configurations of
tracer_mixing work. All unit tests for discontinuous have been updated.
@ashao
Copy link
Copy Markdown
Collaborator Author

ashao commented Aug 11, 2017

The new neutral diffusion code is ready to be pulled into the main code. For now, the original reconstruction code is retained and remains the default so answers should not change. The improvements made here (discontinuous reconstruction and iterating to find a true neutral position) increases the computational cost of tracer diffusion by a factor of 3-4 in OM4_05, about the same cost as the advection part of the routine. Unit tests for a wide variety of cases are included.

@ashao ashao reopened this Aug 11, 2017
@ashao ashao changed the title Neutral Diffusion: Add option for discontinuous reconstruction of T/S (Review only) Neutral Diffusion: Add option for discontinuous reconstruction of T/S Aug 11, 2017
@Hallberg-NOAA
Copy link
Copy Markdown
Collaborator

There are a couple of the density derivative routines that are being duplicated for scalar and array arguments, including some with messy calculations. I would prefer that the pattern of calculate_density be followed, in that the scalar versions are not coded separately but rather copy their arguments into 1-point arrays and then call the array version. Doing it that way instead would avoid having two separate (and potentially inconsistent) implementations of the algorithms.

Andrew Shao added 2 commits August 15, 2017 11:31
Based on the suggestion of @Hallberg-NOAA, the array and scalar versions
of the EOS functions were wrapped into interfaces. For each of the
available equations of state, the array and scalar versions were also put
behind interfaces. For the Wright EOS, the first and second deriviative
scalar variants of the routines call the array variant by promoting
the scalar T, S, and P to 1-element arrays and demoting the 1-element
output arrays to scalars. Answers not expected to change.
Previous commit failed Travis test because of compiler-dependent evaluation
of logical expressions. (if (kl>1 .and. bot_connected(kl-1)) could yield
to an out of bounds error if the compiler evaluates bother sides of the
statement. The offending line was moved one level below an explicit check
for (kl>1)
@Hallberg-NOAA
Copy link
Copy Markdown
Collaborator

The lengthy list of commits in this PR appears to change both answers and (less concerningly) the parameter_doc files in several test cases. However, I do not see anything in the commit logs that indicate which commits actually change the answers. If there are answer-changing modifications, please break up this pull request into the larger part that does not change answers and a very limited set of code changes that do change answers.

@ashao
Copy link
Copy Markdown
Collaborator Author

ashao commented Aug 15, 2017

None of the commits should have changed answers and the cases checked by Travis passed. To help narrow down where I may have inadvertently introduced a change, could you send a subset of the test cases which failed their checks?

@ashao
Copy link
Copy Markdown
Collaborator Author

ashao commented Aug 15, 2017

Oh wait, I see changes that shouldn't have been there. Submitting yet another commit shortly

Changes made in #a49373c are correct in that the continuous polynomials
should be evaluated to calculate gradients. However, they were intended
to be implemented in a different set of commits. Answers should now
be unchanged.
@Hallberg-NOAA Hallberg-NOAA merged commit ede2d22 into mom-ocean:dev/gfdl Aug 16, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants