-
Notifications
You must be signed in to change notification settings - Fork 317
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
Implement diurnal ozone downscaling #2496
base: master
Are you sure you want to change the base?
Conversation
TL; DR: The big thing we still need to decide is how to implement the namelist options and whether we want to automatically downscale ozone any time we get multi-day average, or only optionally do this if
My vote: just automatically do it. Or optionally turn it off |
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.
@adrifoster I looked at your PR and came up with a comment about indentation. If I were nit-picky, I would have pointed out other, aesthetic, indentation issues, but I'm not :-))
Otherwise, this looks great and it seems straightforward enough that I'm comfortable approving without further follow-up.
A question / comment seeking confirmation: I think this is the land model's first example of a stream with an interp function to take data to subdaily, right?
I'd like to be consistent, could you point out the other nit-picky things? |
Yes I believe that is correct. |
All tests PASS except for expected fails, and NLCOMP diffs (which is expected because of the namelist changes I made)
|
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.
@adrifoster I added a few "nit" comments about indentation since you asked.
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.
Thank you very much for your great work on this @adrifoster ! This feels well-designed and well-written, and I appreciate the time you spent working on this feature - both before you went on leave and then the final work you did to finalize it more recently. I especially appreciate the care you took in various places to document things, call out questions you have, etc. I'm sorry it has taken me so long to review it!
I have a number of comments below. I think most of them are pretty small and will hopefully be easy to address. There are maybe a few that might take a bit more thought, such as related to the interpolation algorithm, but nothing that should take any significant rework: the overall structure of this seems great! I'm happy to talk through any of this if it would help.
if ($opts->{'driver'} ne "nuopc") { | ||
$log->fatal_error("Cannot use do3_streams=.true. with MCT."); | ||
} |
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 check can probably be removed now that mct is no longer supported.
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_do3', | ||
'hgrid'=>"360x720cru" ); | ||
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_do3', | ||
'hgrid'=>"360x720cru" ); | ||
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'do3_mapalgo', | ||
'hgrid'=>$nl_flags->{'res'} ); |
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.
- Is hgrid actually needed as an attribute to these add_default calls? It is confusing to me because the hgrid you're specifying doesn't match the grid of the files (based on the files given in namelist_defaults). And since there is only a single option in the namelist_defaults, I'm thinking that you probably don't need to specify hgrid (which I would think would be to choose between multiple options) - but I could be misunderstanding.
# input file for creating diurnal ozone from >daily data | ||
my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; | ||
|
||
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_do3_streams'); |
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.
- As you note in the design document, I'm not sure there's a use case where a user would want to change use_do3_streams. I'd suggest removing that and just basing the logic on atm_ozone_frequency. (You could potentially still avoid adding the stream definition stuff if ozone is off... not sure if it's worth doing that or not.)
@@ -1732,6 +1732,12 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c | |||
<lai_mapalgo hgrid="1x1_asphaltjungleNJ" >nn</lai_mapalgo> | |||
<lai_mapalgo hgrid="5x5_amazon" >nn</lai_mapalgo> | |||
|
|||
<!-- do3 streams namelist defaults --> | |||
<use_do3_streams>.true.</use_do3_streams> | |||
<stream_fldfilename_do3>/glade/work/afoster/ozone_update/ozone_damage_files/converted/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc</stream_fldfilename_do3> |
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 file should be moved into inputdata.
@@ -0,0 +1,116 @@ | |||
# Software Design Documentation |
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.
Thank you for writing this design doc and adding it here! This is especially helpful when coming back to this a couple of years later like I'm doing now!!!
|
||
We add an instance of the `diurnal_ozone_anom_type` as an attribute of the `ozone_base_type`. | ||
|
||
Within the `Init` method of the `ozone_base_type`, we read the `drv_flds_in` file to get the `atom_ozone_frequency_val`. If this value is `atm_ozone_frequency_multiday_average` then we initialize and read in the o3 anomaly data by calling the `read_O3_stream` described above. *Do we need an else decision here?* |
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.
Good question about the else
. I have added a comment on this below, in the relevant part of the code.
do t = 1, this%ntimes | ||
if (real(tod) <= this%time_arr(t)) then | ||
exit | ||
end if | ||
end do |
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.
- Is it possible to have
real(tod) > this%time_arr(this%ntimes)
? My sense is that this case isn't currently handled, but I'm not sure if it's possible for it to arise based on the times on the file.
forc_o3_down(begg:endg) = forc_o3(begg:endg)* & | ||
((this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_start + & | ||
this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_end)/tdiff) |
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.
- Is there a typo here? You use
t_prev
as the index for both; should one of them bet
? I haven't thought carefully about which one should bet
other than thinking: in the edge case wheretod == this%time_arr(t)
, then I think we want to use the anomaly from timet
exactly, right? I guess one other thing I'm thinking about here as I start to think about this more is that I wonder if the names of thetdiff_start
andtdiff_end
variables should be swapped: I haven't thought about this carefully, but it seems liketdiff_start
gives the difference from the end of the time interval, which seems a bit counter-intuitive... but maybe I'm seeing this wrong.
call restartvar(ncid=ncid, flag=flag, varname='o3force', xtype=ncd_double, & | ||
dim1name='gridcell', & | ||
long_name='ozone forcing', units='mol mol^-1', & | ||
readvar=readvar, interpinic_flag='interp', data=this%o3force_grid) |
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.
- I haven't looked at this carefully, but I just want to double-check: does this truly need to be on the restart file? Or is it / can it be recalculated at the start of the run?
integer :: p ! patch index | ||
integer :: c ! column index | ||
integer :: g ! gridcell index | ||
real(r8) :: forc_o3_down(bounds%begg:bounds%endg) ! downscaled ozone partial pressure (mol/mol) |
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.
- Is there a reason for this intermediate forc_o3_down as opposed to putting the result directly in the forc_o3_grid variable? If keeping forc_o3_down, I'd suggest changing its name to forc_o3_downscaled (I assume that's what 'down' is short for?) (rationale: 'down' implies to me 'up' vs. 'down', which is a somewhat reasonable interpretation of the name for a forcing, giving a sign convention, so I'd want to make it clear that that is not the meaning here).
Description of changes
Adds the capability to downscale daily or multi-day ozone into sub-daily ozone input (DATM or from CAM).
As laid out in CTSM Issue #270 we want to downscale input ozone partial pressure (mol/mol) temporally if we receive a multi-day average input ozone (usually in DATM mode).
We have the infrastructure laid out for CAM and DATM to inform CTSM which type of input we are receiving (i.e., 'multiday_average' or 'subdaily'). We only apply this downscaling when receiving multi-day average ozone.
Specific notes
A gridded file provided by @lkemmons for a diurnal ozone variation factor is read in via a new ozone streams module. This streams file is then used to downscale the ozone provided by DATM or otherwise.
Inside the existing
CalcOzoneUptake
routine, if we are using multi-day average ozone, interpolate/downscale theforc_o3
array using the newInterp
subroutine.Right now we are assuming that the units of the input diurnal file are going to be in seconds, and that the file covers the whole day.
There is no need to assume that the dimension will be 1-24 (i.e. on the hour) or that the dimensions be equal intervals.
The file is read in using a new
src/share_esmf/diurnalOzoneStreamMod
module, with associated updates tobld/CLMBuildNamelist.pm
,bld/namelist_files/namelist_defaults_ctsm.xml
andbld/namelist_files/namelist_definition_csvm.xml
Right now the new variable
use_do3_streams
is set in theuser_nl_clm
file. And the other namelist variables (stream_fldfilename_do3
,stream_meshfile_do3
, anddo3_mapalgo
) are inside thelnd_in
file under ado3_streams
namelist.I'm not sure setting up the
use_do3_streams
namelist variable is the best way to go about this, since we essentially want this feature on whenever the ozone frequency is 'multiday_average' @billsacks what do you think?Right now we are hard-coding the
stream_var_name
, andstream_lev_dimname
. I think this is okay. Otherwise, we would want them to be namelist variables that get read in.These updates do change answers, namely ozone uptake is decreased (@danicalombardozzi does this make sense?)
ozone forcing for non-diurnal vs. diurnal for the first simulation day:
ozone uptake for the same day:
ozone uptake summed up over the year:
@danicalombardozzi i'm not sure about the units for these ozone history variables, they are in mol/m2/time step... do we want to convert them to a per second? Or is this already done somewhere?
Contributors other than yourself, if any:
@billsacks @danicalombardozzi @lkemmons
CTSM Issues Fixed (include github issue #): Fixes #270
Are answers expected to change (and if so in what way)? Yes, see above. If turned on will modify ozone uptake. If ozone damage and ozone downscaling are not on, this will have no effect.
Any User Interface Changes (namelist or namelist defaults changes)? Yes, adds new namelist options for do3_streams. We also need to decide if we want to only optionally do this, or automatically do this all the time if we have multi-day ozone.
Testing performed, if any:
See above, will also do system testing