Conversation
Adds namelist options A, B and P_opt controlling an additional zonal-wavenumber jet-latitude forcing term applied to the equilibrium temperature profile, following Garfinkel et al. (2013). Defaults to A=B=0, which leaves teq unchanged from the existing Polvani_Kushner behaviour. Ported from rgnmudhar/Isca_rmudhar polvani_kushner_rm (e.g. commits 717f1bc, f9b2675), curated on top of the 2026 port of Will Seviour's original PK commits.
…ut file Ported from polar_heating()/heat_perturb()/combo_heat1() in rgnmudhar/Isca_rmudhar polvani_kushner_rm:input/input_files.py. Rather than committing the generated binary NetCDF (following the frierson_dry_heating precedent of generating local heating input files at run time), this generates the field from the repo's existing T42 grid file and ozone climatology file. Verified to reproduce the original committed input/asymmetry/w15a4p600f800g50_q6m2y45l800u200.nc from Isca_rmudhar to within float32 rounding (max relative difference ~5e-7).
era_land_t42.nc was committed locally in Will Seviour's original PK commit, but the test case script actually points at the shared input/land_masks/ copy that already exists on master, so the local copy was dead weight.
…r-2 heating) Ported from rgnmudhar/Isca_rmudhar polvani_kushner_rm:exp/test_cases/polvani_kushner/polvani_kushner_test_case.py (her PK_e0v4z13 configuration: eps=0, vtx_gamma=4, z_ozone=13, t_strat=216.65, T42L60, dt_atmos=240s, sponge on), adapted to: - generate the combined polar + midlatitude wavenumber-2 heating input file on the fly via create_pk_heating_input_file.py rather than requiring a committed binary NetCDF (matching this repo's frierson_dry_heating precedent), using the w15a4p600f800g50_q6m2y45l800u200 combo she generated via combo_heat1()'s defaults - shorten the run loop from her 504-month production length to a 12-month illustrative example, consistent with the other test cases in this repo
Follows the existing pattern (e.g. frierson/frierson_dry_heating) where the more specific name is checked after the general one so it can override input_files/nml_out/codebase_to_use.
Matches the existing frierson_dry_heating/input/*.nc entry - the heating input file is generated at test-case run time (see create_pk_heating_input_file.py), not committed.
|
Here is Claude's description of the P/R: Polvani-Kushner forcing: 2026 portThis branch ( Both original branches predate this:
Regan's branch had manually copied Will's original modifications rather than What's on this branchWill Seviour's PK core (5 commits, cherry-picked, authorship preserved)
Two of Will's original commits were excluded as out of scope: one HPC Regan Mudhar's extensions (2 commits, curated, authorship preserved)Her branch has ~100 commits, but it forked from a
Not ported: her postprocessing/plevel_interpolation workflow scripts and One thing worth noting for review: her tip-of-branch Also note: her version of Test cases (
|
| field | max abs diff | max relative diff |
|---|---|---|
ucomp |
9.5e-7 | 1.1e-7 |
vcomp |
9.5e-7 | 2.6e-7 |
temp |
3.1e-5 | 1.1e-7 |
teq |
3.1e-5 | 9.8e-8 |
local_heating |
3.6e-11 | 5.3e-7 |
ps |
7.8e-3 | 7.8e-8 |
height |
7.8e-3 | 8.7e-8 |
All differences are at or below float32 machine epsilon (~1.2e-7) — i.e. the
port reproduces her original results to within floating-point rounding, not
a meaningful physical difference.
The baseline polvani_kushner_test_case.py (Will's QBO-relaxation
configuration) was also smoke-tested for 2 days and runs without error.
The original Polvani & Kushner (2002) setup has no topography/land contrast and no QBO relaxation - both were extras Will Seviour's original commits added as options but the baseline test case shouldn't default to. Removing the era_land_t42.nc topography input and spectral_init_cond_nml block lets topography_option fall back to its 'flat' default; removing relax_to_qbo/ qbo_amp lets relax_to_qbo fall back to its default of False. Renamed the experiment from polvani_kushner_qbo3 to polvani_kushner_default to match. Smoke-tested for 2 days with no error.
|
Have made some modifications to the PK test script as it included the QBO relaxation and land, neither of which we want for a more vanilla PK test case. Also asked Claude to run trip tests with the following results: Update: baseline test case now matches Polvani & Kushner (2002) exactlyThe original P-K02 setup has no land/topography and no QBO relaxation -
Both options remain available in Update: full trip_test runRan the full 12 of 16 passed bit-identical. Of the 4 "failures":
|
|
So, this looks like it's pretty ready to be merged, with those edits pushed, which I'll do now. |
rgnmudhar
left a comment
There was a problem hiding this comment.
Hi Stephen (and Claude) - thanks a lot for your work to incorporate this into the main Isca branch!
Overall it looks great! I mostly made comments relating to what we do or don't want to include.
In general, I think having a test case that is exactly like the Polvani & Kushner (2002) set-up makes sense, and then also another, separate one with the heating options. Crucially the Lindgren et al. 2019 midlatitude heating should be there (should probably rename the script to generic heating_test_case). For the polar heating, I am less certain as it's not really P-K related! I think it's nice not to lose it, so, if you agree with keeping it, then I think there are 2 key things:
- I think you could move the polar_heating_XXX variables (L93-98 of the polvani_kushner_test_case, i.e. Will's heating) into the heating_test_case
- for the version that takes an input file, optionalise it so you can either choose no heating (/ Will's heating) / Orlanski & Solman 2009 polar heating / Lingren et al. 2018 midlatitude heating / polar + midlatitude heating - this would require editing both the python script to create the input files and the test_case script
I also wondered if having a separate test case again for QBO would be good... could be worth checking a few points with @wseviour on this.
I hope everything is clear and I didn't miss anything! Let me know if you need a chat.
Thanks,
Regan
| 'ks': -4., # Boundary layer dependent cooling timescale (default 4 days) | ||
| 'kf': -1., # BL momentum frictional timescale (default 1 days) | ||
|
|
||
| # jet-latitude control, following Garfinkel et al. (2013) - off by default here |
There was a problem hiding this comment.
I personally feel that the jet-latitude control stuff is not part of the "base" P-K set-up so would not be crucial to include at this point if you really wanted to keep it clean. The original paper actually does it in Held-Suarez not Polvani-Kushner so could be worth putting in H-S instead/too (if you decide to keep it here). If keeping, in L101 I would add the link to the paper https://doi.org/10.1175/JCLI-D-12-00301.1
| 'B': 0., # takes values 0 to 20 in multiples of 4 | ||
| 'P_opt': 'Option1', # 'Option1' or 'Option2' depending on jet location requirement | ||
|
|
||
| # stratospheric polar vortex, following Polvani & Kushner (2002) |
There was a problem hiding this comment.
I would again add the link to the paper in the comment here on L106 https://doi.org/10.1029/2001GL014284
| 'strat_vtx': True, # set to False for w_vtx=0, i.e. no polar vortex | ||
| 'eps': 0., # stratospheric latitudinal variation (+-10 in the P-K paper) | ||
| 'vtx_gamma': 4.0, # lapse rate of winter stratospheric cooling (default 4 K/km) | ||
| 'z_ozone': 13., # height of stratospheric heating source (km) |
There was a problem hiding this comment.
Change the comment here to "height of stratospheric heating source (default 13km (~200 hPa), 100hPa (~16km) used in in the P-K paper)"
| # (all zeros unless the two functions below are given non-default arguments) | ||
| # rather than committing a large binary to git - see | ||
| # src/extra/python/scripts/create_pk_heating_input_file.py. | ||
| input_dir = os.path.join(GFDL_BASE, 'exp/test_cases/polvani_kushner/input') |
There was a problem hiding this comment.
Personally feel the polar cap heating is a separate thing to P-K (purely part of my AA experiments) so again could either remove the heating option stuff entirely, or at least keep references to the midlatitude wave-2 heating perturbation, or keep both but make it optional (see my idea below). Though the midlatitude heating is also not part of the base P-K set-up, it is what was necessary to introduce vortex variability, so could definitely see more of an argument for including.
One thought is to have a kind of "if/else" statement for the local_heating_option to give more flexibility. Something like:
# Generate the polar and/or midlatitude wavenumber-2 heating input file
# (all zeros unless the two functions below are given non-default arguments)
# For the polar heating see: https://doi.org/10.1175/2010JAS3267.1 and https://doi.org/10.1029/2023GL105132
# For the midlatitude heating see: https://doi.org/10.1029/2018JD028537
# rather than committing a large binary to git - see
# src/extra/python/scripts/create_pk_heating_input_file.py.
input_dir = os.path.join(GFDL_BASE, 'exp/test_cases/polvani_kushner/input')
os.makedirs(input_dir, exist_ok=True)
heat_type = 'midlat' # default midlat only, other options 'polar', 'midlat_polar', None
if heat_type == 'midlat':
heating_file_path, heating_var_name = create_midlat_heating_file(input_dir)
elif heat_type == 'polar':
heating_file_path, heating_var_name = create_polar_heating_file(input_dir)
elif heat_type == 'midlat_polar':
heating_file_path, heating_var_name = create_polar_and_midlat_heating_file(input_dir)
But then the script creating the input file needs to be edited too and you would probably need to do something with subsequent lines in the present script related to the heating, e.g. L40, L57, and L115-118.
There was a problem hiding this comment.
Also could be worth folding in the other kind of "polar heating" from the other test_case script by Will to this script, so the other is a completely clean set-up that follows the P-K paper exactly
| 'ka': -40., # Constant Newtonian cooling timescale (default 40 days) | ||
| 'ks': -4., # Boundary layer dependent cooling timescale (default 4 days) | ||
| 'kf': -1., # BL momentum frictional timescale (default 1 days) | ||
| 'z_ozone': 15., # Height (in km) of stratospheric warming start |
There was a problem hiding this comment.
change to 16. and the comment to be consistent with the "polar_heating_test_case" version i.e. "height of stratospheric heating source (default 16km (~100 hPa) used in in the P-K paper)"
| real, dimension(size(u,2),size(u,3)) :: uz, vz | ||
| real :: umean, vmean | ||
|
|
||
| real :: umean, vmean, zkm, qbofactr |
There was a problem hiding this comment.
Don't need qbofactr if not keeping qbo nudging
| return field # (pfull, lat, lon) | ||
|
|
||
|
|
||
| def create_polar_and_midlat_heating_file(output_dir, file_name='w15a4p600f800g50_q6m2y45l800u200.nc', |
There was a problem hiding this comment.
As per my earlier comment, could this be rewritten (perhaps two new separate functions?) to create a polar heating only and midlatitude heating only file, as well as this current combined one?
| from create_pk_heating_input_file import create_polar_and_midlat_heating_file | ||
|
|
||
| NCORES = 16 | ||
| RESOLUTION = 'T42', 60 # T42 horizontal resolution, 60 levels in pressure |
There was a problem hiding this comment.
Actually I think the default number of levels should be 40, can keep 60 in the comment maybe?
| enddo | ||
| enddo | ||
| enddo | ||
| else if(trim(local_heating_option) == 'Polar') then |
There was a problem hiding this comment.
Could remove L930-940 if decide not to keep this alternative type of polar heating from Will
| 'MiMA', | ||
| 'held_suarez', | ||
| 'polvani_kushner', | ||
| 'polvani_kushner_polar_heating', |
There was a problem hiding this comment.
Would need to edit if changing to generic heating and also having a separate test case for QBO
The Polvani-Kushner setup for a Newtonian-relaxation representation of the stratosphere has been a feature in Isca's branches for many years, but has yet to be incorporated into the master branch. The original code for PK was written by @wseviour, and was subsequently adapted by @rgnmudhar for her paper here:
https://doi.org/10.1029/2023JD040416
Getting this combination of commits into the master is slightly complicated, as I wanted to preserve as much of the history as possible, despite the original PK modifications being on Will's fork and the subsequent additions being on Regan's I've therefore asked Claude to pull these things together and create two new test cases for Isca:
Claude has verified that setup 2 produces the same results as the same experiments on Regan's fork - https://github.com/rgnmudhar/Isca_rmudhar/tree/polvani_kushner_rm.
Now going to run the trip tests to check this hasn't broken anything else, then will merge in.