-
Notifications
You must be signed in to change notification settings - Fork 150
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
bug: Definition and use of "unnormalized" scale height in cam-fv is inconsistent #298
Comments
hi kevin - apparently the version of the wrf model_mod which supported unnormalized scale heights is not on the main branch. that's a problem to solve for another day. can you see this file? https://github.com/nancycollins/DART_development/blob/all_nsc_changes/models/wrf/model_mod.f90 if so, that has code developed with craig schwartz that does not normalize by surface pressure, and it returns the positive log. in most cases the scale height value is used to compute distances, so the separation between 2 locations. if they're both positive or both negative you get the same distance. but i remember we decided that scale heights should in fact be the positive log of pressure. wikipedia says scale height is a distance (like in kilometers) across which the atmospheric pressure drops by a factor of e. so asking for the scale height of a single location seems to be the value of that location relative to the surface of the earth? so that's the natural log of the pressure, as a positive value, i'd think. |
Even if the SH is defined as + log(p), it still has positive and negative values. What's really happening with the "unnormalized" scale height is that it's _re_normalized When the reference pressure is 10^5 Pa (~Earth's surface), that's the dividing line So the conventional definition of scale height, +log(ps/p) (== -log(p/ps)) gives scale heights Arthur(?) brought up the issue of terminology. The definition of scale height "H" is actually |
thanks for that. what i should have said is that i don't see any need to take -log(p) in our code (compared to just log(p)) since as you point out, the actual value returned can be positive or negative. the vertical separation eventually needs to be converted to radians in the location module so it can be combined with the horizontal separation. here's the code that computes it in the threed_sphere locations mod:
so it is the abs of the distance divided by the normalization factor set by the user in the namelist. (note these can be set on a per-type basis in the threed_sphere locations mod.) the original implementation did normalize the values by the surface pressure. but since we are computing the vertical separation between two points which may be quite far apart in the horizontal, changes in surface pressure near steep topography at the two points changes the vertical distance returned. in revisiting the code later the consensus was that this wasn't what we wanted. arthur is right, we're computing a 'scaled distance' but at this point the terminology is too ingrained, i think, to change. we can certainly document this better in the threed_sphere locations module -- what we're expecting a model_mod to do if the vertical localization type is set to scale height. so the bottom line, in dart, i think is: scale height computations should not be scaled by surface pressure, and there's no reason to take the negative of the log before returning it. it certainly does have to be treated the same everywhere and if that's not the case, that is a bug to be fixed. i confess that i added code in mpas_atm, wrf (uncommitted) and in cam-fv that allowed the user to set a namelist value to do the old computation that scaled by surface pressure for regression testing. it may be at this point that the additional complexity is not worth it and that code could be removed and the logic simplified. |
If we exclusively use +log(p), then what we're calling "scale height" And it contributes to the confusion between "larger or smaller" and "increasing or decreasing" I agree that normalizing by the surface pressure is dangerous. It can be made to work, but it will take some explaining to dispel the appearance |
"it can be made to work"? it is already working. maybe a bug fix is needed for code that is now being called that wasn't tested before, but it's not like it's a big development job. i'm not sure i agree with your argument that it's going to confuse people because mostly it is completely invisible. it's used in the distance calculations only and not written out in the obs_seq.final file. my thoughts on changing it now are: 1) we can call it "scaled height" in our documentation; 2) it's this way in the mpas_atm and this will be inconsistent; 3) no one from MMM has complained about this definition; 4) pressure also decreases with increasing height so it's not like we don't already handle this; 5) WACCM users have been localizing in scale height for several years, i believe, and if this really matters it will be a change for them which is in itself unexpected; and 6) the code has been there for several years without any complaints from users. maybe ask nick whether he has had problems with the current way the code works? |
I've taken another look at the original code and the first fixes I made for Gio's problem 2)-3) Those models don't have vertical location (not distance) tests yet, but Chris reported at a standup recently
5)-6) As I wrote above, the code did work in the ways people asked it to. They didn't need to know I've spent too much time on this, so I'm going to leave it to Nancy and Helen to decide which parts of this PR
|
would you be able to close your existing pull request and open another one with just the proposed changes to the model_mod.f90 in it, relative to the main branch? the current pull request has 1000+ changed files from trying to merge main onto manhattan, and i don't think it includes your proposed version of the model_mod.f90 because the global variable for "scale height too high" isn't there. |
We'll pick up this discussion briefly in the stand-up. One of the problems
is that Kevin is trying to fix a terminology problem that is out of our
hands. The use of "scale-height" for correlation distances in the vertical
in the DA community evolved elsewhere and was picked up by our WRF
collaborators when they started implementing things. If I recall correctly,
that community used the difference in
log(p/ps) to define the scale-height "distance". If the ps is the same, it
would disappear in the difference. However, when a difference was computed
with significantly different ps, this ended up playing a significant role
in this distance definition which caused significant problems in areas of
varying orography as Nancy pointed out. I believe this led us to remove the
ps from our definition so that the DART scale-height distance became
log(p1) - log(p2). This would be better characterized as a log(p) vertical
coordinate or log(p) distance. However, the term "scale-height" had already
been widely used in the peer-reviewed literature for the original ps
normalized differences. I believe that the only difference comes back to
Kevin's concern about the sign of the scaled height as a function of
geometric height.
Kevin's argument about the sign now becomes less obvious. The way the term
is being used in DA is not being thought of as a "scaled-height", but as a
log(p) but called a scale height. I would have to confirm that when used
with WRF our sign behavior is such that the "scale-height" gets less as one
moves up from the earth's surface. Sounds like Nancy already knows that
answer.
So, how to proceed. In the short-term, the behavior in CAM needs to stay
the same unless there was a fundamental bug. My understanding is that the
bug had nothing to do with the computation of distances in "scale-height"
but rather in the way in which things were computed in columns by a
software expediency.
Second, we do not have time to be fixing the more general terminology
problem right now because of the widespread adoption in the DA community.
In particular, whatever we do in CAM must remain consistent (or become
consistent) with the definitions in WRF and MPAS that have been used a lot.
Finally, a conversation with people like Ryan and maybe some NCEP DA folks
would need to take place to assess whether changing terminology to log(p)
or something similar would be useful in the long term.
I have not had time to verify all the things I say here, so I expect the
two of you will correct me if I am mistaken about any of these issues. Jeff
…On Wed, Oct 13, 2021 at 4:23 PM nancy collins ***@***.***> wrote:
would you be able to close your existing pull request and open another one
with just the proposed changes to the model_mod.f90 in it, relative to the
main branch? the current pull request has 1000+ changed files from trying
to merge main onto manhattan, and i don't think it includes your proposed
version of the model_mod.f90 because the global variable for "scale height
too high" isn't there.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#298 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ANDHUIUBPWMZUD7YQBFM2RDUGYBGLANCNFSM5FZGMP7A>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
I followed Helens instructions for changing the base on the issue, and then pushed the commit again. |
great - i now see only a single changed file. thank you!! i can review that. but i still don't see a global variable around line 260 in the proposed model_mod.f90 for no_assim_above_scale_height, so this can't be the final version you want us to review? also obs_too_high() is still being called in model_interpolate()... |
Lots of potential changes came up while debugging Gio's problem. Based on Jeff's response to this discussion, 5) in my list of candidate changes is rejected. |
kevin - maybe you talked about this in the standup - if so, my apologies. i'm getting 'issues' and 'pull requests' confused. if you want to deal with other changes in another issue, that's great. but i'm assuming that in the end there will be a single pull request and release that deals with all the cam top of model issues together. committing updates to your branch incrementally is still a great idea because it helps you isolate changes for testing. is your plan that you will be keeping none of the changes that are currently in model_mod.f90 in the open pull request? some are sign changes which we aren't doing, and some are debugging code that shouldn't stay in the release once you've tested things. (if that's not the case i will review them and give you specific feedback.) as far as thoughts about issues 1,2 and 3 - it would help to see the code changes for issues 1 and 3. for 1) i don't know what 'no_assim_above_pressure' has to do with ramping and scale height. if i see the changes to fix a bug then it probably makes perfect sense. for 3) you say total distance doesn't matter, only the vertical separation for the top ramp. so 'vert_only_distance' seems useful? but i probably don't remember how the code works so seeing your proposed changes would sort that out for me. for 2) adding nint() probably falls into the 'nuisance change' for me since that's what the fortran standard does with or without that call when assigning a real to an integer. |
My (mis)understanding is that we open an issue about a manageable topic To me 1)-3) are still potentially going in. |
no_assim_above_pressure is in this issue and PR because its calculation uses a normalization argument, |
thanks. where i got confused was how no_assim_above_pressure related to missing that normalization flag which only applies to scale height. it's needed for initializing no_assim_above_scaleh, not pressure. it does look like it was missing. good catch. |
kevin - i'm going to post my code review in just a bit. i hope it doesn't come across as harsh - it's hard for me to be clear but soften the tone on some of those items. based on the discussion about the misuse of scale height in DA, and the fact that other modules (wrf, mpas) use positive log() in their code, i think the negative logs need to be removed. i also prefer to make no changes that aren't required to fix the bugs. so i'm objecting to the variable rename and adding the nints(). i am happy to be disagreed with by you or anyone else who is reviewing the changes. i'm retired and the ongoing responsibility for the code is yours, so in the end current group members have to make the final decisions. i have stronger opinions on this code than others because i was part of the re-factoring with johnny when that was done several years ago, so i sometimes can reconstruct the intent, even if there are bugs in the implementation. |
Nancy, thanks for the code review. I'll incorporate the appropriate parts in the next PR,
This issue was intended to cover just some of the changes I believed were needed to get Gio running.
It's a mystery to me, so far, how they excluded obs in the upper layers. My understanding is that get_close_YYY is called before model_interpolate. Get_close_ converts vertical locations to (in this case) VERTISSCALEHEIGHT. Are those locations discarded after get_close_? If not, those locations are passed to model_interpolate, which passes them to obs_too_high, which does NOT check for scale height. But it also does not error out, so model_interpolate is giving it a which_vert which is not VERTISSCALEHEIGHT. |
starting a new issue is probably better but we can do it either way. here is the calling sequence in filter: model_interpolate() is called during forward operator computation, for all obs, which happens before any assimilation starts. those obs have the original locations in the obs_seq.out file. at the start of the assimilation phase there are options to either convert all the obs and state into the requested vertical location, or they can be converted one by one in the get_close routines. there are efficiency and communication bottleneck tradeoffs so it's a namelist option which happens. for a global model with global obs, doing all the conversions up front is probably the better strategy. when they're converted, the converted verticals are saved for the rest of the assimilation phase. then if posterior forward operators are called, they use model_interpolate on the updated state but they use the original obs locations. does this help? |
i have a suggestion to ease kevin's mind about how DA treats scale height. we have a model_nml namelist item to control how scale height is computed called "no_normalization_of_scale_heights". i propose we remove that variable from the namelist but leave it as an internal module global, and add a namelist item called "use_logp_for_scale_height = .true." in the init code we assign that namelist item to no_normalization_of_scale_heights and nothing else changes. then the name of the item is a clue that this is special, and the documentation can explain the differences between the options. |
I think that Nancy's suggestion of use_logp_for_scale_height would be helpful. Going back to the list of things to do from Helen:
|
kevin, this looks good with just a few comment about the implication sections.
2, 3) correct - and i believe that code is already there except for changing the local in the init code to a global for the scale height because the value is already being computed. then obs_too_high() needs to test the global value if scale height is the selected vert localization coordinate.
does this make sense? |
Some of this is veering into solutions, instead of Helen's request for "what should the code do",
Yes, the cancellation of the log(p_ref) parts of a vertical distance calculation is exactly what prompted the definition and use of log(p) instead of log(p_ref/p) (at least in cam-fv); it gives the same distance for less computation. But the cancellation only works if the same p_ref is used for the calculation of the scale height location of both points. If I understood the discussion about other models decision to use only SH = log(p), they decided that because they ran into problems when they used log(p_surf/p) to calculate distances between points at different horizontal locations that had different p_surf. If they had used log(10^5/p) they wouldn't have had those problems. I'm hoping that everywhere in the code that passes p_surf(i,j) to scale_height for 2 locations always does it for the same i,j, so that a differing reference pressure is not causing unnoticed problems. And as I pointed out before, log(p) implies a reference pressure of 1 Pa. log(p) below that has positive values, log(p) above it has negative. So there's a reference pressure (point where the coordinate = 0) even in the log(p) coordinate. It's just implicit (hidden). Again, I know it doesn't make any difference in distance calculations.
|
2,3,4) you're right about passing the normalization flag into the subroutines, and that obs_too_high can deal with any vertical type. good points. |
Woops! I wrote this 10 days ago and got distracted from sending it. Some of this is veering into solutions, instead of Helen's request for "what should the code do",
Yes, the cancellation of the log(p_ref) parts of a vertical distance calculation is exactly what prompted the definition and use of log(p) instead of log(p_ref/p) (at least in cam-fv); it gives the same distance for less computation. But the cancellation only works if the same p_ref is used for the calculation of the scale height location of both points. If I understood the discussion about other models decision to use only SH = log(p), they decided that because they ran into problems when they used log(p_surf/p) to calculate distances between points at different horizontal locations that had different p_surf. If they had used log(10^5/p) they wouldn't have had those problems. I'm hoping that everywhere in the code that passes p_surf(i,j) to scale_height for 2 locations always does it for the same i,j, so that a differing reference pressure is not causing unnoticed problems. And as I pointed out before, log(p) implies a reference pressure of 1 Pa. log(p) below that has positive values, log(p) above it has negative. So there's a reference pressure (point where the coordinate = 0) even in the log(p) coordinate. It's just implicit (hidden). Again, I know it doesn't make any difference in distance calculations.
|
hi kevin, you did post that already. i agree with points 2-4. i'm going to try one last time with point 1. if you still don't agree, please schedule a google meet or zoom call with me? there are currently 2 ways to compute scale_heights in the code. one way is wrong. wrong, wrong, wrong. we all agree. however, it used to be the way scale_height was computed. if we change it then you can't do regression tests or compare results to old runs. so i'm resisting fixing this code because it needs to compute values the old (wrong) way. the default for the namelist item that controls this is to use the new way and this item should be documented as only set to false if you're trying to reproduce an old run or do regression testing. the new way to compute scale height is correct and avoids a couple of divides which don't change the answer and so is more computationally efficient and simpler code. so i don't see anything that needs to be fixed here. your math is completely correct and if we did want to fix the wrong code i'd agree 100%, but it's wrong on purpose. does this make sense? it's not just inertia or not wanting to rename variables. |
Describe the bug
There are several, related bugs, which I've tried to separate into managable units.
This is the first I'd like to resolve, even though I filed one (#296) before this one.
The vertical coordinate "scale height" is defined as log(ps/p), ps = surface pressure (or some other reference)
and log = natural log ln. This can be written as log(ps) - log(p).
When the difference of 2 scale heights is calculated, the 2 log(ps) terms cancel,
so we could save some computation by defining an "unnormalized" scale height = log(1/p) = - log(p)
and calculating SH1 - SH2 = log(p2) - log(p1) (note the numbers).
But when one of those unnormalized SH is compared against some threshhold height,
like ramping_end, that threshhold must be calculated the same way - unnormalized - which it was not.
This topic was further confused by the misdefinition of unnormalized scale height as "log(p)" instead of "- log(p)"
and the resulting, unnecessary complexity in defining higher_is_smaller, and unintended consequences
in routines that use higher_is_smaller.
Set up a cam-fv assimilation using
What was the expected outcome?
There should be no increments at and above layer 5.
What actually happened?
There are non-0 increments in those layers.
The unnormalized scale heights of the state variables have values ranging from
5.88 (log(360 Pa)) to 11.5 (log(99200 Pa)), while the ramp_start (normalized scale height)
had a value of ~ 3.0 (log(10^5/3500) - .3 ramp_depth).
It would appear that all of those state variables are in the damped layer,
but the choice of using unnormalized SH caused higher_is_smaller to be .true. (which it should not have),
and that caused v_above to test whether the state variables have values less than ramp_start.
They do not, so above_ramp_start decided that none of them were in the damped layer.
and so their increments were not damped.
Which model(s) are you working with?
Cam-fv only (all versions of CAM and WACCM(-X))
Version of DART
Which version of DART are you using? Manhattan, all of the versions
Have you modified the DART code?
Only cam-fv/model_mod.f90
I'll issue a pull request shortly on a branch of Manhattan.
Build information
Please describe:
Any machine.
Any compiler
The text was updated successfully, but these errors were encountered: