diff --git a/Externals.cfg b/Externals.cfg index 1e96526479..dc66b3c485 100644 --- a/Externals.cfg +++ b/Externals.cfg @@ -1,5 +1,5 @@ [ccs_config] -tag = ccs_config_cesm0.0.49 +tag = ccs_config_cesm0.0.59 protocol = git repo_url = https://github.com/ESMCI/ccs_config_cesm local_path = ccs_config @@ -13,7 +13,7 @@ local_path = components/cice5 required = True [cice6] -tag = cesm_cice6_2_0_35 +tag = cesm_cice6_4_1_3 protocol = git repo_url = https://github.com/ESCOMP/CESM_CICE local_path = components/cice @@ -21,14 +21,14 @@ externals = Externals.cfg required = True [cmeps] -tag = cmeps0.14.12 +tag = cmeps0.14.24 protocol = git repo_url = https://github.com/ESCOMP/CMEPS.git local_path = components/cmeps required = True [cdeps] -tag = cdeps0.12.67 +tag = cdeps1.0.8 protocol = git repo_url = https://github.com/ESCOMP/CDEPS.git local_path = components/cdeps @@ -57,14 +57,14 @@ local_path = libraries/mct required = True [parallelio] -tag = pio2_5_9 +tag = pio2_5_10 protocol = git repo_url = https://github.com/NCAR/ParallelIO local_path = libraries/parallelio required = True [cime] -tag = cime6.0.82 +tag = cime6.0.94 protocol = git repo_url = https://github.com/ESMCI/cime local_path = cime @@ -79,7 +79,7 @@ externals = Externals_CISM.cfg required = True [clm] -tag = ctsm5.1.dev114 +tag = ctsm5.1.dev120 protocol = git repo_url = https://github.com/ESCOMP/CTSM local_path = components/clm @@ -96,7 +96,7 @@ externals = Externals_FMS.cfg required = True [mosart] -tag = mosart1_0_47 +tag = mosart1_0_48 protocol = git repo_url = https://github.com/ESCOMP/MOSART local_path = components/mosart diff --git a/Externals_CAM.cfg b/Externals_CAM.cfg index 15aa548487..7bb8130432 100644 --- a/Externals_CAM.cfg +++ b/Externals_CAM.cfg @@ -23,21 +23,21 @@ required = True local_path = src/physics/clubb protocol = svn repo_url = https://github.com/larson-group/clubb_release/tags/ -tag = clubb_4ncar_20221129_59cb19f/src/CLUBB_core +tag = clubb_4ncar_20221129_59cb19f_20230330_branchtag/src/CLUBB_core required = True [silhs] local_path = src/physics/silhs protocol = svn repo_url = https://github.com/larson-group/clubb_release/tags/ -tag = clubb_4ncar_20221129_59cb19f/src/SILHS +tag = clubb_4ncar_20221129_59cb19f_20230330_branchtag/src/SILHS required = True [pumas] local_path = src/physics/pumas protocol = git repo_url = https://github.com/ESCOMP/PUMAS -tag = pumas_cam-release_v1.28 +tag = pumas_cam-release_v1.29 required = True [pumas-frozen] diff --git a/bld/build-namelist b/bld/build-namelist index 1e6f51d274..2664e46c5a 100755 --- a/bld/build-namelist +++ b/bld/build-namelist @@ -851,7 +851,7 @@ if (($chem =~ /waccm_ma/ or $chem =~ /waccm_tsmlt/) and !$chem_rad_passive) { elsif (($chem =~ /trop_strat/ or $chem =~ /geoschem/) and !$chem_rad_passive) { $radval .= ",'N:O2:O2','A:CO2:CO2'"; } -elsif ($co2_cycle and !$co2_cycle_rad_passive) { +elsif (($co2_cycle and !$co2_cycle_rad_passive) or ($chem =~ /ghg_mam4/)) { $radval .= ",'N:O2:O2','A:CO2:CO2'"; } else { @@ -877,7 +877,7 @@ if ($rad_prog_ozone) { die "ERROR: can not set ozone rad_climate specification\n"; } -if ((($chem =~ /waccm_ma/) or ($chem =~ /waccm_sc_mam/) or ($chem =~ /waccm_tsmlt/) or ($chem =~ /trop_strat/)) and !$chem_rad_passive ) { +if ((($chem =~ /ghg_mam4/) or ($chem =~ /waccm_ma/) or ($chem =~ /waccm_sc_mam/) or ($chem =~ /waccm_tsmlt/) or ($chem =~ /trop_strat/)) and !$chem_rad_passive ) { $radval .= ",'A:N2O:N2O','A:CH4:CH4','N:CFC11STAR:CFC11','A:CFC12:CFC12'"; } elsif ($prog_ghg1 and $prog_ghg2 and !$chem_rad_passive ) { $radval .= ",'A:N2O:N2O','A:CH4:CH4','A:CFC11:CFC11','A:CFC12:CFC12'"; @@ -1662,7 +1662,16 @@ if ($chem =~ /waccm_sc/) { add_default($nl, 'h2orates'); add_default($nl, 'solar_parms_data_file'); } - +if ($chem =~ /ghg_mam4/) { + add_default($nl, 'h2orates'); + my $flbc_list = "'CH4','N2O','CO2','CFC11','CFC12'"; + add_default($nl, 'flbc_list', 'val'=>$flbc_list); + unless (defined $nl->get_value('flbc_type')) { + add_default($nl, 'flbc_type', 'val'=>'CYCLICAL'); + add_default($nl, 'flbc_cycle_yr', 'val'=>'2000'); + } + add_default($nl, 'flbc_file'); +} if ( $prog_species ) { my $ddval; my $emisval; @@ -2350,7 +2359,7 @@ if (($chem =~ /_mam4/ or $chem =~ /_mam5/) and ($phys =~ /cam6/ or $phys =~ /cam $first = 0; } } - if ($chem eq 'trop_mam4' or $chem eq 'waccm_sc_mam4') { + if ($chem eq 'trop_mam4' or $chem eq 'waccm_sc_mam4'or $chem eq 'ghg_mam4') { # SOA yields (used for the interactive emissions) have been calculated based on the VBS yields in CAM-chem. # Duseong S. Jo, et al. to be submitted to GMD, 2023 -- see https://github.com/ESCOMP/CAM/pull/727 discussion for additional detail. my %soae_fctrs = ('BENZENE_an_srf_file' => '3.4192D0', @@ -2393,8 +2402,8 @@ if (($chem =~ /_mam4/ or $chem =~ /_mam5/) and ($phys =~ /cam6/ or $phys =~ /cam 'num_a2_cv_ext_file' => 'num_a2', ); - # aircraft emissions - if ($chem !~ /trop_mam/ and $chem !~ /waccm_sc/) { + # air craft emissions + if ($chem !~ /trop_mam/ and $chem !~ /ghg_mam/ and $chem !~ /waccm_sc/) { %species = (%species, 'bc_a4_ar_ext_file' => 'bc_a4', 'num_a4_ar_ext_file' => 'num_a4', @@ -2450,7 +2459,7 @@ if (($chem =~ /_mam4/ or $chem =~ /_mam5/) and ($phys =~ /cam6/ or $phys =~ /cam } # MEGAN emissions - if (($chem eq 'trop_mam4' or $chem eq 'waccm_sc_mam4') and !$aqua_mode and !$scam){ + if (($chem eq 'trop_mam4' or $chem eq 'waccm_sc_mam4' or $chem eq 'ghg_mam4') and !$aqua_mode and !$scam){ my $val = "'SOAE = 0.9058*isoprene + 5.8638*(carene_3 + pinene_a + thujene_a + bornene +'," . "' terpineol_4 + terpineol_a + terpinyl_ACT_a + myrtenal + sabinene + pinene_b + camphene +'," . "' fenchene_a + limonene + phellandrene_a + terpinene_a + terpinene_g + terpinolene +'," @@ -2601,10 +2610,10 @@ if (($chem =~ /_mam4/ or $chem =~ /_mam5/) and ($phys =~ /cam6/ or $phys =~ /cam } } -if ($chem eq 'trop_mam4' or $chem eq 'waccm_sc_mam4') { +if (($chem eq 'trop_mam4') or ($chem eq 'waccm_sc_mam4') or ($chem eq 'ghg_mam4')) { # Prescribed species - if ($chem eq 'waccm_sc_mam4') { + if (($chem eq 'waccm_sc_mam4')or($chem eq 'ghg_mam4')) { add_default($nl, 'tracer_cnst_specifier', 'val'=>"'O3','OH','NO3','HO2','HALONS'"); add_default($nl, 'tracer_cnst_file'); add_default($nl, 'tracer_cnst_datapath'); @@ -2731,7 +2740,7 @@ if ($waccmx){ $maxzen = 116.; } elsif ($chem =~ "trop_strat" or $chem =~ "waccm_") { $maxzen = 97.01; -} elsif ($chem =~ "trop_mam" or $chem =~ "trop_mozart") { +} elsif ($chem =~ "trop_mam" or $chem =~ "trop_mozart" or $chem =~ "ghg_mam") { $maxzen = 88.85; } if ($maxzen>0.0) { @@ -3145,6 +3154,11 @@ if (!$simple_phys) { } else { add_default($nl, 'use_hetfrz_classnuc', 'val'=>'.false.'); } + if ($nl->get_value('use_hetfrz_classnuc') =~ m/$TRUE/io) { + # set default scaling factors if het frz is turned on + add_default($nl, 'hetfrz_bc_scalfac'); + add_default($nl, 'hetfrz_dust_scalfac'); + } add_default($nl, 'use_preexisting_ice'); if ($chem =~ /_mam7/) { if ($nl->get_value('use_preexisting_ice') =~ m/$TRUE/io) { @@ -3541,14 +3555,16 @@ if ( length($nl->get_value('soil_erod_file'))>0 ) { else { if ($chem =~ /trop_strat/ or $chem =~ /geoschem/ or $chem =~ /waccm_ma/ or $chem =~ /waccm_tsmlt/ or $chem =~ /trop_mozart/) { add_default($nl, 'dust_emis_fact', 'ver'=>'chem'); - # set scaling of lightning NOx production - add_default($nl, 'lght_no_prd_factor' ); } else { add_default($nl, 'dust_emis_fact'); } } } +if (chem_has_species($cfg, 'NO')) { + # set scaling of lightning NOx production + add_default($nl, 'lght_no_prd_factor' ); +} # Seasalt emissions tuning factor if ($chem =~ /_mam(\d)/) { @@ -3924,7 +3940,6 @@ if ($dyn =~ /se/) { my @vars = qw( se_ftype se_horz_num_threads - se_lcp_moist se_large_Courant_incr se_hypervis_subcycle se_hypervis_subcycle_sponge @@ -3952,7 +3967,6 @@ if ($dyn =~ /se/) { se_fvm_supercycling_jet se_kmin_jet se_kmax_jet - se_phys_dyn_cp se_molecular_diff ); @@ -4177,6 +4191,21 @@ add_default($nl, 'cam_snapshot_before_num'); add_default($nl, 'cam_snapshot_after_num'); check_snapshot_settings(); +if ($opts{'cmeps'}) { + # advertise the nature of ozone data passed to surface models + if ($rad_prog_ozone) { + add_default($nl, 'atm_ozone_frequency', 'val'=>'subdaily'); + } else { + add_default($nl, 'atm_ozone_frequency', 'val'=>'multiday_average'); + } + # for lightning flash freq to CTSM + if ($simple_phys or $aqua_mode) { + add_default($nl, 'atm_provides_lightning', 'val'=>'.false.'); + } else { + add_default($nl, 'atm_provides_lightning', 'val'=>'.true.'); + } +} + #----------------------------------------------------------------------------------------------- # Write output files @@ -4193,16 +4222,8 @@ my %nl_group = (); foreach my $name (@nl_groups) { $nl_group{$name} = ''; } # Dry deposition, MEGAN VOC emis and ozone namelists -@comp_groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm ndep_inparm ozone_coupling_nl); +@comp_groups = qw(drydep_inparm megan_emis_nl fire_emis_nl carma_inparm ndep_inparm ozone_coupling_nl lightning_coupling_nl); -# nature of ozone data passed to surface models -- only if cmeps (nuopc) coupling is used -if ($opts{'cmeps'}) { - if ($rad_prog_ozone) { - add_default($nl, 'atm_ozone_frequency', 'val'=>'subdaily'); - } else { - add_default($nl, 'atm_ozone_frequency', 'val'=>'multiday_average'); - } -} $outfile = "$opts{'dir'}/drv_flds_in"; $nl->write($outfile, 'groups'=>\@comp_groups); if ($print>=1) { diff --git a/bld/config_files/definition.xml b/bld/config_files/definition.xml index e198e1bd65..8e14d94c51 100644 --- a/bld/config_files/definition.xml +++ b/bld/config_files/definition.xml @@ -98,8 +98,8 @@ meteor_smoke (Meteor Smoke), mixed_sulfate (Meteor Smoke and Sulfate), pmc (Pola sulfate (Sulfate Aerosols), tholin (early earth haze), test_detrain (Detrainment), test_growth (Particle Growth), test_passive (Passive Dust), test_radiative (Radiatively Active Dust), test_swelling (Sea Salt), test_tracers (Asian Monsoon), test_tracers2 (Guam). - - Chemistry package: none,terminator,trop_mam3,trop_mam4,trop_mam7,trop_mozart,trop_strat_mam4_ts2,trop_strat_mam4_vbs,trop_strat_mam4_vbsext,trop_strat_mam5_ts2,trop_strat_mam5_vbs,trop_strat_mam5_vbsext,waccm_ma,waccm_mad,waccm_ma_sulfur,waccm_sc,waccm_sc_mam4,waccm_mad_mam4,waccm_ma_mam4,waccm_tsmlt_mam4,waccm_tsmlt_mam4_vbsext,waccm_mad_mam5,waccm_ma_mam5,waccm_tsmlt_mam5,waccm_tsmlt_mam5_vbsext,geoschem_mam4 + + Chemistry package: none,ghg_mam4,terminator,trop_mam3,trop_mam4,trop_mam7,trop_mozart,trop_strat_mam4_ts2,trop_strat_mam4_vbs,trop_strat_mam4_vbsext,trop_strat_mam5_ts2,trop_strat_mam5_vbs,trop_strat_mam5_vbsext,waccm_ma,waccm_mad,waccm_ma_sulfur,waccm_sc,waccm_sc_mam4,waccm_mad_mam4,waccm_ma_mam4,waccm_tsmlt_mam4,waccm_tsmlt_mam4_vbsext,waccm_mad_mam5,waccm_ma_mam5,waccm_tsmlt_mam5,waccm_tsmlt_mam5_vbsext,geoschem_mam4 Prognostic mozart species packages: list of any subset of the following: DST,SSLT,SO4,GHG,OC,BC,CARBON16 diff --git a/bld/configure b/bld/configure index 05509afaec..9036a2c10e 100755 --- a/bld/configure +++ b/bld/configure @@ -63,7 +63,7 @@ OPTIONS test_tracers, test_tracers2]. Default: none. -chem Build CAM with specified prognostic chemistry package - [ none | terminator | trop_mam3 | trop_mam4 | trop_mam7 | trop_mozart | trop_strat_mam4_ts2 | + [ none | ghg_mam4 | terminator | trop_mam3 | trop_mam4 | trop_mam7 | trop_mozart | trop_strat_mam4_ts2 | trop_strat_mam4_vbs | trop_strat_mam4_vbsext | trop_strat_mam5_ts2 | trop_strat_mam5_vbs | trop_strat_mam5_vbsext | waccm_ma | waccm_mad | waccm_ma_sulfur | waccm_sc | waccm_sc_mam4 | waccm_mad_mam4 | waccm_ma_mam4 | waccm_tsmlt_mam4 | waccm_tsmlt_mam4_vbsext | waccm_mad_mam5 | @@ -140,10 +140,6 @@ OPTIONS -verbose [or -v] Turn on verbose echoing of settings made by configure. -version Echo the CVS tag name used to check out this CAM distribution. - Options for surface components used in standalone CAM mode: - - -ocn Build CAM with ocean model [docn | dom | som | socn | aquaplanet | pop]. Default: aquaplanet - Options for building CAM via standalone scripts: -cam_bld Directory where CAM will be built. This is where configure will write the diff --git a/bld/namelist_files/namelist_defaults_cam.xml b/bld/namelist_files/namelist_defaults_cam.xml index 957077df4f..f02a957d53 100644 --- a/bld/namelist_files/namelist_defaults_cam.xml +++ b/bld/namelist_files/namelist_defaults_cam.xml @@ -125,6 +125,9 @@ atm/cam/inic/se/FCMTHIST_ne30pg3_1980-01-01_c221214.nc atm/cam/inic/fv/FC2000mam5_f10_0002-01-01_c221214.nc +atm/cam/inic/se/FWsc_ne30pg3_58L_GRID_48_taperstart10km_lowtop_BL10_v3_beta1p75_Top_43km.nc +atm/cam/inic/se/L93_ne30pg3_ne30pg3_mg17_450_short.cam.i.1979-01-07-00000.nc + atm/cam/chem/trop_mozart/ic/cami_0000-09-01_4x5_L26_c060217.nc atm/cam/chem/trop_mozart/ic/cami_0000-09-01_10x15_L26_c060216.nc @@ -302,7 +305,7 @@ atm/cam/topo/se/ne5pg3_nc3000_Co360_Fi001_MulG_PF_nullRR_Nsw064_20170516.nc atm/cam/topo/se/ne16pg3_nc3000_Co120_Fi001_PF_nullRR_Nsw084_20171012.nc -atm/cam/topo/se/ne30pg3_nc3000_Co060_Fi001_PF_nullRR_Nsw042_20171014.nc +atm/cam/topo/se/ne30pg3_gmted2010_modis_bedmachine_nc3000_Laplace0100_20230105.nc atm/cam/topo/se/ne60pg3_nc3000_Co030_Fi001_PF_nullRR_Nsw021_20171012.nc atm/cam/topo/se/ne120pg3_nc3000_Co015_Fi001_PF_nullRR_Nsw010_20171014.nc atm/cam/topo/se/ne240pg3_nc3000_Co008_Fi001_PF_nullRR_Nsw005_20171015.nc @@ -572,6 +575,7 @@ atm/cam/ggas/ghg_hist_1765-2005_c091218.nc atm/waccm/lb/LBC_1765-2100_1.9x2.5_CCMI_RCP60_za_RNOCStrend_c141002.nc +atm/waccm/lb/LBC_17500116-20150116_CMIP6_0p5degLat_c180905.nc atm/cam/ggas/emissions-cmip6_CO2_anthro_surface_175001-201512_fv_0.9x1.25_c20181011.nc @@ -624,6 +628,7 @@ atm/waccm/phot/xh2o_c080826.nc atm/waccm/phot/xh2o_c080826.nc +atm/waccm/phot/xh2o_c080826.nc atm/waccm/ub @@ -741,8 +746,10 @@ .true. .true. .true. -.false. .false. +.false. +.false. +.false. .false. .false. .false. @@ -1819,6 +1826,8 @@ halons_oxid_1.9x2.5zm_L66_1849-2099_c160714.nc atm/waccm/halons +halons_oxid_1.9x2.5zm_L66_1849-2099_c160714.nc +atm/waccm/halons CYCLICAL 2000 @@ -2243,6 +2252,8 @@ .false. .true. .true. +0.01D0 +0.05D0 .false. .true. @@ -2864,14 +2875,16 @@ '' 'O', 'O2', 'H', 'N2' -'Q' -'Q','CLDLIQ','RAINQM' -'Q','CLDLIQ','CLDICE' -'Q','CLDLIQ','CLDICE' -'Q','CLDLIQ','CLDICE' -'Q','CLDLIQ','CLDICE' -'Q','CLDLIQ','CLDICE','RAINQM','SNOWQM' -'Q','CLDLIQ','CLDICE','RAINQM','SNOWQM' +'Q' +'Q' +'Q' +'Q','CLDLIQ','RAINQM' +'Q','CLDLIQ','CLDICE' +'Q','CLDLIQ','CLDICE' +'Q','CLDLIQ','CLDICE' +'Q','CLDLIQ','CLDICE' +'Q','CLDLIQ','CLDICE','RAINQM','SNOWQM' +'Q','CLDLIQ','CLDICE','RAINQM','SNOWQM','GRAUQM' @@ -2969,8 +2982,6 @@ 2 - .true. - .true. 3.22D0 @@ -2978,6 +2989,7 @@ 3 2 4 + 4 3 1 @@ -2998,8 +3010,6 @@ 1.0e99 1.9 -1 - -1 5.e15 @@ -3287,99 +3297,6 @@ ' C3H6_O3 + ISOP_O3 + MVK_O3 + MACR_O3 + MTERP_O3 + BCARY_O3 + S_O3 + SO_O3' - - - - - - -atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_clim_c061106.nc -atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_clim_c061106.nc -atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_clim_c040926a.nc -atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_clim_c061031.nc -atm/cam/sst/sst_HadOIBl_bc_2.5x3.33_clim_c091210.nc -atm/cam/sst/sst_HadOIBl_bc_4x5_clim_c061031.nc -atm/cam/sst/sst_HadOIBl_bc_10x15_clim_c050526.nc - -atm/cam/sst/sst_HadOIBl_bc_256x512_clim_c031031.nc -atm/cam/sst/sst_HadOIBl_bc_128x256_clim_c050526.nc -atm/cam/sst/sst_HadOIBl_bc_64x128_clim_c050526.nc -atm/cam/sst/sst_HadOIBl_bc_48x96_clim_c050526.nc -atm/cam/sst/sst_HadOIBl_bc_32x64_clim_c050526.nc -atm/cam/sst/sst_HadOIBl_bc_8x16_clim_c050526.nc - -atm/cam/sst/sst_HadOIBl_bc_1x1_clim_c101029.nc -atm/cam/sst/sst_HadOIBl_bc_1x1_clim_c101029.nc - - -atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_clim_pi_c091020.nc -atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_clim_pi_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_clim_pi_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_clim_pi_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_4x5_clim_pi_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_10x15_clim_pi_c100127.nc - -atm/cam/sst/sst_HadOIBl_bc_128x256_clim_pi_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_64x128_clim_pi_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_48x96_clim_pi_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_32x64_clim_pi_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_8x16_clim_pi_c100128.nc - -atm/cam/sst/sst_HadOIBl_bc_1x1_clim_pi_c100129.nc -atm/cam/sst/sst_HadOIBl_bc_1x1_clim_pi_c100129.nc - - -atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_clim_pi_c091020.nc -atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_4x5_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_10x15_1850_2012_c130411.nc - -atm/cam/sst/sst_HadOIBl_bc_128x256_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_64x128_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_48x96_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_32x64_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_8x16_1850_2012_c130411.nc - -atm/cam/sst/sst_HadOIBl_bc_1x1_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_1x1_1850_2012_c130411.nc - -atm/cam/som/cam4.som.forcing.aquaplanet.QzaFix_h50Fix_TspunFix.fv19.nc - - -ocn/docn7/domain.ocn.1x1.111007.nc -ocn/docn7/domain.ocn.1x1.111007.nc - - -atm/cam/ocnfrac/domain.camocn.128x256_USGS_070807.nc -share/domains/domain.ocn.T42_gx1v7.180727.nc -share/domains/domain.ocn.48x96_gx3v7_100114.nc -atm/cam/ocnfrac/domain.camocn.32x64_USGS_070807.nc -atm/cam/ocnfrac/domain.camocn.8x16_USGS_070807.nc - -atm/cam/ocnfrac/domain.camocn.0.23x0.31_gx1v6_101108.nc -atm/cam/ocnfrac/domain.camocn.0.47x0.63_gx1v6_090408.nc -share/domains/domain.ocn.fv0.9x1.25_gx1v7.151020.nc -share/domains/domain.ocn.fv1.9x2.5_gx1v7.170518.nc -share/domains/domain.ocn.4x5_gx3v7_100120.nc -atm/cam/ocnfrac/domain.camocn.10x15_USGS_070807.nc - -share/domains/domain.ocn.C24_gx1v7_c200625.nc -share/domains/domain.ocn.C48_gx1v7_c200625.nc -share/domains/domain.ocn.C96_gx1v7_c200625.nc -share/domains/domain.ocn.C192_gx1v7_c200625.nc -share/domains/domain.ocn.C384_gx1v7_c200625.nc - -share/domains/domain.ocn.ne5np4_gx3v7.140810.nc -share/domains/domain.ocn.ne16np4_gx1v7.171018.nc -share/domains/domain.ocn.ne30_gx1v7.171003.nc -share/domains/domain.ocn.ne60np4_gx1v6.121113.nc -share/domains/domain.ocn.ne120np4_gx1v6.121113.nc -share/domains/domain.ocn.ne240np4_gx1v6.111226.nc - -atm/cam/ocnfrac/domain.aqua.fv1.9x2.5.nc - HEMCO_Config.rc diff --git a/bld/namelist_files/namelist_definition.xml b/bld/namelist_files/namelist_definition.xml index b7c8d46f50..05fafa608d 100644 --- a/bld/namelist_files/namelist_definition.xml +++ b/bld/namelist_files/namelist_definition.xml @@ -1733,7 +1733,7 @@ Default: none + group="cam_history_nl" valid_values="A,B,I,X,M,N,L,S" > Sets the averaging flag for all variables on a particular history file series. Valid values are: @@ -1741,6 +1741,7 @@ series. Valid values are: B ==> GMT 00:00:00 average I ==> Instantaneous M ==> Minimum + N ==> average over nsteps X ==> Maximum L ==> Local-time S ==> Standard deviation @@ -1832,6 +1833,7 @@ are: B ==> GMT 00:00:00 average I ==> Instantaneous M ==> Minimum + N ==> average over nsteps X ==> Maximum L ==> Local-time S ==> Standard deviation @@ -1906,27 +1908,27 @@ if .true. then output CLUBBs radiative history statistics Default: false - Same as {{ hilight }}fincl1{{ closehilight }}, but for CLUBB statistics on zt grid. - Same as {{ hilight }}fincl1{{ closehilight }}, but for CLUBB statistics on zm grid. - Same as {{ hilight }}fincl1{{ closehilight }}, but for CLUBB statistics on radiation zt grid. - Same as {{ hilight }}fincl1{{ closehilight }}, but for CLUBB statistics on radiation zm grid. - Same as {{ hilight }}fincl1{{ closehilight }}, but for CLUBB statistics on surface. @@ -2825,6 +2827,18 @@ Add diagnostic output for heterogeneous freezing code. Default: .false. + +Heterogeneous freezing scaling factor for black carbon aerosols. +Default: 0.01 + + + +Heterogeneous freezing scaling factor for dust aerosols. +Default: 0.05 + + Switch to turn on treatment of pre-existing ice in the ice nucleation code. @@ -3545,7 +3559,7 @@ Include effects of precip evaporation on turbulent moments Switch for CLUBB_ADV parameter that turns on advection of CLUBB pdf moments by -the dynamics core. Very experimental. +the dynamics core. Very experimental. @@ -3894,7 +3908,7 @@ xpyp only. -Flag to apply a locally calculated ustar to momentum surface fluxes in the +Flag to apply a locally calculated ustar to momentum surface fluxes in the clubb interface. @@ -3960,8 +3974,8 @@ Flag to turn on the clubb monotonic flux limiter for vm (meridional momemtum). -Flag to use an "upwind" discretization rather than a centered discretization -for the portion of the wp3 turbulent advection term for ADG1 that is linearized +Flag to use an "upwind" discretization rather than a centered discretization +for the portion of the wp3 turbulent advection term for ADG1 that is linearized in terms of wp3(t+1). (Requires ADG1 PDF and l_standard_term_ta=true). @@ -3988,7 +4002,7 @@ Flag to use smooth Heaviside 'Peskin' in computation of invrs_tau. -Use the standard discretization for the turbulent advection terms. Setting to +Use the standard discretization for the turbulent advection terms. Setting to .false. means that a_1 and a_3 are pulled outside of the derivative in advance_wp2_wp3_module.F90 and in advance_xp2_xpyp_module.F90. @@ -4070,7 +4084,7 @@ production) term. -Flag used to calculate convective velocity using a variable estimate of layer +Flag used to calculate convective velocity using a variable estimate of layer depth based on the depth over which wpthlp is positive near the ground when true @@ -4764,7 +4778,7 @@ Default: set by build-namelist + +History tape number thermo budget output is written to. +Default: 1 + + + +Produce output for the energy budget diagnostic package. +Default: .false. + @@ -6211,14 +6236,8 @@ List of species that are constrained in the stratosphere. Default: set by build-namelist. - -Full pathname of dataset for land mask applied to the lighting NOx production -Default: set by build-namelist. - - + group="lightning_nl" valid_values="" > Multiplication factor applied to the lighting NOx production Default: 1.0. @@ -7260,6 +7279,36 @@ List of nitrogen deposition fluxes to be sent from CAM to surface models. Default: set by build-namelist. + +Year first to use in nitrogen deposition stream data. Set by case xml variable +CAM_STREAM_NDEP_YEAR_FIRST + + + +Year last to use in nitrogen deposition stream data. +Set by case xml variable CAM_STREAM_NDEP_YEAR_LAST + + + +Model year to align with CAM_STREAM_NDEP_YEAR_FIRST. +Set by case xml variable CAM_STREAM_NDEP_YEAR_ALIGN + + + +NDEP stream data filename. +Set by case xml variable CAM_STREAM_NDEP_DATA_FILENAME. + + + +NDEP mesh file corresponding to sream_ndep_data_filename. +Set by case xml variable CAM_STREAM_NDEP_MESH_FILENAME. + + File containing MEGAN emissions factors. @@ -7296,6 +7345,12 @@ coarser temporal resolution. Default: set by build-namelist. + +If TRUE atmosphere model will provide prognosed lightning flash frequency. +Default: FALSE + + - -Scaling of temperature increment for different levels of -thermal energy consistency. -0: no scaling -1: scale increment for cp consistency between dynamics and physics -2: do 1 as well as take into account condensate effect on thermal energy -Default: Set by build-namelist. - - Hyperviscosity coefficient for u,v, T [m^4/s]. @@ -7730,17 +7775,6 @@ If < 0, se_sponge_del4_lev is automatically set based on model top location. Default: Set by build-namelist. - -If TRUE the continous equations the dynamical core is based on will conserve a -comprehensive moist total energy -If FALSE the continous equations the dynamical core is based on will conserve -a total energy based on cp for dry air and no condensates (same total energy as -CAM physics uses). -For more details see Lauritzen et al., (2018;DOI:10.1029/2017MS001257) -Default: TRUE - - If TRUE the CSLAM algorithm will work for Courant number larger than 1 with @@ -8285,30 +8319,6 @@ us_standard_atmosphere: static atmospheric state (u,v)=0, standard lapse rate fo Default: 'none' - - - - - -Full pathname of time-variant sea-surface temperature and sea-ice -concentration boundary dataset. -Default: set by build-namelist. - - - -Full pathname of -Default: set by build-namelist. - - - -Full pathname of grid file for time-variant sea-surface temperature and sea-ice -concentration boundary dataset. -Default: set by build-namelist. - - + + + + + + + +Stream filename(s) for Nitrogen Deposition data + + + +Stream meshfile for Nitrogen Deposition data + + + +First year to loop over for Nitrogen Deposition data + + + +Last year to loop over for Nitrogen Deposition data + + + +Simulation year that aligns with stream_year_first_ndep value + + diff --git a/bld/namelist_files/use_cases/1850-2005_cam5.xml b/bld/namelist_files/use_cases/1850-2005_cam5.xml index 8a6c2a7f0c..5d4a572be0 100644 --- a/bld/namelist_files/use_cases/1850-2005_cam5.xml +++ b/bld/namelist_files/use_cases/1850-2005_cam5.xml @@ -56,35 +56,11 @@ INTERP_MISSING_MONTHS - atm/cam/chem/trop_mozart_aero/oxid - oxid_1.9x2.5_L26_1850-2005_c091123.nc - INTERP_MISSING_MONTHS + atm/cam/chem/trop_mozart_aero/oxid + oxid_1.9x2.5_L26_1850-2005_c091123.nc + INTERP_MISSING_MONTHS 1850-2000 - -.false. -1850 -2012 -2008 - -atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_4x5_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_10x15_1850_2012_c130411.nc - -atm/cam/sst/sst_HadOIBl_bc_128x256_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_64x128_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_48x96_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_32x64_1850_2012_c130411.nc -atm/cam/sst/sst_HadOIBl_bc_8x16_1850_2012_c130411.nc - - -.true. -0 -0 -atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_clim_pi_c091020.nc - diff --git a/bld/namelist_files/use_cases/1850_cam_lt.xml b/bld/namelist_files/use_cases/1850_cam_lt.xml new file mode 100644 index 0000000000..f3c043d55b --- /dev/null +++ b/bld/namelist_files/use_cases/1850_cam_lt.xml @@ -0,0 +1,67 @@ + + + + +atm/cam/solar/SolarForcingCMIP6piControl_c160921.nc + 18500101 + FIXED + + +atm/cam/inic/se/FWsc_ne30pg3_58L_GRID_48_taperstart10km_lowtop_BL10_v3_beta1p75_Top_43km.nc + + +atm/waccm/lb/LBC_17500116-20150116_CMIP6_0p5degLat_c180905.nc +1850 +'CYCLICAL' +'CO2','CH4','N2O','CFC11','CFC12','CFC11eq' + + +'Q:H2O->UBC_FILE' +atm/cam/chem/ubc/b.e21.BWHIST.f09_g17.CMIP6-historical-WACCM.ensAvg123.cam.h0zm.H2O.185001-201412_c230509cdf5.nc +CYCLICAL +1850 + + + 'atm/cam/ozone_strataero' + 'ozone_strataero_cyclical_WACCM6_L70_CMIP6-piControl.001_y21-50avg_zm_5day_c180802.nc' + 'O3' + CYCLICAL + 1850 + + + 1850 + 'atm/cam/ozone_strataero' + 'ozone_strataero_cyclical_WACCM6_L70_CMIP6-piControl.001_y21-50avg_zm_5day_c180802.nc' + .true. + 'CYCLICAL' + + + + 1850 + 'atm/cam/tracer_cnst' + 'tracer_cnst_WACCM6_halons_3DmonthlyL70_1850climoCMIP6piControl001_y21-50avg_c180802.nc' + 'O3','OH','NO3','HO2','HALONS' + 'CYCLICAL' + '' + + + CYCLICAL + 1850 + + 'num_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_num_so4_a1_anthro-ene_vertical_mol_175001-201412_ne30pg3_c20200103.nc', + 'num_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_num_a1_so4_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'num_a2 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_num_a2_so4_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'SO2 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_SO2_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'so4_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_so4_a1_anthro-ene_vertical_mol_175001-201412_ne30pg3_c20200103.nc', + 'so4_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_so4_a1_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'so4_a2 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_so4_a2_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc' + + + + CYCLICAL + 1850 + +CYCLICAL +1850 + + diff --git a/bld/namelist_files/use_cases/1850_cam_mt.xml b/bld/namelist_files/use_cases/1850_cam_mt.xml new file mode 100644 index 0000000000..67049703f3 --- /dev/null +++ b/bld/namelist_files/use_cases/1850_cam_mt.xml @@ -0,0 +1,62 @@ + + + + +atm/cam/solar/SolarForcingCMIP6piControl_c160921.nc + 18500101 + FIXED + + +atm/cam/inic/se/L93_ne30pg3_ne30pg3_mg17_450_short.cam.i.1979-01-07-00000.nc + + +atm/waccm/lb/LBC_17500116-20150116_CMIP6_0p5degLat_c180905.nc +1850 +'CYCLICAL' +'CO2','CH4','N2O','CFC11','CFC12','CFC11eq' + + + + 'atm/cam/ozone_strataero' + 'ozone_strataero_cyclical_WACCM6_L70_CMIP6-piControl.001_y21-50avg_zm_5day_c180802.nc' + 'O3' + CYCLICAL + 1850 + + + 1850 + 'atm/cam/ozone_strataero' + 'ozone_strataero_cyclical_WACCM6_L70_CMIP6-piControl.001_y21-50avg_zm_5day_c180802.nc' + .true. + 'CYCLICAL' + + + + 1850 + 'atm/cam/tracer_cnst' + 'tracer_cnst_WACCM6_halons_3DmonthlyL70_1850climoCMIP6piControl001_y21-50avg_c180802.nc' + 'O3','OH','NO3','HO2','HALONS' + 'CYCLICAL' + '' + + + CYCLICAL + 1850 + + 'num_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_num_so4_a1_anthro-ene_vertical_mol_175001-201412_ne30pg3_c20200103.nc', + 'num_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_num_a1_so4_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'num_a2 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_num_a2_so4_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'SO2 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_SO2_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'so4_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_so4_a1_anthro-ene_vertical_mol_175001-201412_ne30pg3_c20200103.nc', + 'so4_a1 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_so4_a1_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc', + 'so4_a2 -> $INPUTDATA_ROOT/atm/cam/chem/emis/historical_ne30pg3/emissions-cmip6_so4_a2_contvolcano_vertical_850-5000_ne30pg3_c20200125.nc' + + + + CYCLICAL + 1850 + +CYCLICAL +1850 + + diff --git a/bld/namelist_files/use_cases/2000_cam6.xml b/bld/namelist_files/use_cases/2000_cam6.xml index 56195092cd..fef59dc7d3 100644 --- a/bld/namelist_files/use_cases/2000_cam6.xml +++ b/bld/namelist_files/use_cases/2000_cam6.xml @@ -2,13 +2,15 @@ - - 2000 - atm/cam/ozone - tracer_cnst_CAM6chem_2000climo_3D_monthly_c171004.nc - '' - 'O3','OH','NO3','HO2' - 'CYCLICAL' +atm/cam/ozone +tracer_cnst_CAM6chem_2000climo_3D_monthly_c171004.nc +'O3','OH','NO3','HO2' +atm/cam/tracer_cnst +tracer_cnst_halons_3D_L70_1849-2015_CMIP6ensAvg_c180927.nc +'O3','OH','NO3','HO2','HALONS' +2000 +CYCLICAL +'' 2000 atm/cam/ozone diff --git a/bld/namelist_files/use_cases/aquaplanet_cam3.xml b/bld/namelist_files/use_cases/aquaplanet_cam3.xml index 3fd3d876cb..373b2ad18d 100644 --- a/bld/namelist_files/use_cases/aquaplanet_cam3.xml +++ b/bld/namelist_files/use_cases/aquaplanet_cam3.xml @@ -57,9 +57,6 @@ - -.true. - 86164.10063718943 6.37100e6 @@ -78,4 +75,3 @@ 0 - diff --git a/bld/namelist_files/use_cases/aquaplanet_cam4.xml b/bld/namelist_files/use_cases/aquaplanet_cam4.xml index a18f4cfcd0..67d32c9f9f 100644 --- a/bld/namelist_files/use_cases/aquaplanet_cam4.xml +++ b/bld/namelist_files/use_cases/aquaplanet_cam4.xml @@ -31,8 +31,6 @@ - -.true. 86164.10063718943 6.37100e6 @@ -45,4 +43,3 @@ .false. - diff --git a/bld/namelist_files/use_cases/aquaplanet_cam5.xml b/bld/namelist_files/use_cases/aquaplanet_cam5.xml index afc820ecef..814eecd98f 100644 --- a/bld/namelist_files/use_cases/aquaplanet_cam5.xml +++ b/bld/namelist_files/use_cases/aquaplanet_cam5.xml @@ -29,10 +29,6 @@ CYCLICAL 1990 - -.true. - - 86164.10063718943 6.37100e6 @@ -50,4 +46,3 @@ "" - diff --git a/bld/namelist_files/use_cases/aquaplanet_cam6.xml b/bld/namelist_files/use_cases/aquaplanet_cam6.xml index cbe41e8cee..814eecd98f 100644 --- a/bld/namelist_files/use_cases/aquaplanet_cam6.xml +++ b/bld/namelist_files/use_cases/aquaplanet_cam6.xml @@ -29,9 +29,6 @@ CYCLICAL 1990 - -.true. - 86164.10063718943 6.37100e6 @@ -49,4 +46,3 @@ "" - diff --git a/bld/namelist_files/use_cases/aquaplanet_rce_cam6.xml b/bld/namelist_files/use_cases/aquaplanet_rce_cam6.xml index 01d810b08d..f03c4294b2 100644 --- a/bld/namelist_files/use_cases/aquaplanet_rce_cam6.xml +++ b/bld/namelist_files/use_cases/aquaplanet_rce_cam6.xml @@ -44,9 +44,6 @@ CYCLICAL 1990 - -.true. - .true. 0.73391095 @@ -71,4 +68,3 @@ 0.0 - diff --git a/bld/namelist_files/use_cases/hist_cam_lt.xml b/bld/namelist_files/use_cases/hist_cam_lt.xml new file mode 100644 index 0000000000..577610275c --- /dev/null +++ b/bld/namelist_files/use_cases/hist_cam_lt.xml @@ -0,0 +1,48 @@ + + + +19790101 + + +atm/cam/solar/SolarForcingCMIP6_18491230-23000102_c20200615.nc + + +atm/cam/inic/se/FWsc_ne30pg3_58L_GRID_48_taperstart10km_lowtop_BL10_v3_beta1p75_Top_43km.nc + + +atm/waccm/lb/LBC_17500116-20150116_CMIP6_0p5degLat_c180905.nc +'SERIAL' +'CO2','CH4','N2O','CFC11','CFC12','CFC11eq' + + +'Q:H2O->UBC_FILE' +atm/cam/chem/ubc/f.e21.FWHISTBgcCrop.f09_f09_mg17.CMIP6-AMIP-WACCM.ensAvg123.cam.h0zm.UBC.195001-201412_c220322.nc +'SERIAL' + + + 'atm/cam/ozone_strataero' + 'ozone_strataero_WACCM_L70_zm5day_18500101-20150103_CMIP6ensAvg_c180923.nc' + 'O3' + SERIAL + + + .true. + 'atm/cam/ozone_strataero' + 'ozone_strataero_WACCM_L70_zm5day_18500101-20150103_CMIP6ensAvg_c180923.nc' + SERIAL + + + 'atm/cam/tracer_cnst' + 'tracer_cnst_halons_3D_L70_1849-2015_CMIP6ensAvg_c180927.nc' + 'O3','OH','NO3','HO2','HALONS' + INTERP_MISSING_MONTHS + '' + + +INTERP_MISSING_MONTHS + + +INTERP_MISSING_MONTHS +SERIAL + + diff --git a/bld/namelist_files/use_cases/hist_cam_mt.xml b/bld/namelist_files/use_cases/hist_cam_mt.xml new file mode 100644 index 0000000000..08c53aa595 --- /dev/null +++ b/bld/namelist_files/use_cases/hist_cam_mt.xml @@ -0,0 +1,43 @@ + + + +19790101 + + +atm/cam/solar/SolarForcingCMIP6_18491230-23000102_c20200615.nc + + +atm/cam/inic/se/L93_ne30pg3_ne30pg3_mg17_450_short.cam.i.1979-01-07-00000.nc + + +atm/waccm/lb/LBC_17500116-20150116_CMIP6_0p5degLat_c180905.nc +'SERIAL' +'CO2','CH4','N2O','CFC11','CFC12','CFC11eq' + + + 'atm/cam/ozone_strataero' + 'ozone_strataero_WACCM_L70_zm5day_18500101-20150103_CMIP6ensAvg_c180923.nc' + 'O3' + SERIAL + + + .true. + 'atm/cam/ozone_strataero' + 'ozone_strataero_WACCM_L70_zm5day_18500101-20150103_CMIP6ensAvg_c180923.nc' + SERIAL + + + 'atm/cam/tracer_cnst' + 'tracer_cnst_halons_3D_L70_1849-2015_CMIP6ensAvg_c180927.nc' + 'O3','OH','NO3','HO2','HALONS' + INTERP_MISSING_MONTHS + '' + + +INTERP_MISSING_MONTHS + + +INTERP_MISSING_MONTHS +SERIAL + + diff --git a/bld/namelist_files/use_cases/sd_waccm_sulfur.xml b/bld/namelist_files/use_cases/sd_waccm_sulfur.xml index f45159054a..25c4d622de 100644 --- a/bld/namelist_files/use_cases/sd_waccm_sulfur.xml +++ b/bld/namelist_files/use_cases/sd_waccm_sulfur.xml @@ -139,27 +139,4 @@ 1850-2000 - -.false. -1850 -2008 - -atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_1850_2008_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_1850_2008_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_4x5_1850_2008_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_10x15_1850_2008_c100127.nc - -atm/cam/sst/sst_HadOIBl_bc_128x256_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_64x128_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_48x96_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_32x64_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_8x16_1850_2008_c100128.nc - - -.true. -0 -0 -atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_clim_pi_c091020.nc - diff --git a/bld/namelist_files/use_cases/waccm_carma_bc_2013_cam4.xml b/bld/namelist_files/use_cases/waccm_carma_bc_2013_cam4.xml index ff2a72cbcc..a6e5287553 100644 --- a/bld/namelist_files/use_cases/waccm_carma_bc_2013_cam4.xml +++ b/bld/namelist_files/use_cases/waccm_carma_bc_2013_cam4.xml @@ -46,12 +46,12 @@ atm/waccm/sulf/SAD_SULF_1849-2100_1.9x2.5_c090817.nc 'SERIAL' - + .false. atm/waccm/qbo/qbocoefficients_c091230.nc' -.true. +.true. @@ -75,42 +75,42 @@ 0, -240, -240, -24, -24 'A', 'I', 'I', 'A', 'A' - + - 'AOA1', 'AOA2', 'BR', 'BRCL', 'BRO', 'BRONO2', 'CCL4', 'CF2CLBR', 'CF3BR', - 'CFC11', 'CFC113', 'CFC12', 'CH2O', 'CH3BR', 'CH3CCL3', 'CH3CL', 'CH3O2', 'CH3OOH', - 'CH4', 'CL', 'CL2', 'CL2O2', 'CLDHGH', 'CLDLOW', 'CLDMED', 'CLDTOT', 'CLO', 'CLONO2', - 'CLOUD', 'CO', 'CO2', 'DTCOND', 'DTV', 'DUV', 'DVV', 'EKGW', 'FLNS', 'FLNSC', 'FLNT', + 'AOA1', 'AOA2', 'BR', 'BRCL', 'BRO', 'BRONO2', 'CCL4', 'CF2CLBR', 'CF3BR', + 'CFC11', 'CFC113', 'CFC12', 'CH2O', 'CH3BR', 'CH3CCL3', 'CH3CL', 'CH3O2', 'CH3OOH', + 'CH4', 'CL', 'CL2', 'CL2O2', 'CLDHGH', 'CLDLOW', 'CLDMED', 'CLDTOT', 'CLO', 'CLONO2', + 'CLOUD', 'CO', 'CO2', 'DTCOND', 'DTV', 'DUV', 'DVV', 'EKGW', 'FLNS', 'FLNSC', 'FLNT', 'FLNTC', 'FSDS', 'FSNS', 'FSNSC', 'FSNT', 'FSNTC', 'H', 'H2', 'H2O', 'H2O2', 'HBR', 'HCFC22', 'HCL', 'HNO3', 'HO2', 'HO2NO2', 'HOBR', 'HOCL', 'HORZ', 'LANDFRAC', 'LHFLX', 'N', 'N2O', 'N2O5', 'NO', 'NO2', 'NO3', 'O', 'O1D', 'O2', 'O3', 'OCLO', 'OCNFRAC', 'OH', 'OMEGA', 'PHIS', 'PRECC', 'PRECL', 'PS', 'Q', 'QFLX', 'QPERT', 'QRL', 'QRLNLTE', 'QRS', 'RELHUM', 'SHFLX', 'SOLIN', 'SWCF', 'QCP', - 'QTHERMAL', 'QRL_TOT', 'QRS_TOT', 'QJOULE', 'PSL', 'HNO3_STS', 'HNO3_NAT', - 'HNO3_GAS', 'NO_Aircraft', 'NO_Lightning', 'QNO', 'QRS_AUR', 'QRS_CO2NIR', 'QRS_EUV', - 'SAD_ICE', 'SAD_LNAT', 'SAD_SULFC', 'T', 'TREFHT', - 'TTGW', 'U', 'UTGWORO', 'UTGWSPEC', 'V', 'VERT', 'VTGWORO', 'VTGWSPEC', 'Z3', 'O2_1S', - 'O2_1D', 'NOX', 'NOY', 'CLOX', 'CLOY', 'BROX', 'BROY', 'TCLY', 'TOTH', 'QJOULE', 'UI', + 'QTHERMAL', 'QRL_TOT', 'QRS_TOT', 'QJOULE', 'PSL', 'HNO3_STS', 'HNO3_NAT', + 'HNO3_GAS', 'NO_Aircraft', 'NO_Lightning', 'QNO', 'QRS_AUR', 'QRS_CO2NIR', 'QRS_EUV', + 'SAD_ICE', 'SAD_LNAT', 'SAD_SULFC', 'T', 'TREFHT', + 'TTGW', 'U', 'UTGWORO', 'UTGWSPEC', 'V', 'VERT', 'VTGWORO', 'VTGWSPEC', 'Z3', 'O2_1S', + 'O2_1D', 'NOX', 'NOY', 'CLOX', 'CLOY', 'BROX', 'BROY', 'TCLY', 'TOTH', 'QJOULE', 'UI', 'VI', 'UIONTEND', 'VIONTEND', 'DTCORE', 'T_24_COS', 'T_24_SIN', 'T_12_COS', 'T_12_SIN', 'OMEGA_24_COS', 'OMEGA_24_SIN', 'OMEGA_12_COS', 'OMEGA_12_SIN', - 'U_24_COS', 'U_24_SIN', 'U_12_COS', 'U_12_SIN', 'V_24_COS', 'V_24_SIN', 'V_12_COS', + 'U_24_COS', 'U_24_SIN', 'U_12_COS', 'U_12_SIN', 'V_24_COS', 'V_24_SIN', 'V_12_COS', 'V_12_SIN', 'PS_24_COS', 'PS_24_SIN', 'PS_12_COS', 'PS_12_SIN', 'CLDLIQ','CLDICE','CONCLD', 'FRONTGF:I', 'BUTGWSPEC', 'BTAUE', 'BTAUW', 'BTAUN', 'BTAUS','TAUE','TAUW','TAUN','TAUS', 'TAUGWX', 'TAUGWY', 'TAUX','TAUY','SNOWHLND','SNOWHICE','ICEFRAC','FSDSC','SFNO', 'SFCO', 'SFCH2O','CFC11STAR','TROPP_FD' - + - 'PS', 'Z3', 'T', 'U', 'V', 'FLNT','PSL', + 'PS', 'Z3', 'T', 'U', 'V', 'FLNT','PSL', 'OMEGA','FSDS','FSDSC','CLOUD','CONCLD','SNOWHLND','SNOWHICE', - 'CH3CL', 'CFC11', 'CFC12', 'CFC113', 'HCFC22', 'CCL4', 'CH3CCL3', + 'CH3CL', 'CFC11', 'CFC12', 'CFC113', 'HCFC22', 'CCL4', 'CH3CCL3', 'CH3BR', 'CF3BR', 'CF2CLBR', 'CO', 'CO2', 'CH2O', 'CH3OOH', 'CH4', 'O3', 'O', 'O1D', 'N', 'NO', 'NO2', 'NO3', 'N2O5', 'HNO3', 'HO2NO2', 'NOX', 'NOY', 'N2O', 'H', 'H2', 'OH', 'HO2', 'H2O2', 'H2O', - 'CL','CL2', 'CLO', 'OCLO', 'CL2O2', 'CLONO2', 'HOCL', 'HCL', 'CLOX', 'CLOY', + 'CL','CL2', 'CLO', 'OCLO', 'CL2O2', 'CLONO2', 'HOCL', 'HCL', 'CLOX', 'CLOY', 'BR', 'BRO', 'HOBR', 'HBR', 'BRCL', 'BRONO2', 'BROX', 'BROY', 'TCLY', 'jo2_a', 'jo2_b', 'jo3_a', 'jo3_b', 'jhocl', 'jno3_b', 'jcl2o2', 'SAD_SULFC', 'SAD_LNAT', 'SAD_ICE','AOA1','AOA2', @@ -118,7 +118,7 @@ 'VTHzm', 'WTHzm', 'UVzm', 'UWzm', 'TH', 'MSKtem' - + 'PS:B', 'T:B', 'Z3:B', 'U:B', 'V:B', 'CO:B', 'CO2:B', 'H2:B', 'O:B', 'O2:B', 'O3:B', 'H:B', 'OH:B', 'HO2:B', 'H2O:B', @@ -126,11 +126,11 @@ 'Np:B', 'N2p:B', 'Op:B', 'O2p:B', 'NOp:B', 'e:B', 'QRL_TOT:B', 'QRS_TOT:B', 'QJOULE:B', 'jno3_a:B', 'jno3_b:B', 'jcl2o2:B', 'CL2O2:B', 'CLO:B', 'BRO:B', 'NO3:B', 'DTCORE:B', 'DTV:B', 'TTGW:B','OMEGA:B' - + - 'PS', 'PSL', 'U', 'V', 'T', 'Z3', 'PHIS','FRONTGF:I', 'OMEGA' + 'PS', 'PSL', 'U', 'V', 'T', 'Z3', 'PHIS','FRONTGF:I', 'OMEGA' - + 'MSKtem', 'PS', 'PSL', 'VTHzm', 'UVzm', 'UWzm', 'Uzm', 'Vzm', 'THzm','Wzm', 'PHIS' @@ -138,27 +138,4 @@ 1850-2000 - -.false. -1850 -2008 - -atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_1850_2008_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_1850_2008_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_4x5_1850_2008_c100127.nc -atm/cam/sst/sst_HadOIBl_bc_10x15_1850_2008_c100127.nc - -atm/cam/sst/sst_HadOIBl_bc_128x256_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_64x128_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_48x96_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_32x64_1850_2008_c100128.nc -atm/cam/sst/sst_HadOIBl_bc_8x16_1850_2008_c100128.nc - - -.true. -0 -0 -atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_clim_pi_c091020.nc - diff --git a/cime_config/buildnml b/cime_config/buildnml index ca44b885d5..c35f7c6243 100755 --- a/cime_config/buildnml +++ b/cime_config/buildnml @@ -48,6 +48,12 @@ def buildnml(case, caseroot, compname): RUN_REFTOD = case.get_value("RUN_REFTOD") COMP_INTERFACE = case.get_value("COMP_INTERFACE") + stream_ndep_year_first = case.get_value("CAM_STREAM_NDEP_YEAR_FIRST") + stream_ndep_year_last = case.get_value("CAM_STREAM_NDEP_YEAR_LAST") + stream_ndep_year_align = case.get_value("CAM_STREAM_NDEP_YEAR_ALIGN") + stream_ndep_data_filename = case.get_value("CAM_STREAM_NDEP_DATA_FILENAME") + stream_ndep_mesh_filename = case.get_value("CAM_STREAM_NDEP_MESH_FILENAME") + testsrc = os.path.join(srcroot, "components", "cam") if os.path.exists(testsrc): srcroot = testsrc @@ -167,6 +173,12 @@ def buildnml(case, caseroot, compname): buildnl_opts += ["-inputdata", input_data_list] + CAM_NAMELIST_OPTS += " stream_ndep_year_first=" + stream_ndep_year_first + CAM_NAMELIST_OPTS += " stream_ndep_year_last=" + stream_ndep_year_last + CAM_NAMELIST_OPTS += " stream_ndep_year_align=" + stream_ndep_year_align + CAM_NAMELIST_OPTS += " stream_ndep_data_filename='" + stream_ndep_data_filename.strip() + "'" + CAM_NAMELIST_OPTS += " stream_ndep_mesh_filename='" + stream_ndep_mesh_filename.strip() + "'" + buildnl_opts += ["-namelist", '" &atmexp ' + CAM_NAMELIST_OPTS + '/" '] diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml index b09dd13d17..a31f354dc5 100644 --- a/cime_config/config_component.xml +++ b/cime_config/config_component.xml @@ -13,7 +13,7 @@ CAM cam4 physics: CAM cam3 physics: CAM simplified and non-versioned physics : - CAM7 development physics: + CAM7 development physics: - 58 vertical layers: - 93 vertical layers: CAM-Chem troposphere/stratosphere chemistry with simplified VBS-SOA: CAM-Chem troposphere/stratosphere chemistry with simplified VBS-SOA and expanded isoprene and terpene oxidation: GEOS-Chem troposphere/stratosphere chemistry : CAM-Chem troposphere/stratosphere chem with simplified volatility basis set SOA scheme and fire emissons : CAM CLUBB - turned on by default in CAM60: - CAM-Chem troposphere/stratosphere chem with extended volatility basis set SOA scheme and modal aerosols : + CAM-Chem troposphere/stratosphere chem with extended volatility basis set SOA scheme and modal aersols : + CAM low top model + Prognostic GHG chemistry mechanism for CAM7: Modal Aerosol Model composed of 7 modes: + CAM mid top model CAM CO2 ramp: CAM super-parameterized CAM one moment SAM microphysics CAM super-parameterized CAM one moment SAM microphysics using CLUBB @@ -130,6 +131,7 @@ -phys cam_dev + -chem ghg_mam4 -chem trop_strat_mam5_vbs -chem geoschem_mam4 -hemco @@ -163,13 +165,14 @@ -chem waccm_mad_mam5 -offline_dyn + -nlev 56 -nlev 56 -nlev 56 -nlev 88 -nlev 145 - -nlev 58 - -nlev 93 + -nlev 58 + -nlev 93 -phys adiabatic @@ -210,6 +213,8 @@ waccm_tsmlt_1850_cam6 waccm_ma_1850_cam6 waccm_sc_1850_cam6 + 1850_cam_lt + 1850_cam_mt 2000_cam4_trop_chem waccmxie_ma_2000_cam4 @@ -253,6 +258,8 @@ 1950-2010_ccmi_refc1_waccmx_ma 1850-2005_cam5 hist_cam6 + hist_cam_lt + hist_cam_mt waccm_tsmlt_hist_cam6 waccm_sc_hist_cam6 waccm_ma_hist_cam6 @@ -361,6 +368,79 @@ User mods to apply to specific compset matches. + + + + char + 2000 + + 1850 + 2010 + 1850 + 2015 + + run_component_cam + env_run.xml + Nitrogen deposition data year first + + + + char + 2000 + + 2010 + 1850 + 2015 + 2101 + + run_component_cam + env_run.xml + Nitrogen deposition data year last + + + + char + 1 + + 1850 + 2015 + + run_component_cam + env_run.xml + Nitrogen deposition align CAM_STREAM_NDEP_YEAR_FIRST with this model year + + + + + char + UNSET + + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_f09_g17.CMIP6-SSP5-8.5-WACCM_1849-2101_monthly_c191007.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_f09_g17.CMIP6-SSP1-2.6-WACCM_1849-2101_monthly_c191007.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_f09_g17.CMIP6-SSP2-4.5-WACCM_1849-2101_monthly_c191007.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_SSP370_b.e21.BWSSP370cmip6.f09_g17.CMIP6-SSP3-7.0-WACCM.002_1849-2101_monthly_0.9x1.25_c211216.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_hist_b.e21.BWHIST.f09_g17.CMIP6-historical-WACCM.ensmean_1849-2015_monthly_0.9x1.25_c180926.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_hist_b.e21.BWHIST.f09_g17.CMIP6-historical-WACCM.ensmean_1849-2015_monthly_0.9x1.25_c180926.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_hist_b.e21.BWHIST.f09_g17.CMIP6-historical-WACCM.ensmean_1849-2015_monthly_0.9x1.25_c180926.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_WACCM6_CMIP6piControl001_y21-50avg_1850monthly_0.95x1.25_c180802.nc + + run_component_cam + env_run.xml + Nitrogen deposition data filename + + + + char + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + run_component_cam + env_run.xml + Nitrogen deposition mesh filename (corresponding to the CAM_STREAM_NDEP_DATA_FILENAME) + + ========================================= CAM naming conventions diff --git a/cime_config/config_compsets.xml b/cime_config/config_compsets.xml index 65051c66ac..0bd04659ff 100644 --- a/cime_config/config_compsets.xml +++ b/cime_config/config_compsets.xml @@ -61,6 +61,26 @@ + + FLTHIST_v0c + HIST_CAM%DEV%LT%GHGMAM4_CLM51%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV + + + + FMTHIST_v0c + HIST_CAM%DEV%MT%GHGMAM4_CLM51%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV + + + + FLT1850_TESTINGONLY_v0c + 1850_CAM%DEV%LT%GHGMAM4_CLM51%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV + + + + FMT1850_TESTINGONLY_v0c + 1850_CAM%DEV%MT%GHGMAM4_CLM51%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV + + FHIST_BGC HIST_CAM60_CLM50%BGC-CROP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV @@ -316,11 +336,11 @@ FCLTHIST - HIST_CAM%DEV%L58%CCTS1_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV + HIST_CAM%DEV%LT%CCTS1_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV FCMTHIST - HIST_CAM%DEV%L93%CCTS1_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV + HIST_CAM%DEV%MT%CCTS1_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV FCvbsxHIST @@ -597,51 +617,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 diff --git a/cime_config/testdefs/testlist_cam.xml b/cime_config/testdefs/testlist_cam.xml index 4806d18d52..a67c77f510 100644 --- a/cime_config/testdefs/testlist_cam.xml +++ b/cime_config/testdefs/testlist_cam.xml @@ -1424,7 +1424,15 @@ - + + + + + + + + + @@ -2506,9 +2514,10 @@ - + + diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/user_nl_cam deleted file mode 100644 index 53ed11dfc5..0000000000 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/user_nl_cam +++ /dev/null @@ -1,5 +0,0 @@ -mfilt=1,1,1,1,1,1,1,1,1,1 -ndens=1,1,1,1,1,1,1,1,1,1 -nhtfrq=-24,-24,-24,-24,-24,-24,-24,-24,-24,-24 -tracer_cnst_specifier = 'O3','OH','NO3','HO2','HALONS' -ubc_specifier = 'NOTSET' diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/shell_commands b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/shell_commands similarity index 84% rename from cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/shell_commands rename to cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/shell_commands index eca142f772..513b5dbe41 100644 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/shell_commands +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/shell_commands @@ -1,3 +1,3 @@ ./xmlchange ROF_NCPL=\$ATM_NCPL ./xmlchange RUN_STARTDATE=0001-12-14 -./xmlchange CAM_CONFIG_OPTS="-phys cam_dev -microphys mg2 -chem waccm_sc_mam4 -nlev 32" +./xmlchange CAM_CONFIG_OPTS="-phys cam_dev -microphys mg2 -chem ghg_mam4 -nlev 32" diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/user_nl_cam new file mode 100644 index 0000000000..1e5bc2fa49 --- /dev/null +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/user_nl_cam @@ -0,0 +1,9 @@ +mfilt=1,1,1,1,1,1,1,1,1,1 +ndens=1,1,1,1,1,1,1,1,1,1 +nhtfrq=-24,-24,-24,-24,-24,-24,-24,-24,-24,-24 +tracer_cnst_specifier = 'O3','OH','NO3','HO2','HALONS' +flbc_cycle_yr=1850 +phys_grid_ctem_nfreq=-6 +phys_grid_ctem_zm_nbas=16 +phys_grid_ctem_za_nlat=15 +fincl2 = 'THphys','VTHzm','WTHzm','UVzm','UWzm','Uzm','Vzm','Wzm','THzm' diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/user_nl_clm b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/user_nl_clm similarity index 100% rename from cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_L32wsc/user_nl_clm rename to cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/user_nl_clm diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_physgrid_tem_mpasa120_wcmsc/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_physgrid_tem_mpasa120_wcmsc/user_nl_cam index 1212d35edd..1769cf51c8 100644 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq1d_physgrid_tem_mpasa120_wcmsc/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq1d_physgrid_tem_mpasa120_wcmsc/user_nl_cam @@ -17,7 +17,7 @@ phys_grid_ctem_za_nlat = 90 fincl1 = ' ' fexcl1 = ' ' -fincl2 = 'VTHzaphys','WTHzaphys','UVzaphys','UWzaphys' +fincl2 = 'Uzm','Vzm','Wzm','THzm', 'VTHzm','WTHzm','UVzm','UWzm' mfilt=1,1,1,1,1,1,1,1,1,1 ndens=1,1,1,1,1,1,1,1,1,1 diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq3s_physgrid_tem/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/outfrq3s_physgrid_tem/user_nl_cam index 55e353983a..dad2b49ac7 100644 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq3s_physgrid_tem/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq3s_physgrid_tem/user_nl_cam @@ -5,4 +5,4 @@ inithist='ENDOFRUN' phys_grid_ctem_nfreq=3 phys_grid_ctem_zm_nbas=16 phys_grid_ctem_za_nlat=15 -fincl3 = 'VTHzaphys','WTHzaphys','UVzaphys','UWzaphys' +fincl3 = 'Uzm','Vzm','Wzm','THzm', 'VTHzm','WTHzm','UVzm','UWzm' diff --git a/cime_config/testdefs/testmods_dirs/cam/outfrq9s_physgrid_tem_1deg/user_nl_cam b/cime_config/testdefs/testmods_dirs/cam/outfrq9s_physgrid_tem_1deg/user_nl_cam index 9cf4e0a97d..a82b687449 100644 --- a/cime_config/testdefs/testmods_dirs/cam/outfrq9s_physgrid_tem_1deg/user_nl_cam +++ b/cime_config/testdefs/testmods_dirs/cam/outfrq9s_physgrid_tem_1deg/user_nl_cam @@ -5,4 +5,4 @@ inithist='ENDOFRUN' phys_grid_ctem_nfreq=-2 phys_grid_ctem_zm_nbas=120 phys_grid_ctem_za_nlat=90 -fincl3 = 'VTHzaphys','WTHzaphys','UVzaphys','UWzaphys' +fincl3 = 'Uzm','Vzm','Wzm','THzm', 'VTHzm','WTHzm','UVzm','UWzm' diff --git a/doc/ChangeLog b/doc/ChangeLog index d09f63077b..5d77cc2f5a 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,5 +1,2413 @@ =============================================================== +Tag name: cam6_3_111 +Originator(s): cacraig, hannay, fvitt +Date: May 17, 2023 +One-line Summary: create CAM LT and MT 1850 use_cases +Github PR URL: https://github.com/ESCOMP/CAM/pull/806 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + - Add use_cases for 1850 LT and MT compsets: https://github.com/ESCOMP/CAM/issues/804 + + *** IMPORTANT NOTE -- MT compsets do not run successfully for 9 time steps + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: + - See specific details below in file section: + Updated namelist settings based on discussion in: https://github.com/NCAR/amwg_dev/discussions/261 + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: hannay, nusbaume + +List all files eliminated: N/A + +List all files added and what they do: +A bld/namelist_files/use_cases/1850_cam_lt.xml +A bld/namelist_files/use_cases/1850_cam_mt.xml + - Initial use cases - setup for BLT1850 and BMT1850 to use + +List all existing files that have been modified, and describe the changes: +M bld/build-namelist + - Remove H2O ext_file from ghg_mam runs + +M bld/namelist_files/namelist_defaults_cam.xml + - Added gw_apply_tndmz defaults for ghg_mam4 93 and 58 level + - Added se_hypervis_subcycle default for ne30np4, npg3, 58 level + +M bld/namelist_files/use_cases/hist_cam_lt.xml +M bld/namelist_files/use_cases/hist_cam_mt.xml + - Removed the above settings and others which are set properly via namelist_defaults + +M cime_config/config_component.xml + - Added hooks for 1850 LT and MT use_cases + +M cime_config/config_compsets.xml + - Added for Testing purposes ONLY - FLT1850_TESTINGONLY_v0c and FMT1850_TESTINGONLY_v0c + + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + FAIL ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 RUN time=266 + - preexisting failure + + FAIL ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 RUN time=357 + - This test passed for Brian Eaton when he made cam6_3_110. We retested and Francis Vitt had it fail for + cam6_3_109. Cheryl Craig tested using cam6_3_110 and cam6_3_108 and it failed in both of these version. + Saying this is a preexisting failure and will be researched later + + FAIL ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev BASELINE + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s BASELINE + - expected baselines differences due to namelist changes + + +izumi/nag/aux_cam: all BFB except: + FAIL DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae RUN time=10 + + +izumi/gnu/aux_cam: all BFB + +ADDITIONAL TESTS RUN: + + Cecile ran FLTHIST and FLT1850 tests with restart and they ran properly (with user_nl_cam, user_nl_clm, CLM SourceMods and + various XML settings): + /glade/scratch/hannay/cases/f.cam6_3_111.FLT1850.001 + /glade/scratch/hannay/cases/f.cam6_3_111.FLTHIST_v0c.001 + + +=============================================================== +=============================================================== + +Tag name: cam6_3_110 +Originator(s): eaton, bstephens +Date: Tue May 9 01:46:34 PM EDT 2023 +One-line Summary: Resolve miscellaneous issues. +Github PR URL: https://github.com/ESCOMP/CAM/pull/797 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +. Issue #371 - Grid matches in refcases will need to change from + gland4 to gris4 if they are re-enabled + (https://github.com/ESCOMP/CAM/issues/371). + - Resolved by removing entries for old refcases. + +. Issue #741 - Updates to address CLUBB variable-name length limit. + (https://github.com/ESCOMP/CAM/issues/741) + - Use cam_history_support::max_fieldname_len to replace hardcoded 16. + - PR #743 will be resolved by this PR. + +. Issue #608 - Fix path for buildlib/buildnml + (https://github.com/ESCOMP/CAM/issues/608) + - Fix one wrong occurance of the old path 'cime/scripts/Tools'. Don't + see any problem with paths for buildlib/buildnml. + +. Issue #749 - Correct description of low-level wind output + (https://github.com/ESCOMP/CAM/issues/749) + - fix description as suggested + +. Issue #803 - Add missing GHGMAM4 to FMTHIST compset + (https://github.com/ESCOMP/CAM/issues/803) + - add missing %GHGMAM4 to FMTHIST compset + - change FLTHIST_v0b to FLTHIST_v0c + - change FMTHIST_v0b to FMTHIST_v0c + +. resolves #371 +. resolves #741 +. resolves #743 +. resolves #608 +. resolves #749 +. resolves #803 + +Describe any changes made to build system: none + +Describe any changes made to the namelist: none + +List any changes to the defaults for the boundary datasets: none + +Describe any substantial timing or memory changes: none + +Code reviewed by: fvitt, cacraigucar, nusbaume + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +bld/namelist_files/namelist_definition.xml +. change type of clubb_vars_* from char*16 to char*35 + +cime_config/config_compsets.xml +. remove commented out lines (575-618) for old refcases +. add missing %GHGMAM4 to FMTHIST compset +. change FLTHIST_v0b to FLTHIST_v0c +. change FMTHIST_v0b to FMTHIST_v0c + +src/physics/cam/cam_diagnostics.F90 +. change descriptions of WSPDSRFMX and WSPDSRFAV from 'at the surface' to + 'at surface layer midpoint' + +src/physics/cam/clubb_intr.F90 +. access max_fieldname_len from cam_history_support +. replace hardcoded 16 by max_fieldname_len in 8 places that set the name + of the variable for an outfld call + +test/system/archive_baseline.sh +. change path of bless_test_results from 'cime/scripts/Tools' to + 'cime/CIME/Tools' + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: + - pre-existing failure + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + +izumi/gnu/aux_cam: All PASS + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: BFB + +=============================================================== +=============================================================== + +Tag name: cam6_3_109 +Originator(s): pel, jet +Date: 28 April 2023 +One-line Summary: Science and infrastructure updates for inline energy/mass budgets +Github PR URL: https://github.com/ESCOMP/CAM/pull/761 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + Add inline energy/mass budgets support. (#519) Science changes are + included that help close the mass and energy budgets of physics + and the SE/MPAS dycores (#521) as well as adding all water + constituents to atmospheric mass (pressure) (#520). + + Extra items also included in this PR: + - Bugfix to correctly open an instance version of atm_in (ndep issue #790) + - Update FLTHIST compset and finish implementing initial FMTHIST compset (#789) + + As of this commit energy/mass budgets have been roughed in for + physics and the SE and MPAS dycores. Similar to amwg_diagnostic + functionality, energy/mass budget diagnostic fields will be added + to a history file via the thermo_budget_histfile_num namelist + parameter. Globally averaged energy budget summaries are also + calculated and written to the atm log file every time the budget + history tape is written to. The period over which energy and mass + budgets are averaged is the same as the averaging period of the + history budget file. Thus history budgets can be output/averaged + at timestep, hour, or month resolutions using the nhtfrq variable + specific to the budget history file identified by + thermo_budget_histfile_num. The new namelist logical variable + thermo_buget_history is used to turn budgeting on (.true.) or off + (.false.) The default is .false. (no budgeting) because of the + global gathers needed to create the budgets. + + An energy or mass budget is defined by a mathematical operation + (sum/difference) of two energy/mass snapshots. For instance one + can talk of the energy lost/gained by the physics + parameterizations by comparing snapshots taken before and after + running the physics. + + An energy budget is created, logged and written to the budget history tape in four steps + 1) call cam_budget_em_snapshot to define multiple energy/mass snapshots + 2) call cam_budget_em_budget to define a budget as the difference/sum of two snapshots. + 3) call tot_energy_phys (or tot_energy_dyn) for each named snapshot + 4) setting namelist variables thermo_budget_history, thermo_budget_histfile_num, nhtfrq + + Energy and mass snapshots are defined and added to the history + buffer via the cam_budget_em_snapshot subroutine. The cam_budget_em_snapshot routine + creates a set of vertically integrated energy and mass history + output fields based on the snapshot name parameter prepended with + the types of energy and mass that are carried in cam and defined + in cam_thermo.F90 For example calling cam_budget_em_snapshot with a name of + 'dAP', perhaps standing for an energy snapshot after physics is + called, will create a set of fields that contain kinetic (KE_dAP), + sensible (SE_dAP), potential (PO_dAP) and total (TE_dap) energies + as well as atmospheric vapor (wv_dAP), liquid (wl_dAP) and ice + (wi_dAP) masses. A call to calc_total_energy for the each named + snapshot (here placed after after the physics parameterization) + will calculate and outfld the 9 or so specific energy and mass + snapshots. + + The cam_budget_em_budget routine defines a named budget composed of the + difference or sum of two snapshots. As with cam_budget_em_shapshot the + budget name is prepended with the same energies identifiers as + cam_budget_em_snapshot. All energy/mass snapshots as well as the budgets are + saved to the history buffer and written to the budget history + file. tot_energy_phys and tot_energy_dyn routines exists for both + physics and dynamics to allow snapshots tailored to thermodynamic + needs and data structures of those packages. + + +Describe any changes made to build system: + +Describe any changes made to the namelist: + New budgeting namelist variables have been added. Interface + follows existing functionality to outfld standard diagnostics for + budgeting and diagnosis. + + se_lcp_moist + se_phys_dyn_cp + - removed + + thermo_budget_histfile_num: integer identifing which history file will contain + additional budgeting diagnostic fields + thermo_budget_history: logical that turns history budgeting on and off. + - added + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: + Global gathers are done each time a thermo budgeting field is + written to the history file. The budgeting diagnostics are not + meant to be enabled during a production run. + +Code reviewed by: cacraigucar nusbaume brian-eaton fvitt pel + +List all files eliminated: N/A + +List all files added and what they do: + A src/cam/control/cam_budget.F90 + provides support for energy/mass budgeting using cam_history infrastructure. + +List all existing files that have been modified, and describe the changes: + + M bld/namelist_files/use_cases/hist_cam_mt.xml + - update FLTHIST for coupled runs + + M bld/build_namelist + - Remove se_lcp_moist and se_phys_dyn_cp namelist flags + + M namelist_defaults_cam.xml + - new mpas initial data default for mpasa120 aquaplanet. + - update cam_dev defaults to add Graupel constituent. + + M namelist_definition.xml + - new averaging flag option for budget variables 'N' allows normalization by nsteps. + - nstep normalization is required to properly budget subcycled fields. + - new namelist parameters for budgeting + + M cam_comp.F90 + - add call to print budgets. The print_budget function needs to be defined for all dycores. + + M cam_history.F90 + - new functionality for history buffered fields + - new area weighted global averaging functionality for history fields. + - create new composed hbuf field which is created from a sum/difference operation on + two existing fields. + - restart information added for budgeting. + + M cam_history_buffers.F90 + - new subroutine for nstep field averaging + + M cam_history_support.F90 + - added support for new global average functionality + + M cime_config/config_compsets.xml + - update FLTHIST for coupled runs + + M runtime_opts.F90 + - added budget namelist read + + M atm_comp_nuopc.F90 + - bug fix, support for E/W formatted initial data longitudes spanning -180:180 + + M cpl/nuopc/atm_stream_ndep.F90 + - bug fix to allow opening instance version of atm_in namelist. + + M eul/dp_coupling.F90 + - update calling parameters + + M eul/dycore_budget.F90 + - Dummy routine for printing EUL budget - not fully supported yet. + + M fv/dp_coupling.F90 + - update calling parameters + + M fv/dycore_budget.F90 + - Dummy routine for printing FV budget - not fully supported yet. + + M fv/metdata.F90 + - thermodynamic activespecies variables + + M fv3/dp_coupling.F90 + - update calling parameters + + M fv3/dycore_budget.F90 + - Dummy routine for printing FV3 budget - not fully supported yet. + + M mpas/dp_coupling.F90 + - science updates + - all water constitutents added to pressure + - mods to further reduce bias in energy budget + + M mpas/dycore_budget.F90 + - Routine for printing MPAS budget + + M mpas/dyn_comp.F90 + - Add core budgets for mpas energy and mass - stages + + M mpas/dyn_grid.F90 + - register area weights for mpas grids + + M se/advect_tend.F90 + - refactor statements checking for use of cslam + + M se/dp_coupling.F90 + - science updates + - all water constitutents added to pressure + - mods to further reduce bias in energy budget + + M se/dycore/control_mod.F90 + - remove phys_dyn_cp energy scaling flag + + M se/dycore/control_mod.F90 + - thermal energy scaling of T + + M se/dycore/dimensions_mod.F90 + - get rid of lcp_moist now namelist variable + + M se/dycore/fvm_mod.F90 + - add use_cslam logical in place of if ntrac>0 + + M se/dycore/global_norms_mod.F90 + - new interface for calculating both elem and fvm global integrals (fvm added) + + M se/dycore/hybrid_mod.F90 + - add use_cslam logical in place of if ntrac>0 + + M se/dycore/namelist_mod.F90 + - add use_cslam logical in place of if ntrac>0 + + M se/dycore/prim_advance_mod.F90 + - science updates to close energy budget + - refactor energy calc routine. + - new hydrostatic energy routine with potential energy now split out from SE + + M se/dycore/prim_advection_mod.F90 + - refactor for enthalpy ... internal energy to enthalpy + + M se/dycore/prim_driver_mod.F90 + - rename routine to calculate total energy + + M se/dycore/prim_state_mod.F90 + - add use_cslam logical in place of if ntrac>0 + + M se/dycore/viscosity.F90 + - add use_cslam logical in place of if ntrac>0 + + M se/dycore_budget.F90 + - Routine for printing SE energy/mass budgets + + M se/dyn_comp.F90 + - Add core budget variables for se energy and mass - stages + + M se/dyn_grid.F90 + - register area weights for se grids + - call budget_add for all SE energy/mass budget fields. + + M se/dyn_grid.F90 + - consistent naming of routine that calculates total energy + + M se/restart_dynamics.F90 + - add use_cslam logical in place of if ntrac>0 + + M se/stepon.F90 + - update name calc_tot_energy_dynamics to tot_energy_dyn + + M se/test_fvm_mapping.F90 + - add use_cslam logical in place of if ntrac>0 + + M infrastructure/phys_grid.F90 + - register area weights for physic grid + - call budget_add for all SE energy/mass budget fields. + + M cam_diagnostics.F90 + - register physics energy/mass budgets using budget_add calls + - physics energy/mass variables (physics budget stages) + + M check_energy.F90 + - update calls to get hydrostatic energy (include new potential energy input param) + - update calc energy/mass routine for potential energy calculation. + + M constituents.F90 + - clean up unused variables (NAG) + + M geopotential.F90 + - remove unused routines/variables (NAG) + - add computation of generalized virtual temp to geopotential_t + + M phys_control.F90 + - code cleanup + + M cam/phys_grid.F90 + - register area weights for global integrals + + M physics_types.F90 + - science updates for energy/mass budgets + + M cam/physpkg.F90 + - science updates for energy/mass budgets + - science updates for energy/mass budgets + + M cam_dev/physpkg.F90 + - science updates for energy/mass budgets + + M simple/physpkg.F90 + - science updates for energy/mass budgets (update dme_adjust) + + M utils/air_composition.F90 + - refactor/cleanup/rename + + M utils/grid_support.F90 + - support for global area weighting for budgets + + M utils/cam_thermo.F90 + - energy and mass budget variables and descriptions. + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: Expecting namelist and baseline failures (SE,MPAS,FV3 climate changing, others roundoff) + + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) + - pre-existing failure + + ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPMOZ.cheyenne_intel.cam-outfrq3s (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPX2000.cheyenne_intel.cam-outfrq3s (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.FADIAB.cheyenne_intel.cam-terminator (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase (Overall: DIFF) + ERI_D_Ln18_Vnuopc.f45_f45_mg37.QPC41850.cheyenne_intel.cam-co2rmp_usecase (Overall: DIFF) + ERP_D_Ln9_Vmct.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_D_Ln9_Vmct.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_Ld3_Vnuopc.f09_f09_mg17.FWHIST.cheyenne_intel.cam-reduced_hist1d (Overall: DIFF) + ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes (Overall: DIFF) + ERP_Ln9_Vmct.f09_f09_mg17.2000_CAM60_CLM50%SP_CICE5%PRES_DOCN%DOM_MOSART_SGLC_SWAV.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) + ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) + ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev (Overall: DIFF) + ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 (Overall: DIFF) + ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 (Overall: DIFF) + ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERS_Ln9_Vnuopc.f19_f19_mg17.FSPCAMS.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + ERS_Ln9_Vnuopc.ne0TESTONLYne5x4_ne0TESTONLYne5x4_mg37.FADIAB.cheyenne_intel.cam-outfrq3s_refined (Overall: DIFF) + SMS_D_Ld2_Vnuopc.f19_f19_mg17.QPC5HIST.cheyenne_intel.cam-volc_usecase (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCts2nudged.cheyenne_intel.cam-outfrq9s_leapday (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCvbsxHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC2000climo.cheyenne_intel.cam-outfrq3s_usecase (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC5M7.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) + SMS_Ld1_Vnuopc.f09_f09_mg17.FW2000climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) + SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d (Overall: DIFF) + SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) + SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m (Overall: DIFF) + SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging (Overall: DIFF) + SMS_Ln9_Vnuopc.f09_f09_mg17.FW1850.cheyenne_intel.cam-reduced_hist3s (Overall: DIFF) + SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs (Overall: DIFF) + SMS_Ln9_Vnuopc.f19_f19_mg17.FHIST.cheyenne_intel.cam-outfrq9s_nochem (Overall: DIFF) + - expecting climate changing differences in SE,MPAS,FV3 + - verified FV,EUL differences are roundoff + + FAIL ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.FADIAB.cheyenne_intel.cam-terminator NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase NLCOMP + FAIL ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 NLCOMP + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 NLCOMP + FAIL ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 NLCOMP + FAIL ERS_Ln9_Vnuopc.ne0TESTONLYne5x4_ne0TESTONLYne5x4_mg37.FADIAB.cheyenne_intel.cam-outfrq3s_refined NLCOMP + FAIL SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d NLCOMP + FAIL SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d NLCOMP + - expected NLCOMP failures due to removal of se_lcp_moist, se_phys_dyn_cp namelist variables for SE runs + - expected NLCOMP failures from addition of GRAUPEL to water species for cam_dev and FV3 runs + +izumi/nag/aux_cam: Expecting namelist and baseline failures + + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) + - pre-existing failure + + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s (Overall: DIFF) + ERC_D_Ln9_Vnuopc.mpasa480z32_mpasa480.FHS94.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac (Overall: DIFF) + ERI_D_Ln18_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: DIFF) + ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: DIFF) + ERI_D_Ln18_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: DIFF) + ERI_D_Ln18_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: DIFF) + ERP_Ln9_Vmct.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) + ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) + ERS_Ln27_Vnuopc.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s (Overall: DIFF) + ERS_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s (Overall: DIFF) + PEM_D_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: DIFF) + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) + SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s (Overall: DIFF) + SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: DIFF) + SMS_D_Ln9_P1x1_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba (Overall: DIFF) + SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: DIFF) + SUB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s (Overall: DIFF) + TMC_D_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: DIFF) + - expecting climate changing differences in SE,MPAS,FV3 + - verified FV,EUL differences are roundoff + + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac NLCOMP + FAIL ERI_D_Ln18_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic NLCOMP + FAIL ERI_D_Ln18_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic NLCOMP + FAIL ERP_Ln9_Vmct.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf NLCOMP + FAIL ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf NLCOMP + FAIL ERS_Ln27_Vnuopc.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s NLCOMP + FAIL ERS_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s NLCOMP + FAIL PEM_D_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 NLCOMP + FAIL SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s NLCOMP + FAIL SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem NLCOMP + FAIL SMS_D_Ln9_P1x1_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s NLCOMP + - expected NLCOMP failures due to removal of se_lcp_moist, se_phys_dyn_cp namelist variables for SE runs + +izumi/gnu/aux_cam: Expecting namelist and baseline failures + ERC_D_Ln9_Vnuopc.f10_f10_mg37.FADIAB.izumi_gnu.cam-terminator (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag (Overall: DIFF) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: DIFF) + ERC_D_Ln9_Vnuopc.ne5pg4_ne5pg4_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: DIFF) + ERP_Ln9_Vnuopc.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s (Overall: DIFF) + ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s (Overall: DIFF) + PEM_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: DIFF) + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 (Overall: DIFF) + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 (Overall: DIFF) + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 (Overall: DIFF) + SMS_D_Ln3_Vnuopc.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc (Overall: DIFF) + SMS_D_Ln9.f10_f10_mg37.2000_CAM%DEV%GHGMAM4_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV_SESP.izumi_gnu.cam-outfrq9s (Overall: DIFF) + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee (Overall: DIFF) + SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac (Overall: DIFF) + - expecting climate changing differences in SE,MPAS,FV3 + - verified FV,EUL differences are roundoff + + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne5pg4_ne5pg4_mg37.FADIAB.izumi_gnu.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC3.izumi_gnu.cam-outfrq3s_usecase NLCOMP + FAIL ERP_Ln9_Vnuopc.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s NLCOMP + FAIL PEM_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 NLCOMP + FAIL SMS_D_Ln9.f10_f10_mg37.2000_CAM%DEV%GHGMAM4_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV_SESP.izumi_gnu.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac NLCOMP + - expected NLCOMP failures due to removal of se_lcp_moist, se_phys_dyn_cp namelist variables for SE runs + - expected NLCOMP failures from addition of GRAUPEL to water species for cam_dev and FV3 runs + - expected NLCOMP failures due to change in format of water_species_in_air for EUL runs + +Summarize any changes to answers: climate changing for SE,MPAS due to science updates + climate changing for FV3 due to addition of GRAUPEL + roundoff for FV and EUL + +=============================================================== +=============================================================== + +Tag name: cam6_3_108 +Originator(s): fvitt +Date: 27 Apr 2023 +One-line Summary: Ocean emissions bug fix; enable passing lightning flash rates to surface models +Github PR URLs: + + https://github.com/ESCOMP/CAM/pull/795 + https://github.com/ESCOMP/CAM/pull/747 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + Fix issue with ocean emissions in B compsets where SSTs are zero over land. #794 + In configurations where SSTs are zeros over land (B compsets) divide by zero + errors have occurred. The where block used to mask the calculations of fluxes + was not preforming as intended to avoid the divide by zero errors. The where + block is replaced with a loop over columns and explicitly check columns for + ocean fraction. The flux calculations are preformed only in columns not over + land. + + Enable passing cloud-to-ground lightning flash rates to surface models. #567 + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: + + atm_provides_lightning indicator added to drv_flds_in: + If TRUE atmosphere model will provide prognosed lightning flash frequency. + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: cacraigucar nusbaume jedwards4b jtruesdal brian-eaton + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: + +M Externals.cfg + - update CMEPS for lightning flash freqencies field + +M bld/build-namelist + - added namelist switch in drv_flds_in for lightning flashes + - set lght_no_prd_factor if chemistry includes NO + +M bld/namelist_files/namelist_definition.xml + - atm_provides lightning switch + +M src/chemistry/mozart/mo_chemini.F90 +M src/chemistry/mozart/chemistry.F90 + - moved reading lightning namelist options to more general location runtime_opts.F90 + +M src/chemistry/mozart/mo_lightning.F90 + - add namelist reader + - provide cloud-to-ground flash rates + - enable use in configurations without chemistry + - calculate NOx production rates only if needed by chemistry + +M src/chemistry/mozart/ocean_emis.F90 + - preform calculations on single columns + - replace where block with loop over columns -- calc fluxes only in columns over ocean + +M src/control/runtime_opts.F90 + - invoke lightning namelist reader + +M src/control/camsrfexch.F90 +M src/cpl/nuopc/atm_import_export.F90 + - add field for export of lightning flash rates + +M src/physics/cam/physpkg.F90 +M src/physics/cam_dev/physpkg.F90 + - call lightning register and init routines + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: all bit-for-bit + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: + - pre-existing failure + + ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPMOZ.cheyenne_intel.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPX2000.cheyenne_intel.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.FADIAB.cheyenne_intel.cam-terminator (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T42_T42_mg17.FDABIP04.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T42_T42_mg17.FHS94.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.f45_f45_mg37.QPC41850.cheyenne_intel.cam-co2rmp_usecase (Overall: NLFAIL) details: + ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes (Overall: NLFAIL) details: + ERS_Ln9_Vnuopc.ne0TESTONLYne5x4_ne0TESTONLYne5x4_mg37.FADIAB.cheyenne_intel.cam-outfrq3s_refined (Overall: NLFAIL) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC5.cheyenne_intel.cam-scm_prep (Overall: NLFAIL) details: + SMS_D_Ld2_Vnuopc.f19_f19_mg17.QPC5HIST.cheyenne_intel.cam-volc_usecase (Overall: NLFAIL) details: + SMS_D_Ld5_Vnuopc.f19_f19_mg17.PC4.cheyenne_intel.cam-cam4_port5d (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC2000climo.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC5M7.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + SMS_Ld5_Vnuopc.f09_f09_mg17.PC6.cheyenne_intel.cam-cam6_port_f09 (Overall: NLFAIL) details: + - NLCOMP failures are due to new lightning_coupling_nl namelist group in drv_flds_in + + ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ld3_Vnuopc.f09_f09_mg17.FWHIST.cheyenne_intel.cam-reduced_hist1d (Overall: DIFF) details: + ERP_Lh12_Vnuopc.f19_f19_mg17.FW4madSD.cheyenne_intel.cam-outfrq3h (Overall: DIFF) details: + ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev (Overall: DIFF) details: + ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 (Overall: DIFF) details: + ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f19_f19_mg17.FSPCAMS.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCts2nudged.cheyenne_intel.cam-outfrq9s_leapday (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCvbsxHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.T42_T42.FSCAM.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.FW1850.cheyenne_intel.cam-reduced_hist3s (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f19_f19_mg17.FHIST.cheyenne_intel.cam-outfrq9s_nochem (Overall: DIFF) details: + - differences are due to new atmImp_Sa_lightning coupler field -- otherwise all bit-for-bit + - NLCOMP failures are due to new lightning_coupling_nl namelist group in drv_flds_in + +izumi/nag/aux_cam: all bit-for-bit + + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.mpasa480z32_mpasa480.FHS94.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: + ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: NLFAIL) details: + ERS_Ln27_Vnuopc.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: + ERS_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: + PEM_D_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: NLFAIL) details: + SMS_D_Ld2_Vnuopc.f45_f45_mg37.PC5.izumi_nag.cam-outfrq24h_port (Overall: NLFAIL) details: + SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: NLFAIL) details: + SMS_D_Ln7_Vnuopc.T42_T42_mg17.QPSCAMC5.izumi_nag.cam-scmarm (Overall: NLFAIL) details: + SMS_D_Ln9_P1x1_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba (Overall: NLFAIL) details: + SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: NLFAIL) details: + SUB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + TMC_D_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: NLFAIL) details: + TMC_D_Vnuopc.T5_T5_mg37.QPC5.izumi_nag.cam-ghgrmp_e8 (Overall: NLFAIL) details: + - NLCOMP failures are due to new lightning_coupling_nl namelist group in drv_flds_in + +izumi/gnu/aux_cam: all bit-for-bit + + SMS_P48x1_D_Ln9_Vnuopc.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9.f10_f10_mg37.2000_CAM%DEV%GHGMAM4_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV_SESP.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + - differences are due to new atmImp_Sa_lightning coupler field -- otherwise all bit-for-bit + - NLCOMP failures are due to new lightning_coupling_nl namelist group in drv_flds_in + + ERC_D_Ln9_Vnuopc.f10_f10_mg37.FADIAB.izumi_gnu.cam-terminator (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5pg4_ne5pg4_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC3.izumi_gnu.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.T5_T5_mg37.QPC4.izumi_gnu.cam-co2rmp (Overall: NLFAIL) details: + ERP_Ln9_Vnuopc.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: + ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: + PEM_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 (Overall: NLFAIL) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC4.izumi_gnu.cam-scm_prep (Overall: NLFAIL) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: NLFAIL) details: + SMS_D_Ln3_Vnuopc.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac (Overall: NLFAIL) details: + - NLCOMP failures are due to new lightning_coupling_nl namelist group in drv_flds_in + +Summarize any changes to answers: bit-for-bit unchanged + +=============================================================== +=============================================================== + +Tag name: cam6_3_107 +Originator(s): eaton +Date: Tue Apr 18 10:27:45 AM EDT 2023 +One-line Summary: Reimplement zonal_mean_mod::Invert_Matrix using LAPACK DGESV +Github PR URL: https://github.com/ESCOMP/CAM/pull/788 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +The Invert_Matrix subroutine in module zonal_mean_mod has been +reimplemented using the LAPACK subroutine DGESV. + +Resolves: +. Replace "Invert_Matrix" subroutine in "zonal_mean_mod.F90" with LAPACK version #736 + (https://github.com/ESCOMP/CAM/issues/736) +. Bug in zonal mean "Invert_Matrix" subroutine #745 + (https://github.com/ESCOMP/CAM/issues/745) + +Describe any changes made to build system: none + +Describe any changes made to the namelist: none + +List any changes to the defaults for the boundary datasets: none + +Describe any substantial timing or memory changes: not tested + +Code reviewed by: fvitt, cacraigucar, peverwhee, patcal + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +src/utils/zonal_mean_mod.F90 +. modify subroutine Invert_Matrix to use LAPACK DGESV routine. + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: + - pre-existing failure + + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev (Overall: DIFF) details: + - the zonal mean (*zm) fields in the h1 file have 2-3 significant digits of agreement + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + + SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: DIFF) details: + - the zonal mean (*zm) fields in the h2 file have 2-3 significant digits of agreement + +izumi/gnu/aux_cam: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 (Overall: DIFF) details: + - diffs in all fields in h0 and h1 files. This is expected because the + the nudging uses the zonal_mean_mod code if Nudge_ZonalFilter is true, + which it is in this test. + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: + +. The only changes to answers are for runs using nudging with + Nudge_ZonalFilter set to true. + +. The zonal mean diagnostic output only agrees with previous output to a + couple of significant figures. That's because previous output was + produced with a bug in the Invert_Matrix subroutine (issue #745). + Independent testing showed that fixing that bug and comparing with the + new version of Invert_Matrix yields roundoff level differences (15-16 + significant digits of agreement). + +=============================================================== +=============================================================== + +Tag name: cam6_3_106 +Originator(s): cacraig, fvitt, eaton +Date: Thu Apr 6 07:10:24 PM EDT 2023 +One-line Summary: Initialize CO2 when it's missing from initial file. +Github PR URL: https://github.com/ESCOMP/CAM/pull/780 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +Fixes: When CO2 is not in IC file, needs to initialize to a non-zero value #779 + https://github.com/ESCOMP/CAM/issues/779 + +Describe any changes made to build system: none + +Describe any changes made to the namelist: none + +List any changes to the defaults for the boundary datasets: none + +Describe any substantial timing or memory changes: none + +Code reviewed by: brian-eaton, fvitt, nusbaume + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +src/chemistry/mozart/chemisty.F90 +. For ghg_chem, add CO2 to the case statement to use chem_surfvals_get + for initialization. + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: + - pre-existing failure + + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev (Overall: DIFF) details: + - expected diff due to change in CO2 initialization + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + +izumi/gnu/aux_cam: + SMS_D_Ln9.f10_f10_mg37.2000_CAM%DEV%GHGMAM4_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV_SESP.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + - expected diff due to change in CO2 initialization + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: BFB except for any run using ghg_mam4 + chemistry and using an initial file that doesn't contain CO2. In that + case the CO2 is now being initialized by chem_surf_vals. Previously it was + zero above the surface layer which is set by the LBC code. + +=============================================================== +=============================================================== + +Tag name: cam6_3_105 +Originator(s): bstephens, eaton +Date: Thu Apr 6 09:51:59 AM EDT 2023 +One-line Summary: fix for COSP with cam_dev physics +Github PR URL: https://github.com/ESCOMP/CAM/pull/777 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +Fixes: Add PBUF fields to make cosp compatible with cam_dev #776 + https://github.com/ESCOMP/CAM/issues/776 + Note: the original fix was reimplemented to just check whether or + not fields used by the cosp simulator are present in the pbuf, and + if not then to use local arrays of zeros. + +Describe any changes made to build system: none + +Describe any changes made to the namelist: none + +List any changes to the defaults for the boundary datasets: none + +Describe any substantial timing or memory changes: none + +Code reviewed by: brian-eaton, cacraigucar, adamrher + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +src/physics/cam/cospsimulator_intr.F90 +. remove pbuf_get_index calls for SH_CLDLIQ, SH_CLDICE. The indices were + not being used. +. add optional arg to pbuf_get_index calls for SH_FLXPRC, SH_FLXSNW to + avoid endrun calls if fields not present in the pbuf. In that case + negative value indices are returned and appropriate action can be taken. + In this case the fields are assigned values of zero. + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: +ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: +. expected failure + +izumi/nag/aux_cam: +DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: +. expected failure + +izumi/gnu/aux_cam: All PASS. + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: BFB + +=============================================================== +=============================================================== + +Tag name: cam6_3_104 +Originator(s): fvitt +Date: 5 Apr 2023 +One-line Summary: Misc bug fixes +Github PR URL: https://github.com/ESCOMP/CAM/pull/785 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + Fix issues: + - ghg_mam4 is not working with cam_dev regression tests #773 + - undefined rho values in nucleate_ice_cam_calc #781 + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: brian-eaton cacraigucar nusbaume + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: + +M bld/namelist_files/use_cases/2000_cam6.xml + - use appropriate prescribed tracer inputs for trop_mam4 and ghg_mam4 chemistry + -- ghg_mam4 needs HALONS + +M cime_config/testdefs/testlist_cam.xml + - add regression test for GHG chem with cam_dev phys and year 2000 use case + +M src/chemistry/mozart/tracer_cnst.F90 + - add error checking + +M src/physics/cam/nucleate_ice_cam.F90 + - define rho for all model layers + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: + - pre-existing failure + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + +izumi/gnu/aux_cam: + SMS_D_Ln9.f10_f10_mg37.2000_CAM%DEV%GHGMAM4_CLM50%SP_CICE%PRES_DOCN%DOM_MOSART_SGLC_SWAV_SESP.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + - new test + +Summarize any changes to answers: bit-for-bit unchanged + +=============================================================== +=============================================================== + +Tag name: cam6_3_103 +Originator(s): cacraig +Date: Apr 5, 2023 +One-line Summary: Update externals to almost match cesm2_3_alpha12d +Github PR URL: https://github.com/ESCOMP/CAM/pull/783 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + - CLM tag is one newer than was used in alpha12d as it contains some of the coarse grid modifications + - FMS is an older version (inherited from cam6_3_102) + - cpl7 is one tag newer (inherited from cam6_3_102) + - Multi-instance is broken with current CMEPS external: https://github.com/ESCOMP/CAM/issues/733 + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: nusbaume, eaton + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: +M Externals.cfg + - Externals updated as described above + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: + - pre-existing failure + + ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPMOZ.cheyenne_intel.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPX2000.cheyenne_intel.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.FADIAB.cheyenne_intel.cam-terminator (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T42_T42_mg17.FDABIP04.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T42_T42_mg17.FHS94.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.f45_f45_mg37.QPC41850.cheyenne_intel.cam-co2rmp_usecase (Overall: NLFAIL) details: + ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + ERP_Lh12_Vnuopc.f19_f19_mg17.FW4madSD.cheyenne_intel.cam-outfrq3h (Overall: NLFAIL) details: + ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes (Overall: NLFAIL) details: + ERS_Ln9_Vnuopc.f19_f19_mg17.FSPCAMS.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + ERS_Ln9_Vnuopc.ne0TESTONLYne5x4_ne0TESTONLYne5x4_mg37.FADIAB.cheyenne_intel.cam-outfrq3s_refined (Overall: NLFAIL) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC5.cheyenne_intel.cam-scm_prep (Overall: NLFAIL) details: + SMS_D_Ld2_Vnuopc.f19_f19_mg17.QPC5HIST.cheyenne_intel.cam-volc_usecase (Overall: NLFAIL) details: + SMS_D_Ld5_Vnuopc.f19_f19_mg17.PC4.cheyenne_intel.cam-cam4_port5d (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC2000climo.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC5M7.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.T42_T42.FSCAM.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + SMS_Ld5_Vnuopc.f09_f09_mg17.PC6.cheyenne_intel.cam-cam6_port_f09 (Overall: NLFAIL) details: + - namelist differences due to 'import_data_fields' added to docn_in and nuopc.runseq run seqeunce modified + + ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + - concluded this answer change was most likely due to the change in value of the run sequence in nuopc.runseq having + phases_aofluxes_run being run before the ocn elements + + ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ld3_Vnuopc.f09_f09_mg17.FWHIST.cheyenne_intel.cam-reduced_hist1d (Overall: DIFF) details: + ERP_Ln9_Vmct.f09_f09_mg17.2000_CAM60_CLM50%SP_CICE5%PRES_DOCN%DOM_MOSART_SGLC_SWAV.cheyenne_intel.cam-outfrq9s (Overall: DIFF) +details: + ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev (Overall: DIFF) details: + ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 (Overall: DIFF) details: + ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCts2nudged.cheyenne_intel.cam-outfrq9s_leapday (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCvbsxHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_Ld1_Vnuopc.f09_f09_mg17.FW2000climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.FW1850.cheyenne_intel.cam-reduced_hist3s (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f19_f19_mg17.FHIST.cheyenne_intel.cam-outfrq9s_nochem (Overall: DIFF) details: + - CTSM has answer changes which expect to change F compsets + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + + ERP_Vnuopc_Ln9.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) details: + - baseline failure due to new test accidentally introduced in CMEPS + + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.mpasa480z32_mpasa480.FHS94.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: + ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: NLFAIL) details: + ERS_Ln27_Vnuopc.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: + ERS_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: + PEM_D_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: NLFAIL) details: + SMS_D_Ld2_Vnuopc.f45_f45_mg37.PC5.izumi_nag.cam-outfrq24h_port (Overall: NLFAIL) details: + SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: NLFAIL) details: + SMS_D_Ln7_Vnuopc.T42_T42_mg17.QPSCAMC5.izumi_nag.cam-scmarm (Overall: NLFAIL) details: + SMS_D_Ln9_P1x1_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba (Overall: NLFAIL) details: + SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: NLFAIL) details: + SUB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + TMC_D_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: NLFAIL) details: + TMC_D_Vnuopc.T5_T5_mg37.QPC5.izumi_nag.cam-ghgrmp_e8 (Overall: NLFAIL) details: + +izumi/gnu/aux_cam: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.FADIAB.izumi_gnu.cam-terminator (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.ne5pg4_ne5pg4_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC3.izumi_gnu.cam-outfrq3s_usecase (Overall: NLFAIL) details: + ERI_D_Ln18_Vnuopc.T5_T5_mg37.QPC4.izumi_gnu.cam-co2rmp (Overall: NLFAIL) details: + ERP_Ln9_Vnuopc.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: + ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: + PEM_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 (Overall: NLFAIL) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 (Overall: NLFAIL) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC4.izumi_gnu.cam-scm_prep (Overall: NLFAIL) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: NLFAIL) details: + SMS_D_Ln3_Vnuopc.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac (Overall: NLFAIL) details: + SMS_P48x1_D_Ln9_Vnuopc.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: + - namelist differences due to 'import_data_fields' added to docn_in and nuopc.runseq run seqeunce modified + +=============================================================== +=============================================================== + +Tag name: cam6_3_102 +Originator(s): fvitt +Date: 4 Apr 2023 +One-line Summary: Updates to TEM diagnostics +Github PR URL: https://github.com/ESCOMP/CAM/pull/770 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + - fix issue with TEM diagnostics not implemented in cam_dev physics #769 + - adopt the zm naming convention for the zonal mean outputs + - add 'Uzm','Vzm','Wzm','THzm' output fields + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: brian-eaton cacraigucar nusbaume + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: +M cime_config/testdefs/testmods_dirs/cam/outfrq1d_14dec_ghg_cam_dev/user_nl_cam + - include namelist options to test TEM output + +M cime_config/testdefs/testmods_dirs/cam/outfrq1d_physgrid_tem_mpasa120_wcmsc/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/outfrq3s_physgrid_tem/user_nl_cam +M cime_config/testdefs/testmods_dirs/cam/outfrq9s_physgrid_tem_1deg/user_nl_cam + - use zm history field names for the TEM output + +M src/physics/cam/phys_grid_ctem.F90 + - adopts the zm naming convention for the zonal mean outputs + - add 'Uzm','Vzm','Wzm','THzm' output fields + +M src/physics/cam_dev/physpkg.F90 + - add calls to the phys_grid_ctem interface + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: FAIL) details: + - pre-existing failure + + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev (Overall: DIFF) details: + FAIL ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev NLCOMP + FAIL ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_101: ERROR BFAIL some baseline files were missing + - expected failure -- TEM output added to this test + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + + SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: DIFF) details: + FAIL SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem NLCOMP + FAIL SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_101_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + - change in TEM output field names + +izumi/gnu/aux_cam: All PASS + +Summarize any changes to answers: bit-for-bit unchanged + +=============================================================== +=============================================================== + +Tag name: cam6_3_101 +Originator(s): cacraig, eaton, hannay, Thomas Toniazzo, Vince Larson +Date: March 31, 2023 +One-line Summary: Create FLTHIST_v0a compset +Github PR URL: Create initial FLTHIST and FMTHIST compsets for CAM7: https://github.com/ESCOMP/CAM/pull/767 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + - Create testing compsets based on FLT,FMT,FW and FX: https://github.com/ESCOMP/CAM/issues/765 + - Partially implements these compsets: FLTHIST_v0a has been worked on with Cecile + FMTHIST_v0a has been started, but is not complete + Other compsets have not been worked on + - Update CLUBB external (fix bug found by Thomas Toniazzo): https://github.com/ESCOMP/CAM/issues/768 + +Describe any changes made to build system: + - Introduce %LT (low_top) %MT (mid_top) and %GHGMAM4 (turn on ghg_mam4 chemistry) + - Remove %L58 and %L93 settings and replace with %LT and %MT + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: eaton, nusbaume, fvitt + +List all files eliminated: N/A + +List all files added and what they do: +A bld/namelist_files/use_cases/hist_cam_lt.xml + - use_case for FLTHIST_v0a - developed in consultation with Cecile + +A bld/namelist_files/use_cases/hist_cam_mt.xml + - template use_case for FMTHIST_v0a - not completed + +List all existing files that have been modified, and describe the changes: +M Externals_CAM.cfg + - Bring in CLUBB bug fix tag which fixes small bug in mono_flux_limiter.F90 + +M bld/namelist_files/namelist_defaults_cam.xml + - Add initial condition files for ne30np4, npg=3 for 58 and 93 levels + - Add topo file for ne30np4, npg=3 + +M cime_config/config_component.xml + - Remove %L58 and %L93 + - Introduce %LT, %MT and %GHGMAM4 options + +M cime_config/config_compsets.xml + - Introduce FLTHIST_v0a compset (note that a regression test was not introduced for it yet) + - Create FMTHIST_v0a compset (not completed) + - replace %L58 and %L93 with %LT and %MT + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: all BFB except: + FAIL ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 NLCOMP + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d NLCOMP + - topo file change + + FAIL ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s BASELINE + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s BASELINE + FAIL SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d BASELINE + - expected baseline changes due to new topo file + + FAIL ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 RUN time=119 + - New failing test - issue https://github.com/ESCOMP/CAM/issues/772 opened + +izumi/nag/aux_cam: all BFB except: + FAIL DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae RUN time=180 + - pre-existing failure + +izumi/gnu/aux_cam: all BFB + +=============================================================== +=============================================================== + +Tag name: cam6_3_100 +Originator(s): fvitt +Date: 20 Mar 2023 +One-line Summary: Introduce prognostic GHG chemistry mechanism for CAM7 +Github PR URL: https://github.com/ESCOMP/CAM/pull/766 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + New chemistry mechanism for CAM7 prognostic GHGs #762 + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: brian-eaton jtruesdal cacraigucar nusbaume + +List all files eliminated: N/A + +List all files added and what they do: +A src/chemistry/pp_ghg_mam4/chem_mech.doc +A src/chemistry/pp_ghg_mam4/chem_mech.in +A src/chemistry/pp_ghg_mam4/chem_mods.F90 +A src/chemistry/pp_ghg_mam4/m_rxt_id.F90 +A src/chemistry/pp_ghg_mam4/m_spc_id.F90 +A src/chemistry/pp_ghg_mam4/mo_adjrxt.F90 +A src/chemistry/pp_ghg_mam4/mo_exp_sol.F90 +A src/chemistry/pp_ghg_mam4/mo_imp_sol.F90 +A src/chemistry/pp_ghg_mam4/mo_indprd.F90 +A src/chemistry/pp_ghg_mam4/mo_lin_matrix.F90 +A src/chemistry/pp_ghg_mam4/mo_lu_factor.F90 +A src/chemistry/pp_ghg_mam4/mo_lu_solve.F90 +A src/chemistry/pp_ghg_mam4/mo_nln_matrix.F90 +A src/chemistry/pp_ghg_mam4/mo_phtadj.F90 +A src/chemistry/pp_ghg_mam4/mo_prod_loss.F90 +A src/chemistry/pp_ghg_mam4/mo_rxt_rates_conv.F90 +A src/chemistry/pp_ghg_mam4/mo_setrxt.F90 +A src/chemistry/pp_ghg_mam4/mo_sim_dat.F90 + - add ghg_mam4 chemistry mechanism + +List all existing files that have been modified, and describe the changes: +M bld/namelist_files/namelist_definition.xml +M bld/config_files/definition.xml +M bld/configure + - add ghg_mam4 chem option + +M bld/build-namelist +M bld/namelist_files/namelist_defaults_cam.xml + - default namelist settings for ghg_mam4 chemistry + +M cime_config/testdefs/testlist_cam.xml + - add test for ghg_mam4 + - replace outfrq1d_14dec_L32wsc with outfrq1d_14dec_ghg_cam_dev + -- replaces "-chem waccm_sc_mam4" with "-chem ghg_mam4" + -- this is more relevant for CAM7 development + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_ghg_cam_dev (Overall: DIFF) details: + - new test which replaces outfrq1d_14dec_L32wsc + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + +izumi/gnu/aux_cam: All PASS + +Summarize any changes to answers: bit-for-bit unchanged + +=============================================================== +=============================================================== + +Tag name: cam6_3_099 +Originator(s): adamrher, eaton +Date: Thu Mar 16 11:22:00 AM EDT 2023 +One-line Summary: fix drydep emissions for cam_dev physics +Github PR URL: https://github.com/ESCOMP/CAM/pull/763 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +. Fixes #759 (https://github.com/ESCOMP/CAM/issues/759) + drydep of gas phase species "skipped" in cam_dev + +Describe any changes made to build system: none + +Describe any changes made to the namelist: none + +List any changes to the defaults for the boundary datasets: none + +Describe any substantial timing or memory changes: none + +Code reviewed by: jtruesdal, cacraigucar, fvitt, nusbaume + +List all files eliminated: none + +List all files added and what they do: none + +List all existing files that have been modified, and describe the changes: + +src/chemistry/mozart/chemistry.F90 +. add state%rpdel, state%rpdeldry to actual args in call to + gas_phase_chemdr + +src/chemistry/mozart/mo_gas_phase_chemdr.F90 +. add rpdel, rpdeldry to dummy args for gas_phase_chemdr +. access cam_physpkg_is from phys_control module +. access gravit from physconst +. access cnst_type from constituents +. if cam_dev physics then apply drydep fluxes directly to the species + tendency array, else apply to the emissions array. + + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_L32wsc (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + + - There are baseline diffs in all tests that use cam_dev physics. + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + + - pre-existing failure + +izumi/gnu/aux_cam: + + - All PASS + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: BFB except for cam_dev physics due to + fix in treatment of drydep fluxes. + +=============================================================== +=============================================================== + +Tag name: cam6_3_098 +Originator(s): mvertens, eaton +Date: Tue Mar 14 09:16:31 MDT 2023 +One-line Summary: always pass NDEP from CAM and remove sst specs +Github PR URL: https://github.com/ESCOMP/CAM/pull/764 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + +. Resolve issue #104 - https://github.com/ESCOMP/CAM/issues/104 + Always send Nitrogen-deposition to surface components. + + This PR enables CAM to read in ndep (using the CDEPS inline API) from + forcing files if it is not computing NDEP prognostically. As a result + CAM will ALWAYS send NDEP to the mediator. + + Right how, CLM is not using the passed NDEP from the streams - since it + is still reading the drv_flds_in for NDEP. + + It is now possible for the drv_flds_in entry for ndep to be removed + and CLM can always accept NDEP from either CAM or DATM. + + New XML variables are introduced to specify the stream forcing. This is + being done in CTSM as well for all of its CDEPS stream specific variables. + + NOTE: that CTSM also needs a new PR in order to accept these new fields + from CAM rather than use its own internal streams. + +. Remove old sst specs from the namelist. This is a cleanup. + +Describe any changes made to build system: none + +Describe any changes made to the namelist: +. The follow variables are in new group ndep_stream_nl which is read in + src/cpl/nuopc/atm_stream_ndep.F90 + stream_ndep_year_first + stream_ndep_year_last + stream_ndep_year_align + stream_ndep_data_filename + stream_ndep_mesh_filename + +List any changes to the defaults for the boundary datasets: +. NDEP datasets are added by cime_config/config_component.xml + +Describe any substantial timing or memory changes: not tested + +Code reviewed by: gold2718, fvitt, cacraigucar, nusbaume, brian-eaton + +List all files eliminated: none + +List all files added and what they do: + +src/cpl/nuopc/atm_stream_ndep.F90 +. Contains methods for reading in nitrogen deposition data file. Also + includes functions for dynamic ndep file handling and interpolation. +. Reads namelist group ndep_stream_nl from the atm_in file. + +List all existing files that have been modified, and describe the changes: +bld/configure +. remove documentation for -ocn option. + +bld/namelist_files/namelist_defaults_cam.xml +. remove old settings for bndtvs, bndtvs_domain, and focndomain. DOM and + DOCN are no longer used. + +bld/namelist_files/namelist_definition.xml +. 5 new variables, stream_ndep_*, are added to group ndep_stream_nl +. bndtvs, focndomain, and bndtvs_domain removed +. 5 new variables, *_ndep, added to group ndep_stream_nml + +bld/namelist_files/use_cases/1850-2005_cam5.xml +bld/namelist_files/use_cases/sd_waccm_sulfur.xml +bld/namelist_files/use_cases/waccm_carma_bc_2013_cam4.xml +. remove defaults for stream_year_*, bndtvs, sstcyc + +bld/namelist_files/use_cases/aquaplanet_cam3.xml +bld/namelist_files/use_cases/aquaplanet_cam4.xml +bld/namelist_files/use_cases/aquaplanet_cam5.xml +bld/namelist_files/use_cases/aquaplanet_cam6.xml +bld/namelist_files/use_cases/aquaplanet_rce_cam6.xml +. remove default for aqua_planet (no longer in the namelist definition file) + +cime_config/buildnml +. get values of stream_ndep_* from the corresponding case variables + (CAM_STREAM_NDEP_*). Add the namelist key=value pairs to the string that + is generated to be passed via the -namelist option. + +cime_config/config_component.xml +. add values for the case variables CAM_STREAM_NDEP_* + +src/control/camsrfexch.F90 +. remove conditionals from allocation of cam_out%nhx_nitrogen_flx and + cam_out%noy_nitrogen_flx. CAM always provides this data now. + +src/cpl/nuopc/atm_comp_nuopc.F90 +. add explicit use/only statements for ESMF module +. add ESMF Mesh and clock objects with module scope, and add to the calling + args for export_fields. They are needed to generate streams. + +src/cpl/nuopc/atm_import_export.F90 +. mods so that nhx/noy are always in the list of fields that are exported. + If ndep_nflds=0 then the set_active_Faxa_* flags are set false. +. model_mesh, model_clock added to export_fields arg list +. add code to export_fields to use the stream code to set nhx/noy + deposition if it hasn't been computed. + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase (Overall: DIFF) details: + FAIL ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase NLCOMP + FAIL ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vmct.T42_T42_mg17.FDABIP04.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vmct.T42_T42_mg17.FDABIP04.cheyenne_intel.cam-outfrq3s_usecase NLCOMP + ERC_D_Ln9_Vmct.T42_T42_mg17.FHS94.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vmct.T42_T42_mg17.FHS94.cheyenne_intel.cam-outfrq3s_usecase NLCOMP + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPMOZ.cheyenne_intel.cam-outfrq3s (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPMOZ.cheyenne_intel.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPMOZ.cheyenne_intel.cam-outfrq3s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPX2000.cheyenne_intel.cam-outfrq3s (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPX2000.cheyenne_intel.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPX2000.cheyenne_intel.cam-outfrq3s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.FADIAB.cheyenne_intel.cam-terminator (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.FADIAB.cheyenne_intel.cam-terminator NLCOMP + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.T42_T42_mg17.FDABIP04.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vnuopc.T42_T42_mg17.FDABIP04.cheyenne_intel.cam-outfrq3s_usecase NLCOMP + ERC_D_Ln9_Vnuopc.T42_T42_mg17.FHS94.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vnuopc.T42_T42_mg17.FHS94.cheyenne_intel.cam-outfrq3s_usecase NLCOMP + ERI_D_Ln18_Vnuopc.f45_f45_mg37.QPC41850.cheyenne_intel.cam-co2rmp_usecase (Overall: DIFF) details: + FAIL ERI_D_Ln18_Vnuopc.f45_f45_mg37.QPC41850.cheyenne_intel.cam-co2rmp_usecase NLCOMP + FAIL ERI_D_Ln18_Vnuopc.f45_f45_mg37.QPC41850.cheyenne_intel.cam-co2rmp_usecase BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_D_Ln9_Vmct.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL ERP_D_Ln9_Vmct.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s NLCOMP + ERP_D_Ln9_Vmct.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL ERP_D_Ln9_Vmct.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s NLCOMP + ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ld3_Vnuopc.f09_f09_mg17.FWHIST.cheyenne_intel.cam-reduced_hist1d (Overall: NLFAIL) details: + FAIL ERP_Ld3_Vnuopc.f09_f09_mg17.FWHIST.cheyenne_intel.cam-reduced_hist1d NLCOMP + ERP_Lh12_Vnuopc.f19_f19_mg17.FW4madSD.cheyenne_intel.cam-outfrq3h (Overall: DIFF) details: + FAIL ERP_Lh12_Vnuopc.f19_f19_mg17.FW4madSD.cheyenne_intel.cam-outfrq3h NLCOMP + FAIL ERP_Lh12_Vnuopc.f19_f19_mg17.FW4madSD.cheyenne_intel.cam-outfrq3h BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes (Overall: DIFF) details: + FAIL ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes NLCOMP + FAIL ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vmct.f09_f09_mg17.2000_CAM60_CLM50%SP_CICE5%PRES_DOCN%DOM_MOSART_SGLC_SWAV.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL ERP_Ln9_Vmct.f09_f09_mg17.2000_CAM60_CLM50%SP_CICE5%PRES_DOCN%DOM_MOSART_SGLC_SWAV.cheyenne_intel.cam-outfrq9s NLCOMP + ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 NLCOMP + FAIL ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 NLCOMP + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s NLCOMP + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: NLFAIL) details: + FAIL ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 NLCOMP + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_L32wsc (Overall: DIFF) details: + FAIL ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_L32wsc NLCOMP + FAIL ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_L32wsc BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 (Overall: DIFF) details: + FAIL ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 NLCOMP + FAIL ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 (Overall: DIFF) details: + FAIL ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 NLCOMP + FAIL ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERS_Ln9_Vnuopc.f19_f19_mg17.FSPCAMS.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERS_Ln9_Vnuopc.f19_f19_mg17.FSPCAMS.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERS_Ln9_Vnuopc.f19_f19_mg17.FSPCAMS.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + ERS_Ln9_Vnuopc.ne0TESTONLYne5x4_ne0TESTONLYne5x4_mg37.FADIAB.cheyenne_intel.cam-outfrq3s_refined (Overall: NLFAIL) details: + FAIL ERS_Ln9_Vnuopc.ne0TESTONLYne5x4_ne0TESTONLYne5x4_mg37.FADIAB.cheyenne_intel.cam-outfrq3s_refined NLCOMP + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC5.cheyenne_intel.cam-scm_prep (Overall: DIFF) details: + FAIL SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC5.cheyenne_intel.cam-scm_prep NLCOMP + FAIL SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC5.cheyenne_intel.cam-scm_prep BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ld2_Vnuopc.f19_f19_mg17.QPC5HIST.cheyenne_intel.cam-volc_usecase (Overall: DIFF) details: + FAIL SMS_D_Ld2_Vnuopc.f19_f19_mg17.QPC5HIST.cheyenne_intel.cam-volc_usecase NLCOMP + FAIL SMS_D_Ld2_Vnuopc.f19_f19_mg17.QPC5HIST.cheyenne_intel.cam-volc_usecase BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ld5_Vnuopc.f19_f19_mg17.PC4.cheyenne_intel.cam-cam4_port5d (Overall: NLFAIL) details: + FAIL SMS_D_Ld5_Vnuopc.f19_f19_mg17.PC4.cheyenne_intel.cam-cam4_port5d NLCOMP + SMS_D_Ln9_Vmct.T42_T42.2000_CAM60%SCAM_CLM50%SP_CICE5%PRES_DOCN%DOM_SROF_SGLC_SWAV.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL SMS_D_Ln9_Vmct.T42_T42.2000_CAM60%SCAM_CLM50%SP_CICE5%PRES_DOCN%DOM_SROF_SGLC_SWAV.cheyenne_intel.cam-outfrq9s NLCOMP + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCts2nudged.cheyenne_intel.cam-outfrq9s_leapday (Overall: NLFAIL) details: + FAIL SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCts2nudged.cheyenne_intel.cam-outfrq9s_leapday NLCOMP + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCvbsxHIST.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCvbsxHIST.cheyenne_intel.cam-outfrq9s NLCOMP + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f09_f09_mg17.FSD.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f09_f09_mg17.FSD.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC2000climo.cheyenne_intel.cam-outfrq3s_usecase (Overall: NLFAIL) details: + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC2000climo.cheyenne_intel.cam-outfrq3s_usecase NLCOMP + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC5M7.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC5M7.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC5M7.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s NLCOMP + SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + FAIL SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s NLCOMP + SMS_D_Ln9_Vnuopc.T42_T42.FSCAM.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.T42_T42.FSCAM.cheyenne_intel.cam-outfrq9s NLCOMP + FAIL SMS_D_Ln9_Vnuopc.T42_T42.FSCAM.cheyenne_intel.cam-outfrq9s BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_Ld1_Vnuopc.f09_f09_mg17.FW2000climo.cheyenne_intel.cam-outfrq1d (Overall: NLFAIL) details: + FAIL SMS_Ld1_Vnuopc.f09_f09_mg17.FW2000climo.cheyenne_intel.cam-outfrq1d NLCOMP + SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + FAIL SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d NLCOMP + FAIL SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d (Overall: NLFAIL) details: + FAIL SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d NLCOMP + SMS_Ld5_Vnuopc.f09_f09_mg17.PC6.cheyenne_intel.cam-cam6_port_f09 (Overall: NLFAIL) details: + FAIL SMS_Ld5_Vnuopc.f09_f09_mg17.PC6.cheyenne_intel.cam-cam6_port_f09 NLCOMP + SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m (Overall: DIFF) details: + FAIL SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m NLCOMP + FAIL SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging (Overall: DIFF) details: + FAIL SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging NLCOMP + FAIL SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_Ln9_Vnuopc.f09_f09_mg17.FW1850.cheyenne_intel.cam-reduced_hist3s (Overall: NLFAIL) details: + FAIL SMS_Ln9_Vnuopc.f09_f09_mg17.FW1850.cheyenne_intel.cam-reduced_hist3s NLCOMP + SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs (Overall: DIFF) details: + FAIL SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs NLCOMP + FAIL SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_Ln9_Vnuopc.f19_f19_mg17.FHIST.cheyenne_intel.cam-outfrq9s_nochem (Overall: DIFF) details: + FAIL SMS_Ln9_Vnuopc.f19_f19_mg17.FHIST.cheyenne_intel.cam-outfrq9s_nochem NLCOMP + FAIL SMS_Ln9_Vnuopc.f19_f19_mg17.FHIST.cheyenne_intel.cam-outfrq9s_nochem BASELINE /glade/p/cesm/amwg/cesm_baselines/cam6_3_097: FIELDLIST field lists differ (otherwise bit-for-bit) + +The NLCOMP failures are due to adding the ndep_stream_nl group to atm_in. +The BASELINE test failures are due to different field list in the cpl.hi files. + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + FAIL DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae NLCOMP + FAIL DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae RUN time=223 + PEND DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae COMPARE_base_da + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QSPCAMS.izumi_nag.cam-outfrq3s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.mpasa480z32_mpasa480.FHS94.izumi_nag.cam-outfrq3s_usecase (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vnuopc.mpasa480z32_mpasa480.FHS94.izumi_nag.cam-outfrq3s_usecase NLCOMP + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne16pg3_ne16pg3_mg17.QPC4.izumi_nag.cam-outfrq3s_usecase BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC4.izumi_nag.cam-outfrq3s_usecase (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC4.izumi_nag.cam-outfrq3s_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC4.izumi_nag.cam-outfrq3s_usecase BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERI_D_Ln18_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: DIFF) details: + FAIL ERI_D_Ln18_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac NLCOMP + FAIL ERI_D_Ln18_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: DIFF) details: + FAIL ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 NLCOMP + FAIL ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERI_D_Ln18_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: + FAIL ERI_D_Ln18_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic NLCOMP + ERI_D_Ln18_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic (Overall: NLFAIL) details: + FAIL ERI_D_Ln18_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_nag.cam-outfrq3s_bwic NLCOMP + ERP_Ln9_Vmct.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: NLFAIL) details: + FAIL ERP_Ln9_Vmct.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf NLCOMP + ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf NLCOMP + FAIL ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + ERS_Ln27_Vnuopc.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: + FAIL ERS_Ln27_Vnuopc.ne5pg3_ne5pg3_mg37.FKESSLER.izumi_nag.cam-outfrq9s NLCOMP + ERS_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s (Overall: NLFAIL) details: + FAIL ERS_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq9s NLCOMP + PEM_D_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + FAIL PEM_D_Ln9_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s NLCOMP + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ld2_Vnuopc.f45_f45_mg37.PC5.izumi_nag.cam-outfrq24h_port (Overall: NLFAIL) details: + FAIL SMS_D_Ld2_Vnuopc.f45_f45_mg37.PC5.izumi_nag.cam-outfrq24h_port NLCOMP + SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + FAIL SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s NLCOMP + FAIL SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: DIFF) details: + FAIL SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem NLCOMP + FAIL SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln7_Vnuopc.T42_T42_mg17.QPSCAMC5.izumi_nag.cam-scmarm (Overall: DIFF) details: + FAIL SMS_D_Ln7_Vnuopc.T42_T42_mg17.QPSCAMC5.izumi_nag.cam-scmarm NLCOMP + FAIL SMS_D_Ln7_Vnuopc.T42_T42_mg17.QPSCAMC5.izumi_nag.cam-scmarm BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_P1x1_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s (Overall: NLFAIL) details: + FAIL SMS_D_Ln9_P1x1_Vnuopc.ne5_ne5_mg37.FADIAB.izumi_nag.cam-outfrq3s NLCOMP + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_ba BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: DIFF) details: + FAIL SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase NLCOMP + FAIL SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + SUB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + FAIL SUB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s NLCOMP + FAIL SUB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_nag: FIELDLIST field lists differ (otherwise bit-for-bit) + TMC_D_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: NLFAIL) details: + FAIL TMC_D_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac NLCOMP + TMC_D_Vnuopc.T5_T5_mg37.QPC5.izumi_nag.cam-ghgrmp_e8 (Overall: NLFAIL) details: + FAIL TMC_D_Vnuopc.T5_T5_mg37.QPC5.izumi_nag.cam-ghgrmp_e8 NLCOMP + +The DAE failure is pre-existing. +The NLCOMP failures are due to adding the ndep_stream_nl group to atm_in. +The BASELINE test failures are due to different field list in the cpl.hi files. + +izumi/gnu/aux_cam: + + ERC_D_Ln9_Vnuopc.f10_f10_mg37.FADIAB.izumi_gnu.cam-terminator (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.FADIAB.izumi_gnu.cam-terminator NLCOMP + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC4.izumi_gnu.cam-outfrq3s_diags BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-rad_diag BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s NLCOMP + FAIL ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC4.izumi_gnu.cam-outfrq3s_nudging_ne5_L26 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba NLCOMP + FAIL ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq3s_ba BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERC_D_Ln9_Vnuopc.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vnuopc.ne5pg2_ne5pg2_mg37.FADIAB.izumi_gnu.cam-outfrq3s NLCOMP + ERC_D_Ln9_Vnuopc.ne5pg4_ne5pg4_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + FAIL ERC_D_Ln9_Vnuopc.ne5pg4_ne5pg4_mg37.FADIAB.izumi_gnu.cam-outfrq3s NLCOMP + ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC3.izumi_gnu.cam-outfrq3s_usecase (Overall: DIFF) details: + FAIL ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC3.izumi_gnu.cam-outfrq3s_usecase NLCOMP + FAIL ERC_D_Ln9_Vnuopc.T5_T5_mg37.QPC3.izumi_gnu.cam-outfrq3s_usecase BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERI_D_Ln18_Vnuopc.T5_T5_mg37.QPC4.izumi_gnu.cam-co2rmp (Overall: DIFF) details: + FAIL ERI_D_Ln18_Vnuopc.T5_T5_mg37.QPC4.izumi_gnu.cam-co2rmp NLCOMP + FAIL ERI_D_Ln18_Vnuopc.T5_T5_mg37.QPC4.izumi_gnu.cam-co2rmp BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + ERP_Ln9_Vnuopc.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s (Overall: NLFAIL) details: + FAIL ERP_Ln9_Vnuopc.ne5_ne5_mg37.FHS94.izumi_gnu.cam-outfrq9s NLCOMP + ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + FAIL ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s NLCOMP + FAIL ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + PEM_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s (Overall: NLFAIL) details: + FAIL PEM_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.FADIAB.izumi_gnu.cam-outfrq3s NLCOMP + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 (Overall: DIFF) details: + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 NLCOMP + FAIL PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC4.izumi_gnu.cam-scm_prep (Overall: DIFF) details: + FAIL SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC4.izumi_gnu.cam-scm_prep NLCOMP + FAIL SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC4.izumi_gnu.cam-scm_prep BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: DIFF) details: + FAIL SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 NLCOMP + FAIL SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln3_Vnuopc.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc (Overall: DIFF) details: + FAIL SMS_D_Ln3_Vnuopc.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc NLCOMP + FAIL SMS_D_Ln3_Vnuopc.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee NLCOMP + FAIL SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac (Overall: DIFF) details: + FAIL SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac NLCOMP + FAIL SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + SMS_P48x1_D_Ln9_Vnuopc.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + FAIL SMS_P48x1_D_Ln9_Vnuopc.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s NLCOMP + FAIL SMS_P48x1_D_Ln9_Vnuopc.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s BASELINE /fs/cgd/csm/models/atm/cam/pretag_bl/cam6_3_097_gnu: FIELDLIST field lists differ (otherwise bit-for-bit) + +The NLCOMP failures are due to adding the ndep_stream_nl group to atm_in. +The BASELINE test failures are due to different field list in the cpl.hi files. + +CAM tag used for the baseline comparison tests if different than previous +tag: + +Summarize any changes to answers: none. + +=============================================================== +=============================================================== + +Tag name: cam6_3_097 +Originator(s): andrewgettelman, tilmes, fvitt +Date: 13 Mar 2023 +One-line Summary: Heterogeneous freezing science updates and bug fixes +Github PR URL: https://github.com/ESCOMP/CAM/pull/755 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + The following science updates and bug fixes to heterogeneous freezing parameterization + - new namelist parameters for scaling of dust and black carbon contributions + to heterogeneous freezing rates + - use physical approach to calculate species fractions + - use consistent concentrations of cloud-borne and ambient aerosol + - include sulfate in coarse dust fraction calculation + Update PUMAS external + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: + + New namelist parameters: + + hetfrz_bc_scalfac + Heterogeneous freezing scaling factor for black carbon aerosols. + Default: 0.01 + + hetfrz_dust_scalfac + Heterogeneous freezing scaling factor for dust aerosols. + Default: 0.05 + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: andrewgettelman, cacraigucar, jtruesdal, adamrher, nusbaume + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: +M Externals_CAM.cfg + - pumas update + +M bld/build-namelist +M bld/namelist_files/namelist_defaults_cam.xml +M bld/namelist_files/namelist_definition.xml + - new hetfrz scaling factors namelist parameters + +M src/physics/cam/hetfrz_classnuc_cam.F90 + - add scaling factor for dust + +M src/physics/cam/hetfrz_classnuc.F90 + - new hetfrz scaling factors namelist parameters for dust and BC + - remove separate interface for collection of cloud-borne aerosols + so that cloud-borne and ambient aerosol concentrations are consistent + - set num_to_mass_in to false (use physical approach to calc species fractions) + and calc primary carbon fraction consistently + - include SO4 in dst3 fraction calculation + +M src/physics/cam/microp_aero.F90 + - remove separate interface for collection of cloud-borne aerosols + so that cloud-borne and ambient aerosol concentrations are consistent + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp (Overall: DIFF) details: + ERP_D_Ln9_Vmct.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vmct.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ld3_Vnuopc.f09_f09_mg17.FWHIST.cheyenne_intel.cam-reduced_hist1d (Overall: DIFF) details: + ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes (Overall: DIFF) details: + ERP_Ln9_Vmct.f09_f09_mg17.2000_CAM60_CLM50%SP_CICE5%PRES_DOCN%DOM_MOSART_SGLC_SWAV.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: DIFF) details: + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_L32wsc (Overall: DIFF) details: + ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 (Overall: DIFF) details: + ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vmct.T42_T42.2000_CAM60%SCAM_CLM50%SP_CICE5%PRES_DOCN%DOM_SROF_SGLC_SWAV.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCts2nudged.cheyenne_intel.cam-outfrq9s_leapday (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCvbsxHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC2000climo.cheyenne_intel.cam-outfrq3s_usecase (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.T42_T42.FSCAM.cheyenne_intel.cam-outfrq9s (Overall: NLFAIL) details: + SMS_Ld1_Vnuopc.f09_f09_mg17.FW2000climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld5_Vnuopc.f09_f09_mg17.PC6.cheyenne_intel.cam-cam6_port_f09 (Overall: NLFAIL) details: + SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.FW1850.cheyenne_intel.cam-reduced_hist3s (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs (Overall: DIFF) details: + - expect different answers in cam6 configurations + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: DIFF) details: + ERP_Ln9_Vmct.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) details: + SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: DIFF) details: + - expect different answers in cam6 configurations + +izumi/gnu/aux_cam: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: DIFF) details: + - expect different answers in cam6 configurations + +Summarize any changes to answers: larger than roundoff + +=============================================================== +=============================================================== + +Tag name: cam6_3_096 +Originator(s): tilmes, fvitt +Date: 8 Mar 2023 +One-line Summary: Aqueous chemistry bug fix +Github PR URL: https://github.com/ESCOMP/CAM/pull/760 + +Purpose of changes (include the issue number and title text for each relevant GitHub issue): + + Exclude cloud ice from the water constituent input into the aqueous chemistry so that + only cloud liquid is used. + (See issue: Aq.chemistry update #758) + +Describe any changes made to build system: N/A + +Describe any changes made to the namelist: N/A + +List any changes to the defaults for the boundary datasets: N/A + +Describe any substantial timing or memory changes: N/A + +Code reviewed by: nusbaume, cacraig, tilmes + +List all files eliminated: N/A + +List all files added and what they do: N/A + +List all existing files that have been modified, and describe the changes: + +M src/chemistry/mozart/chemistry.F90 + - cloud water input is only the cloud liquid constituent + +If there were any failures reported from running test_driver.sh on any test +platform, and checkin with these failures has been OK'd by the gatekeeper, +then copy the lines from the td.*.status files for the failed tests to the +appropriate machine below. All failed tests must be justified. + +cheyenne/intel/aux_cam: + ERC_D_Ln9_P144x1_Vnuopc.ne16pg3_ne16pg3_mg17.QPC6HIST.cheyenne_intel.cam-outfrq3s_ttrac_usecase (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq3s_cosp (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPMOZ.cheyenne_intel.cam-outfrq3s (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f19_f19_mg17.QPX2000.cheyenne_intel.cam-outfrq3s (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.ne16_ne16_mg17.QPC5HIST.cheyenne_intel.cam-outfrq3s_usecase (Overall: DIFF) details: + ERP_D_Ln9_Vmct.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vmct.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vnuopc.f09_f09_mg17.QSC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vnuopc.f19_f19_mg17.QPC6.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_D_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.F2000dev.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ld3_Vnuopc.f09_f09_mg17.FWHIST.cheyenne_intel.cam-reduced_hist1d (Overall: DIFF) details: + ERP_Lh12_Vnuopc.f19_f19_mg17.FW4madSD.cheyenne_intel.cam-outfrq3h (Overall: DIFF) details: + ERP_Ln9_P24x3_Vnuopc.f45_f45_mg37.QPWmaC6.cheyenne_intel.cam-outfrq9s_mee_fluxes (Overall: DIFF) details: + ERP_Ln9_Vmct.f09_f09_mg17.2000_CAM60_CLM50%SP_CICE5%PRES_DOCN%DOM_MOSART_SGLC_SWAV.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.C96_C96_mg17.F2000climo.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2000dev.cheyenne_intel.cam-outfrq9s_mg3 (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f09_f09_mg17.FHIST_BDRD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.f19_f19_mg17.FWsc1850.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne30_ne30_mg17.FCnudged.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne30pg3_ne30pg3_mg17.FW2000climo.cheyenne_intel.cam-outfrq9s_wcm_ne30 (Overall: DIFF) details: + ERS_Ld3_Vnuopc.f10_f10_mg37.F1850.cheyenne_intel.cam-outfrq1d_14dec_L32wsc (Overall: DIFF) details: + ERS_Ln9_P288x1_Vnuopc.mpasa120_mpasa120.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa120 (Overall: DIFF) details: + ERS_Ln9_P36x1_Vnuopc.mpasa480_mpasa480.F2000climo.cheyenne_intel.cam-outfrq9s_mpasa480 (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f09_f09_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + ERS_Ln9_Vnuopc.f19_f19_mg17.FXSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC5.cheyenne_intel.cam-scm_prep (Overall: DIFF) details: + SMS_D_Ld2_Vnuopc.f19_f19_mg17.QPC5HIST.cheyenne_intel.cam-volc_usecase (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCts2nudged.cheyenne_intel.cam-outfrq9s_leapday (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FCvbsxHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f09_f09_mg17.FSD.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FWma2000climo.cheyenne_intel.cam-outfrq9s_waccm_ma_mam4 (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.FXHIST.cheyenne_intel.cam-outfrq9s_amie (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC2000climo.cheyenne_intel.cam-outfrq3s_usecase (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f19_f19_mg17.QPC5M7.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.FX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.ne16_ne16_mg17.QPX2000.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0ARCTICne30x4_ne0ARCTICne30x4_mt12.FHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne0CONUSne30x8_ne0CONUSne30x8_mt12.FCHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc_P720x1.ne30pg3_ne30pg3_mg17.FCLTHIST.cheyenne_intel.cam-outfrq9s (Overall: DIFF) details: + SMS_Ld1_Vnuopc.f09_f09_mg17.FW2000climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld1_Vnuopc.f19_f19.F2000dev.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Ld1_Vnuopc.ne30pg3_ne30pg3_mg17.FC2010climo.cheyenne_intel.cam-outfrq1d (Overall: DIFF) details: + SMS_Lm13_Vnuopc.f10_f10_mg37.F2000climo.cheyenne_intel.cam-outfrq1m (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.F2010climo.cheyenne_intel.cam-nudging (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f09_f09_mg17.FW1850.cheyenne_intel.cam-reduced_hist3s (Overall: DIFF) details: + SMS_Ln9_Vnuopc.f19_f19.F2000climo.cheyenne_intel.cam-silhs (Overall: DIFF) details: + - configurations with aqueous chemistry are expected to change answers + +izumi/nag/aux_cam: + DAE_Vnuopc.f45_f45_mg37.FHS94.izumi_nag.cam-dae (Overall: FAIL) details: + - pre-existing failure + + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-carma_sea_salt (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_cosp (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_subcol (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_am (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_convmic (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s_cospsathist (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC6.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-outfrq3s_ttrac (Overall: DIFF) details: + ERI_D_Ln18_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: DIFF) details: + ERI_D_Ln18_Vnuopc.f19_f19_mg17.QPC6.izumi_nag.cam-ghgrmp_e8 (Overall: DIFF) details: + ERP_Ln9_Vmct.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC6.izumi_nag.cam-outfrq9s_clubbmf (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal0 (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal1 (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_nag.cam-ttrac_loadbal3 (Overall: DIFF) details: + SMS_D_Ln3_Vnuopc.ne5pg3_ne5pg3_mg37.QPX2000.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + SMS_D_Ln6_Vnuopc.ne5_ne5_mg37.QPWmaC4.izumi_nag.cam-outfrq3s_physgrid_tem (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-rad_diag_mam (Overall: DIFF) details: + SMS_P48x1_D_Ln3_Vnuopc.f09_f09_mg17.QPC6HIST.izumi_nag.cam-outfrq3s_co2cycle_usecase (Overall: DIFF) details: + SUB_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s (Overall: DIFF) details: + TMC_D_Vnuopc.f10_f10_mg37.QPC5.izumi_nag.cam-outfrq3s_eoyttrac (Overall: DIFF) details: + TMC_D_Vnuopc.T5_T5_mg37.QPC5.izumi_nag.cam-ghgrmp_e8 (Overall: DIFF) details: + - configurations with aqueous chemistry are expected to change answers + +izumi/gnu/aux_cam: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPC5.izumi_gnu.cam-outfrq3s_unicon (Overall: DIFF) details: + ERC_D_Ln9_Vnuopc.f10_f10_mg37.QPSPCAMM.izumi_gnu.cam-outfrq3s (Overall: DIFF) details: + ERP_Ln9_Vnuopc.ne5_ne5_mg37.QPC5.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal0 (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal1 (Overall: DIFF) details: + PLB_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-ttrac_loadbal3 (Overall: DIFF) details: + SCT_D_Ln7_Vnuopc.T42_T42_mg17.QPC6.izumi_gnu.cam-scm_prep_c6 (Overall: DIFF) details: + SMS_D_Ln3_Vnuopc.f10_f10_mg37.QPMOZ.izumi_gnu.cam-outfrq3s_chemproc (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.f10_f10_mg37.QPWmaC4.izumi_gnu.cam-outfrq9s_apmee (Overall: DIFF) details: + SMS_D_Ln9_Vnuopc.ne5pg3_ne5pg3_mg37.QPC5.izumi_gnu.cam-outfrq3s_ttrac (Overall: DIFF) details: + SMS_P48x1_D_Ln9_Vnuopc.f19_f19_mg17.FW4madSD.izumi_gnu.cam-outfrq9s (Overall: DIFF) details: + - configurations with aqueous chemistry are expected to change answers + +Summarize any changes to answers: larger than roundoff + +=============================================================== +=============================================================== + Tag name: cam6_3_095 Originator(s): fvitt Date: 15 Feb 2023 diff --git a/src/chemistry/mozart/chemistry.F90 b/src/chemistry/mozart/chemistry.F90 index 5aba3224c6..2e870f4922 100644 --- a/src/chemistry/mozart/chemistry.F90 +++ b/src/chemistry/mozart/chemistry.F90 @@ -59,10 +59,6 @@ module chemistry character(len=shr_kind_cl) :: bndtvg = ' ' ! pathname for greenhouse gas loss rate character(len=shr_kind_cl) :: h2orates = ' ' ! pathname for greenhouse gas (lyman-alpha H2O loss) - ! lightning - - real(r8) :: lght_no_prd_factor = 1._r8 - ! photolysis character(len=shr_kind_cl) :: rsf_file = 'rsf_file' @@ -110,7 +106,7 @@ module chemistry character(len=fieldname_len) :: srcnam(gas_pcnst) ! names of source/sink tendencies - integer :: ixcldliq, ixcldice ! indicies of liquid and ice cloud water + integer :: ixcldliq ! index of liquid cloud water integer :: ndx_cld integer :: ndx_cmfdqr integer :: ndx_nevapr @@ -377,7 +373,6 @@ subroutine chem_readnl(nlfile) xs_coef_file, xs_short_file, & exo_coldens_file, & xs_long_file, rsf_file, photo_max_zen, & - lght_no_prd_factor, & depvel_lnd_file, drydep_srf_file, & srf_emis_type, srf_emis_cycle_yr, srf_emis_fixed_ymd, srf_emis_fixed_tod, srf_emis_specifier, & fstrat_file, fstrat_list, & @@ -454,10 +449,6 @@ subroutine chem_readnl(nlfile) call mpibcast (bndtvg, len(bndtvg), mpichar, 0, mpicom) call mpibcast (h2orates, len(h2orates), mpichar, 0, mpicom) - ! lightning - - call mpibcast (lght_no_prd_factor,1, mpir8, 0, mpicom) - ! photolysis call mpibcast (rsf_file, len(rsf_file), mpichar, 0, mpicom) @@ -687,7 +678,6 @@ subroutine chem_init(phys_state, pbuf2d) ! Get liq and ice cloud water indicies !----------------------------------------------------------------------- call cnst_get_ind( 'CLDLIQ', ixcldliq ) - call cnst_get_ind( 'CLDICE', ixcldice ) call cnst_get_ind( 'NUMLIQ', ixndrop, abort=.false. ) !----------------------------------------------------------------------- @@ -767,7 +757,6 @@ subroutine chem_init(phys_state, pbuf2d) , ext_frc_fixed_ymd & , ext_frc_fixed_tod & , exo_coldens_file & - , lght_no_prd_factor & , pbuf2d & ) @@ -979,6 +968,10 @@ subroutine chem_init_cnst( name, latvals, lonvals, mask, q) where(mask) q(:,ilev) = rmwf12 * chem_surfvals_get('F12VMR') end where + case ('CO2') + where(mask) + q(:,ilev) = chem_surfvals_get('CO2MMR') + end where end select end do end if @@ -1210,16 +1203,15 @@ subroutine chem_timestep_tend( state, ptend, cam_in, cam_out, dt, pbuf, fh2o) !----------------------------------------------------------------------- call t_startf( 'chemdr' ) do k = 1,pver - cldw(:ncol,k) = state%q(:ncol,k,ixcldliq) + state%q(:ncol,k,ixcldice) + cldw(:ncol,k) = state%q(:ncol,k,ixcldliq) if (ixndrop>0) & ncldwtr(:ncol,k) = state%q(:ncol,k,ixndrop) end do call gas_phase_chemdr(lchnk, ncol, imozart, state%q, & state%phis, state%zm, state%zi, calday, & - state%t, state%pmid, state%pdel, state%pint, & - cldw, tropLev, tropLevChem, ncldwtr, state%u, state%v, & - chem_dt, state%ps, & + state%t, state%pmid, state%pdel, state%pint, state%rpdel, state%rpdeldry, & + cldw, tropLev, tropLevChem, ncldwtr, state%u, state%v, chem_dt, state%ps, & fsds, cam_in%ts, cam_in%asdir, cam_in%ocnfrac, cam_in%icefrac, & cam_out%precc, cam_out%precl, cam_in%snowhland, ghg_chem, state%latmapback, & drydepflx, wetdepflx, cam_in%cflx, cam_in%fireflx, cam_in%fireztop, & diff --git a/src/chemistry/mozart/mo_chemini.F90 b/src/chemistry/mozart/mo_chemini.F90 index d66458e8fc..9c31b2ba61 100644 --- a/src/chemistry/mozart/mo_chemini.F90 +++ b/src/chemistry/mozart/mo_chemini.F90 @@ -36,7 +36,6 @@ subroutine chemini & , ext_frc_fixed_ymd & , ext_frc_fixed_tod & , exo_coldens_file & - , lght_no_prd_factor & , pbuf2d & ) @@ -48,7 +47,6 @@ subroutine chemini & use mo_srf_emissions, only : srf_emissions_inti use mo_sulf, only : sulf_inti use mo_photo, only : photo_inti - use mo_lightning, only : lightning_inti use mo_drydep, only : drydep_inti use mo_imp_sol, only : imp_slv_inti use mo_exp_sol, only : exp_sol_inti @@ -94,7 +92,6 @@ subroutine chemini & character(len=*), dimension(:), intent(in) :: srf_emis_specifier character(len=*), dimension(:), intent(in) :: ext_frc_specifier character(len=*), intent(in) :: exo_coldens_file - real(r8), intent(in) :: lght_no_prd_factor character(len=*), intent(in) :: ext_frc_type integer, intent(in) :: ext_frc_cycle_yr integer, intent(in) :: ext_frc_fixed_ymd @@ -161,12 +158,6 @@ subroutine chemini & call sad_inti(pbuf2d) if (masterproc) write(iulog,*) 'chemini: after sad_inti on node ',iam - !----------------------------------------------------------------------- - ! ... initialize the lightning module - !----------------------------------------------------------------------- - call lightning_inti(lght_no_prd_factor) - if (masterproc) write(iulog,*) 'chemini: after lightning_inti on node ',iam - !----------------------------------------------------------------------- ! ... initialize the dry deposition module !----------------------------------------------------------------------- diff --git a/src/chemistry/mozart/mo_gas_phase_chemdr.F90 b/src/chemistry/mozart/mo_gas_phase_chemdr.F90 index 323d9bbdaf..9e4e51df1f 100644 --- a/src/chemistry/mozart/mo_gas_phase_chemdr.F90 +++ b/src/chemistry/mozart/mo_gas_phase_chemdr.F90 @@ -232,7 +232,7 @@ end subroutine gas_phase_chemdr_inti !----------------------------------------------------------------------- subroutine gas_phase_chemdr(lchnk, ncol, imozart, q, & phis, zm, zi, calday, & - tfld, pmid, pdel, pint, & + tfld, pmid, pdel, pint, rpdel, rpdeldry, & cldw, troplev, troplevchem, & ncldwtr, ufld, vfld, & delt, ps, & @@ -246,8 +246,9 @@ subroutine gas_phase_chemdr(lchnk, ncol, imozart, q, & ! ebi, hov, fully implicit, and/or rodas algorithms. !----------------------------------------------------------------------- + use phys_control, only : cam_physpkg_is use chem_mods, only : nabscol, nfs, indexm, clscnt4 - use physconst, only : rga + use physconst, only : rga, gravit use mo_photo, only : set_ub_col, setcol, table_photo use mo_exp_sol, only : exp_sol use mo_imp_sol, only : imp_sol @@ -268,7 +269,7 @@ subroutine gas_phase_chemdr(lchnk, ncol, imozart, q, & use mo_mean_mass, only : set_mean_mass use cam_history, only : outfld use wv_saturation, only : qsat - use constituents, only : cnst_mw + use constituents, only : cnst_mw, cnst_type use mo_ghg_chem, only : ghg_chem_set_rates, ghg_chem_set_flbc use mo_sad, only : sad_strat_calc use charge_neutrality, only : charge_balance @@ -306,6 +307,8 @@ subroutine gas_phase_chemdr(lchnk, ncol, imozart, q, & real(r8),target,intent(in) :: tfld(pcols,pver) ! midpoint temperature (K) real(r8), intent(in) :: pmid(pcols,pver) ! midpoint pressures (Pa) real(r8), intent(in) :: pdel(pcols,pver) ! pressure delta about midpoints (Pa) + real(r8), intent(in) :: rpdel(pcols,pver) ! reciprocal pressure delta about midpoints (Pa) + real(r8), intent(in) :: rpdeldry(pcols,pver) ! reciprocal dry pressure delta about midpoints (Pa) real(r8), intent(in) :: ufld(pcols,pver) ! zonal velocity (m/s) real(r8), intent(in) :: vfld(pcols,pver) ! meridional velocity (m/s) real(r8), intent(in) :: cldw(pcols,pver) ! cloud water (kg/kg) @@ -1022,7 +1025,17 @@ subroutine gas_phase_chemdr(lchnk, ncol, imozart, q, & do m = 1,pcnst n = map2chm( m ) if ( n > 0 ) then - cflx(:ncol,m) = cflx(:ncol,m) - sflx(:ncol,n) + if (cam_physpkg_is("cam_dev")) then + ! apply to qtend array + if (cnst_type(m).eq.'dry') then + qtend(:ncol,pver,m) = qtend(:ncol,pver,m) - sflx(:ncol,n)*rpdeldry(:ncol,pver)*gravit + else + qtend(:ncol,pver,m) = qtend(:ncol,pver,m) - sflx(:ncol,n)*rpdel(:ncol,pver)*gravit + end if + else + ! apply to emissions array + cflx(:ncol,m) = cflx(:ncol,m) - sflx(:ncol,n) + end if drydepflx(:ncol,m) = sflx(:ncol,n) wetdepflx_diag(:ncol,n) = wetdepflx(:ncol,m) endif diff --git a/src/chemistry/mozart/mo_lightning.F90 b/src/chemistry/mozart/mo_lightning.F90 index 7f5860d173..4ef18fbaf6 100644 --- a/src/chemistry/mozart/mo_lightning.F90 +++ b/src/chemistry/mozart/mo_lightning.F90 @@ -10,140 +10,205 @@ module mo_lightning use cam_logfile, only : iulog use spmd_utils, only : masterproc, mpicom + use physics_buffer, only : pbuf_get_index, physics_buffer_desc, pbuf_get_field, pbuf_get_chunk + use physics_buffer, only : pbuf_add_field, pbuf_set_field, dtype_r8 + implicit none private - public :: lightning_inti + + public :: lightning_readnl + public :: lightning_register + public :: lightning_init public :: lightning_no_prod public :: prod_no - save + real(r8),protected, allocatable :: prod_no(:,:,:) real(r8) :: factor = 0.1_r8 ! user-controlled scaling factor to achieve arbitrary no prod. - real(r8) :: geo_factor ! grid cell area factor - real(r8) :: vdist(16,3) ! vertical distribution of lightning - real(r8), allocatable :: prod_no(:,:,:) - real(r8), allocatable :: glob_prod_no_col(:,:) - real(r8), allocatable :: flash_freq(:,:) - integer :: no_ndx,xno_ndx - logical :: has_no_lightning_prod = .false. + real(r8) :: geo_factor = -huge(1._r8) ! grid cell area factor + real(r8), allocatable :: vdist(:,:) ! vertical distribution of lightning + + logical :: calc_nox_prod = .false. + logical :: calc_lightning = .false. + + integer :: flsh_frq_ndx = -1 + integer :: cldtop_ndx = -1, cldbot_ndx = -1 + + ! namelist parameter + real(r8) :: lght_no_prd_factor = -huge(1._r8) contains - subroutine lightning_inti( lght_no_prd_factor ) + !------------------------------------------------------------------------- + ! Read namelist options + !------------------------------------------------------------------------- + subroutine lightning_readnl(nlfile) + use namelist_utils, only : find_group_name + use spmd_utils, only : mpicom, masterprocid, mpi_real8, mpi_success + + character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input + + integer :: unitn, ierr + character(len=*), parameter :: subname = 'lightning_readnl' + + ! =================== + ! Namelist definition + ! =================== + namelist /lightning_nl/ lght_no_prd_factor + + ! ============= + ! Read namelist + ! ============= + if (masterproc) then + open( newunit=unitn, file=trim(nlfile), status='old' ) + call find_group_name(unitn, 'lightning_nl', status=ierr) + if (ierr == 0) then + read(unitn, lightning_nl, iostat=ierr) + if (ierr /= 0) then + call endrun(subname // ':: ERROR reading namelist') + end if + end if + close(unitn) + end if + + ! ============================ + ! Broadcast namelist variables + ! ============================ + call mpi_bcast(lght_no_prd_factor, 1, mpi_real8, masterprocid, mpicom, ierr) + if (ierr/=mpi_success) then + call endrun(subname//': MPI_BCAST ERROR: lght_no_prd_factor') + end if + + if (masterproc) then + write(iulog,*) subname,' lght_no_prd_factor: ',lght_no_prd_factor + end if + + if( lght_no_prd_factor /= 1._r8 ) then + factor = factor*lght_no_prd_factor + end if + + end subroutine lightning_readnl + + !------------------------------------------------------------------------- + ! register phys buffer field for cloud to ground lightning flash frequency + ! to pass to the mediator for land model + !------------------------------------------------------------------------- + subroutine lightning_register() + + call pbuf_add_field('LGHT_FLASH_FREQ','global',dtype_r8,(/pcols/),flsh_frq_ndx) ! per minute + + end subroutine lightning_register + + !------------------------------------------------------------------------- + !------------------------------------------------------------------------- + subroutine lightning_init( pbuf2d ) !---------------------------------------------------------------------- ! ... initialize the lightning module !---------------------------------------------------------------------- use mo_constants, only : pi - use mo_chem_utls, only : get_spc_ndx use cam_history, only : addfld, add_default, horiz_only use phys_control, only : phys_getopts - - implicit none + use time_manager, only : is_first_step !---------------------------------------------------------------------- ! ... dummy args !---------------------------------------------------------------------- - real(r8), intent(in) :: lght_no_prd_factor ! lightning no production factor + type(physics_buffer_desc), pointer :: pbuf2d(:,:) !---------------------------------------------------------------------- ! ... local variables !---------------------------------------------------------------------- - integer :: astat + integer :: astat, err logical :: history_cesm_forcing + character(len=*),parameter :: prefix = 'lightning_init: ' + + cldtop_ndx = pbuf_get_index('CLDTOP',errcode=err) + cldbot_ndx = pbuf_get_index('CLDBOT',errcode=err) + calc_lightning = cldtop_ndx>0 .and. cldbot_ndx>0 + + if (.not.calc_lightning) return + + calc_nox_prod = lght_no_prd_factor>0._r8 + + if (calc_nox_prod) then + + if (masterproc) write(iulog,*) prefix,'lightning no production scaling factor = ',factor + + !---------------------------------------------------------------------- + ! ... vdist(kk,itype) = % of lightning nox between (kk-1) and (kk) + ! km for profile itype + !---------------------------------------------------------------------- + allocate(vdist(16,3),stat=astat) + if( astat /= 0 ) then + write(iulog,*) prefix,'failed to allocate vdist; error = ',astat + call endrun(prefix//'failed to allocate vdist') + end if + vdist(:,1) = (/ 3.0_r8, 3.0_r8, 3.0_r8, 3.0_r8, 3.4_r8, 3.5_r8, 3.6_r8, 4.0_r8, & ! midlat cont + 5.0_r8, 7.0_r8, 9.0_r8, 14.0_r8, 16.0_r8, 14.0_r8, 8.0_r8, 0.5_r8 /) + vdist(:,2) = (/ 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 6.1_r8, & ! trop marine + 17.0_r8, 15.4_r8, 14.5_r8, 13.0_r8, 12.5_r8, 2.8_r8, 0.9_r8, 0.3_r8 /) + vdist(:,3) = (/ 2.0_r8, 2.0_r8, 2.0_r8, 1.5_r8, 1.5_r8, 1.5_r8, 3.0_r8, 5.8_r8, & ! trop cont + 7.6_r8, 9.6_r8, 11.0_r8, 14.0_r8, 14.0_r8, 14.0_r8, 8.2_r8, 2.3_r8 /) + + allocate( prod_no(pcols,pver,begchunk:endchunk),stat=astat ) + if( astat /= 0 ) then + write(iulog,*) prefix, 'failed to allocate prod_no; error = ',astat + call endrun(prefix//'failed to allocate prod_no') + end if + geo_factor = ngcols_p/(4._r8*pi) + + call addfld( 'LNO_COL_PROD', horiz_only, 'I', 'Tg N yr-1', 'lightning column NO source' ) + call addfld( 'LNO_PROD', (/ 'lev' /), 'I', 'molecules/cm3/s', 'lightning insitu NO source' ) + call addfld( 'FLASHENGY', horiz_only, 'I', 'J', 'lightning flash energy' ) ! flash energy + + call phys_getopts( history_cesm_forcing_out = history_cesm_forcing ) + if ( history_cesm_forcing ) then + call add_default('LNO_COL_PROD',1,' ') + endif + + if (is_first_step()) then + call pbuf_set_field(pbuf2d, flsh_frq_ndx, 0.0_r8) + endif - call phys_getopts( history_cesm_forcing_out = history_cesm_forcing ) - - no_ndx = get_spc_ndx('NO') - xno_ndx = get_spc_ndx('XNO') - - has_no_lightning_prod = no_ndx>0 .or. xno_ndx>0 - if (.not.has_no_lightning_prod) return - - - if( lght_no_prd_factor /= 1._r8 ) then - factor = factor*lght_no_prd_factor - end if - - - if (masterproc) write(iulog,*) 'lght_inti: lightning no production scaling factor = ',factor - - !---------------------------------------------------------------------- - ! ... vdist(kk,itype) = % of lightning nox between (kk-1) and (kk) - ! km for profile itype - !---------------------------------------------------------------------- - vdist(:,1) = (/ 3.0_r8, 3.0_r8, 3.0_r8, 3.0_r8, 3.4_r8, 3.5_r8, 3.6_r8, 4.0_r8, & ! midlat cont - 5.0_r8, 7.0_r8, 9.0_r8, 14.0_r8, 16.0_r8, 14.0_r8, 8.0_r8, 0.5_r8 /) - vdist(:,2) = (/ 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 2.5_r8, 6.1_r8, & ! trop marine - 17.0_r8, 15.4_r8, 14.5_r8, 13.0_r8, 12.5_r8, 2.8_r8, 0.9_r8, 0.3_r8 /) - vdist(:,3) = (/ 2.0_r8, 2.0_r8, 2.0_r8, 1.5_r8, 1.5_r8, 1.5_r8, 3.0_r8, 5.8_r8, & ! trop cont - 7.6_r8, 9.6_r8, 11.0_r8, 14.0_r8, 14.0_r8, 14.0_r8, 8.2_r8, 2.3_r8 /) - - allocate( prod_no(pcols,pver,begchunk:endchunk),stat=astat ) - if( astat /= 0 ) then - write(iulog,*) 'lght_inti: failed to allocate prod_no; error = ',astat - call endrun - end if - allocate( flash_freq(pcols,begchunk:endchunk),stat=astat ) - if( astat /= 0 ) then - write(iulog,*) 'lght_inti: failed to allocate flash_freq; error = ',astat - call endrun - end if - allocate( glob_prod_no_col(pcols,begchunk:endchunk),stat=astat ) - if( astat /= 0 ) then - write(iulog,*) 'lght_inti: failed to allocate glob_prod_no_col; error = ',astat - call endrun - end if - prod_no(:,:,:) = 0._r8 - flash_freq(:,:) = 0._r8 - geo_factor = ngcols_p/(4._r8*pi) - - - call addfld( 'LNO_COL_PROD', horiz_only, 'I', 'TG N/YR', 'lighting column NO source' ) - call addfld( 'LNO_PROD', (/ 'lev' /), 'I', '/cm3/s', 'lighting insitu NO source' ) - call addfld( 'FLASHFRQ', horiz_only, 'I', '1/MIN', 'lighting flash rate' ) ! flash frequency in grid box per minute (PPP) - call addfld( 'FLASHENGY', horiz_only, 'I', ' ', 'lighting flash rate' ) ! flash frequency in grid box per minute (PPP) - call addfld( 'CLDHGT', horiz_only, 'I', 'KM', 'cloud top height' ) ! cloud top height - call addfld( 'DCHGZONE', horiz_only, 'I', 'KM', 'depth of discharge zone' ) ! depth of discharge zone - call addfld( 'CGIC', horiz_only, 'I', 'RATIO', 'ratio of cloud-ground/intracloud discharges' ) ! ratio of cloud-ground/intracloud discharges - - if ( history_cesm_forcing ) then - call add_default('LNO_COL_PROD',1,' ') endif - end subroutine lightning_inti + call addfld( 'FLASHFRQ', horiz_only, 'I', 'min-1', 'lightning flash rate' ) ! flash frequency in grid box per minute (PPP) + call addfld( 'CLDHGT', horiz_only, 'I', 'km', 'cloud top height' ) ! cloud top height + call addfld( 'DCHGZONE', horiz_only, 'I', 'km', 'depth of discharge zone' ) ! depth of discharge zone + call addfld( 'CGIC', horiz_only, 'I', '1', 'ratio of cloud-ground/intracloud discharges' ) ! ratio of cloud-ground/intracloud discharges + call addfld( 'LGHTNG_CLD2GRND', horiz_only, 'I', 'min-1', 'clound-to-ground lightning flash rate') ! clound to ground flash frequency + end subroutine lightning_init + + !------------------------------------------------------------------------- + !------------------------------------------------------------------------- subroutine lightning_no_prod( state, pbuf2d, cam_in ) !---------------------------------------------------------------------- ! ... set no production from lightning !---------------------------------------------------------------------- use physics_types, only : physics_state - - use physics_buffer, only : pbuf_get_index, physics_buffer_desc, pbuf_get_field, pbuf_get_chunk use physconst, only : rga use phys_grid, only : get_rlat_all_p, get_wght_all_p use cam_history, only : outfld use camsrfexch, only : cam_in_t use shr_reprosum_mod, only : shr_reprosum_calc - use mo_constants, only : rearth, d2r - implicit none + use mo_constants, only : rearth, d2r !---------------------------------------------------------------------- ! ... dummy args !---------------------------------------------------------------------- type(physics_state), intent(in) :: state(begchunk:endchunk) ! physics state - type(physics_buffer_desc), pointer :: pbuf2d(:,:) type(cam_in_t), intent(in) :: cam_in(begchunk:endchunk) ! physics state !---------------------------------------------------------------------- ! ... local variables !---------------------------------------------------------------------- - real(r8), parameter :: land = 1._r8 - real(r8), parameter :: secpyr = 365._r8 * 8.64e4_r8 + real(r8), parameter :: land = 1._r8 + real(r8), parameter :: secpyr = 365._r8 * 8.64e4_r8 - integer :: i, c integer :: cldtind ! level index for cloud top integer :: cldbind ! level index for cloud base > 273k integer :: k, kk, zlow_ind, zhigh_ind, itype @@ -162,16 +227,20 @@ subroutine lightning_no_prod( state, pbuf2d, cam_in ) real(r8) :: flash_energy(pcols,begchunk:endchunk) ! energy of flashes per second real(r8) :: prod_no_col(pcols,begchunk:endchunk) ! global no production rate for diagnostics real(r8) :: wrk, wrk1, wrk2(1) + integer :: icol ! column index integer :: ncol ! columns per chunk - integer :: lchnk ! columns per chunk + integer :: lchnk ! chunk index real(r8),pointer :: cldtop(:) ! cloud top level index real(r8),pointer :: cldbot(:) ! cloud bottom level index real(r8) :: zmid(pcols,pver) ! geopot height above surface at midpoints (m) real(r8) :: zint(pcols,pver+1,begchunk:endchunk) ! geopot height above surface at interfaces (m) real(r8) :: zsurf(pcols) ! geopot height above surface at interfaces (m) - real(r8) :: rlats(pcols,begchunk:endchunk) ! column latitudes in chunks + real(r8) :: rlats(pcols) ! column latitudes in chunks real(r8) :: wght(pcols) + real(r8) :: glob_prod_no_col(pcols,begchunk:endchunk) + real(r8) :: flash_freq(pcols,begchunk:endchunk) + !---------------------------------------------------------------------- ! ... parameters to determine cg/ic ratio [price and rind, 1993] !---------------------------------------------------------------------- @@ -184,26 +253,29 @@ subroutine lightning_no_prod( state, pbuf2d, cam_in ) real(r8), parameter :: m2km = 1.e-3_r8 real(r8), parameter :: km2cm = 1.e5_r8 real(r8), parameter :: lat25 = 25._r8*d2r ! 25 degrees latitude in radians - integer :: cldtop_ndx, cldbot_ndx + real(r8) :: flash_freq_land, flash_freq_ocn + real(r8), pointer :: cld2grnd_flash_freq(:) + + if (.not.calc_lightning) return - if (.not.has_no_lightning_prod) return + nullify(cld2grnd_flash_freq) !---------------------------------------------------------------------- ! ... initialization !---------------------------------------------------------------------- flash_freq(:,:) = 0._r8 - prod_no(:,:,:) = 0._r8 - prod_no_col(:,:) = 0._r8 cldhgt(:,:) = 0._r8 dchgzone(:,:) = 0._r8 cgic(:,:) = 0._r8 flash_energy(:,:) = 0._r8 - glob_prod_no_col(:,:) = 0._r8 - cldtop_ndx = pbuf_get_index('CLDTOP') - cldbot_ndx = pbuf_get_index('CLDBOT') + if (calc_nox_prod) then + prod_no(:,:,:) = 0._r8 + prod_no_col(:,:) = 0._r8 + glob_prod_no_col(:,:) = 0._r8 + end if !-------------------------------------------------------------------------------- ! ... estimate flash frequency and resulting no emissions @@ -223,29 +295,30 @@ subroutine lightning_no_prod( state, pbuf2d, cam_in ) ! with 1e17 n atoms per j. the total number of n atoms is then distributed ! over the complete column of grid boxes. !-------------------------------------------------------------------------------- - Chunk_loop : do c = begchunk,endchunk - ncol = state(c)%ncol - lchnk = state(c)%lchnk + Chunk_loop : do lchnk = begchunk,endchunk + ncol = state(lchnk)%ncol + call pbuf_get_field(pbuf_get_chunk(pbuf2d,lchnk), flsh_frq_ndx, cld2grnd_flash_freq ) call pbuf_get_field(pbuf_get_chunk(pbuf2d,lchnk), cldtop_ndx, cldtop ) call pbuf_get_field(pbuf_get_chunk(pbuf2d,lchnk), cldbot_ndx, cldbot ) - zsurf(:ncol) = state(c)%phis(:ncol)*rga - call get_rlat_all_p(c, ncol, rlats(1,c) ) - call get_wght_all_p(c, ncol, wght) + zsurf(:ncol) = state(lchnk)%phis(:ncol)*rga + call get_wght_all_p(lchnk, pcols, wght) do k = 1,pver - zmid(:ncol,k) = state(c)%zm(:ncol,k) + zsurf(:ncol) - zint(:ncol,k,c) = state(c)%zi(:ncol,k) + zsurf(:ncol) + zmid(:ncol,k) = state(lchnk)%zm(:ncol,k) + zsurf(:ncol) + zint(:ncol,k,lchnk) = state(lchnk)%zi(:ncol,k) + zsurf(:ncol) end do - zint(:ncol,pver+1,c) = state(c)%zi(:ncol,pver+1) + zsurf(:ncol) + zint(:ncol,pver+1,lchnk) = state(lchnk)%zi(:ncol,pver+1) + zsurf(:ncol) + + cld2grnd_flash_freq(:) = 0.0_r8 - col_loop : do i = 1,ncol + col_loop : do icol = 1,ncol !-------------------------------------------------------------------------------- ! ... find cloud top and bottom level above 273k !-------------------------------------------------------------------------------- - cldtind = nint( cldtop(i) ) - cldbind = nint( cldbot(i) ) + cldtind = nint( cldtop(icol) ) + cldbind = nint( cldbot(icol) ) do - if( cldbind <= cldtind .or. state(c)%t(i,cldbind) < t0 ) then + if( cldbind <= cldtind .or. state(lchnk)%t(icol,cldbind) < t0 ) then exit end if cldbind = cldbind - 1 @@ -254,58 +327,77 @@ subroutine lightning_no_prod( state, pbuf2d, cam_in ) !-------------------------------------------------------------------------------- ! ... compute cloud top height and depth of charging zone !-------------------------------------------------------------------------------- - cldhgt(i,c) = m2km*max( 0._r8,zint(i,cldtind,c) ) - dchgz = cldhgt(i,c) - m2km*zmid(i,cldbind) - dchgzone(i,c) = dchgz + cldhgt(icol,lchnk) = m2km*max( 0._r8,zint(icol,cldtind,lchnk) ) + dchgz = cldhgt(icol,lchnk) - m2km*zmid(icol,cldbind) + dchgzone(icol,lchnk) = dchgz !-------------------------------------------------------------------------------- ! ... compute flash frequency for given cloud top height ! (flashes storm^-1 min^-1) !-------------------------------------------------------------------------------- - flash_freq_land = 3.44e-5_r8 * cldhgt(i,c)**4.9_r8 - flash_freq_ocn = 6.40e-4_r8 * cldhgt(i,c)**1.7_r8 - flash_freq(i,c) = cam_in(c)%landfrac(i)*flash_freq_land + & - cam_in(c)%ocnfrac(i) *flash_freq_ocn + flash_freq_land = 3.44e-5_r8 * cldhgt(icol,lchnk)**4.9_r8 + flash_freq_ocn = 6.40e-4_r8 * cldhgt(icol,lchnk)**1.7_r8 + flash_freq(icol,lchnk) = cam_in(lchnk)%landfrac(icol)*flash_freq_land + & + cam_in(lchnk)%ocnfrac(icol) *flash_freq_ocn !-------------------------------------------------------------------------------- - ! ... compute cg/ic ratio - ! cgic = proportion of cg flashes (=pg from ppp paper) + ! cgic = proportion of cloud-to-ground flashes + ! NOx from lightning 1. Global distribution based on lightning physics, C Price et al + ! JOURNAL OF GEOPHYSICAL RESEARCH, VOL. 102, NO. D5, PAGES 5929-5941, MARCH 20, 1997 + ! (https://agupubs.onlinelibrary.wiley.com/doi/epdf/10.1029/96JD03504) + ! eq 14 !-------------------------------------------------------------------------------- - cgic(i,c) = 1._r8/((((ca*dchgz + cb)*dchgz + cc) *dchgz + cd)*dchgz + ce) + cgic(icol,lchnk) = 1._r8/((((ca*dchgz + cb)*dchgz + cc) *dchgz + cd)*dchgz + ce) if( dchgz < 5.5_r8 ) then - cgic(i,c) = 0._r8 + cgic(icol,lchnk) = 0._r8 else if( dchgz > 14._r8 ) then - cgic(i,c) = .02_r8 + cgic(icol,lchnk) = .02_r8 end if - !-------------------------------------------------------------------------------- - ! ... compute flash energy (cg*6.7e9 + ic*6.7e8) - ! and convert to total energy per second - ! set ic = cg - !-------------------------------------------------------------------------------- - flash_energy(i,c) = 6.7e9_r8 * flash_freq(i,c)/60._r8 - !-------------------------------------------------------------------------------- - ! ... LKE Aug 23, 2005: scale production to account for different grid - ! box sizes. This requires a reduction in the overall fudge factor - ! (e.g., from 1.2 to 0.5) - !-------------------------------------------------------------------------------- - flash_energy(i,c) = flash_energy(i,c) * wght(i) * geo_factor - !-------------------------------------------------------------------------------- - ! ... compute number of n atoms produced per second - ! and convert to n atoms per second per cm2 and apply fudge factor - !-------------------------------------------------------------------------------- - prod_no_col(i,c) = 1.e17_r8*flash_energy(i,c)/(1.e4_r8*rearth*rearth*wght(i)) * factor - - !-------------------------------------------------------------------------------- - ! ... compute global no production rate in tgn/yr: - ! tgn per second: * 14.00674 * 1.65979e-24 * 1.e-12 - ! nb: 1.65979e-24 = 1/avo - ! tgn per year: * secpyr - !-------------------------------------------------------------------------------- - glob_prod_no_col(i,c) = 1.e17_r8*flash_energy(i,c) & - * 14.00674_r8 * 1.65979e-24_r8 * 1.e-12_r8 * secpyr * factor + cld2grnd_flash_freq(icol) = cam_in(lchnk)%landfrac(icol)*flash_freq_land*cgic(icol,lchnk) ! cld-to-grnd flash frq (per min) + + if (calc_nox_prod) then + !-------------------------------------------------------------------------------- + ! ... compute flash energy (cg*6.7e9 + ic*6.7e8) + ! and convert to total energy per second + ! set ic = cg + !-------------------------------------------------------------------------------- + flash_energy(icol,lchnk) = 6.7e9_r8 * flash_freq(icol,lchnk)/60._r8 + !-------------------------------------------------------------------------------- + ! ... LKE Aug 23, 2005: scale production to account for different grid + ! box sizes. This requires a reduction in the overall fudge factor + ! (e.g., from 1.2 to 0.5) + !-------------------------------------------------------------------------------- + flash_energy(icol,lchnk) = flash_energy(icol,lchnk) * wght(icol) * geo_factor + !-------------------------------------------------------------------------------- + ! ... compute number of n atoms produced per second + ! and convert to n atoms per second per cm2 and apply fudge factor + !-------------------------------------------------------------------------------- + prod_no_col(icol,lchnk) = 1.e17_r8*flash_energy(icol,lchnk)/(1.e4_r8*rearth*rearth*wght(icol)) * factor + + !-------------------------------------------------------------------------------- + ! ... compute global no production rate in tgn/yr: + ! tgn per second: * 14.00674 * 1.65979e-24 * 1.e-12 + ! nb: 1.65979e-24 = 1/avo + ! tgn per year: * secpyr + !-------------------------------------------------------------------------------- + glob_prod_no_col(icol,lchnk) = 1.e17_r8*flash_energy(icol,lchnk) & + * 14.00674_r8 * 1.65979e-24_r8 * 1.e-12_r8 * secpyr * factor + end if end if cloud_layer end do Col_loop + + call outfld( 'LGHTNG_CLD2GRND', cld2grnd_flash_freq, pcols, lchnk ) end do Chunk_loop + + do lchnk = begchunk,endchunk + call outfld( 'FLASHFRQ', flash_freq(:,lchnk), pcols, lchnk ) + call outfld( 'CGIC', cgic(:,lchnk), pcols, lchnk ) + call outfld( 'CLDHGT', cldhgt(:,lchnk), pcols, lchnk ) + call outfld( 'DCHGZONE', dchgzone(:,lchnk), pcols, lchnk ) + enddo + + if (.not.calc_nox_prod) return + !-------------------------------------------------------------------------------- ! ... Accumulate global total, convert to flashes per second ! ... Accumulate global NO production rate @@ -325,29 +417,29 @@ subroutine lightning_no_prod( state, pbuf2d, cam_in ) !-------------------------------------------------------------------------------- ! ... Distribute production up to cloud top [Pickering et al., 1998 (JGR)] !-------------------------------------------------------------------------------- - do c = begchunk,endchunk - ncol = state(c)%ncol - lchnk = state(c)%lchnk + do lchnk = begchunk,endchunk + call get_rlat_all_p(lchnk, pcols, rlats) + ncol = state(lchnk)%ncol call pbuf_get_field(pbuf_get_chunk(pbuf2d,lchnk), cldtop_ndx, cldtop ) - do i = 1,ncol - cldtind = nint( cldtop(i) ) - if( prod_no_col(i,c) > 0._r8 ) then - if( cldhgt(i,c) > 0._r8 ) then - if( abs( rlats(i,c) ) > lat25 ) then - itype = 1 ! midlatitude continental - else if( nint( cam_in(c)%landfrac(i) ) == land ) then - itype = 3 ! tropical continental + do icol = 1,ncol + cldtind = nint( cldtop(icol) ) + if( prod_no_col(icol,lchnk) > 0._r8 ) then + if( cldhgt(icol,lchnk) > 0._r8 ) then + if( abs( rlats(icol) ) > lat25 ) then + itype = 1 ! midlatitude continental + else if( nint( cam_in(lchnk)%landfrac(icol) ) == land ) then + itype = 3 ! tropical continental else - itype = 2 ! topical marine + itype = 2 ! topical marine end if frac_sum = 0._r8 do k = cldtind,pver - zlow = zint(i,k+1,c) * m2km ! lower interface height (km) - zlow_scal = zlow * 16._r8/cldhgt(i,c) ! scale to 16 km convection height - zlow_ind = max( 1,INT(zlow_scal)+1 ) ! lowest vdist index to include in layer - zhigh = zint(i,k,c) * m2km ! upper interface height (km) - zhigh_scal = zhigh * 16._r8/cldhgt(i,c) ! height (km) scaled to 16km convection height - zhigh_ind = max( 1,MIN( 16,INT(zhigh_scal)+1 ) ) ! highest vdist index to include in layer + zlow = zint(icol,k+1,lchnk) * m2km ! lower interface height (km) + zlow_scal = zlow * 16._r8/cldhgt(icol,lchnk) ! scale to 16 km convection height + zlow_ind = max( 1,INT(zlow_scal)+1 ) ! lowest vdist index to include in layer + zhigh = zint(icol,k,lchnk) * m2km ! upper interface height (km) + zhigh_scal = zhigh * 16._r8/cldhgt(icol,lchnk) ! height (km) scaled to 16km convection height + zhigh_ind = max( 1,MIN( 16,INT(zhigh_scal)+1 ) ) ! highest vdist index to include in layer do kk = zlow_ind,zhigh_ind wrk = kk wrk1 = kk - 1 @@ -355,11 +447,11 @@ subroutine lightning_no_prod( state, pbuf2d, cam_in ) - max( zlow_scal,wrk1 ) fraction = max( 0._r8, min( 1._r8,fraction ) ) frac_sum = frac_sum + fraction*vdist(kk,itype) - prod_no(i,k,c) = prod_no(i,k,c) & ! sum the fraction of column NOx in layer k + prod_no(icol,k,lchnk) = prod_no(icol,k,lchnk) & ! sum the fraction of column NOx in layer k + fraction*vdist(kk,itype)*.01_r8 end do - prod_no(i,k,c) = prod_no_col(i,c) * prod_no(i,k,c) & ! multiply fraction by column amount - / (km2cm*(zhigh - zlow)) ! and convert to atom N cm^-3 s^-1 + prod_no(icol,k,lchnk) = prod_no_col(icol,lchnk) * prod_no(icol,k,lchnk) & ! multiply fraction by column amount + / (km2cm*(zhigh - zlow)) ! and convert to atom N cm^-3 s^-1 end do end if end if @@ -370,15 +462,10 @@ subroutine lightning_no_prod( state, pbuf2d, cam_in ) !-------------------------------------------------------------------------------- ! ... output lightning no production to history file !-------------------------------------------------------------------------------- - do c = begchunk,endchunk - lchnk = state(c)%lchnk - call outfld( 'LNO_PROD', prod_no(:,:,c), pcols, lchnk ) - call outfld( 'LNO_COL_PROD', glob_prod_no_col(:,c), pcols, lchnk ) - call outfld( 'FLASHFRQ', flash_freq(:,c), pcols, lchnk ) - call outfld( 'FLASHENGY', flash_energy(:,c), pcols, lchnk ) - call outfld( 'CLDHGT', cldhgt(:,c), pcols, lchnk ) - call outfld( 'DCHGZONE', dchgzone(:,c), pcols, lchnk ) - call outfld( 'CGIC', cgic(:,c), pcols, lchnk ) + do lchnk = begchunk,endchunk + call outfld( 'LNO_PROD', prod_no(:,:,lchnk), pcols, lchnk ) + call outfld( 'LNO_COL_PROD', glob_prod_no_col(:,lchnk), pcols, lchnk ) + call outfld( 'FLASHENGY', flash_energy(:,lchnk), pcols, lchnk ) enddo end subroutine lightning_no_prod diff --git a/src/chemistry/mozart/ocean_emis.F90 b/src/chemistry/mozart/ocean_emis.F90 index 26819fd846..289cafeb77 100644 --- a/src/chemistry/mozart/ocean_emis.F90 +++ b/src/chemistry/mozart/ocean_emis.F90 @@ -3,23 +3,23 @@ ! Ref: Carpenter et al Chem Soc Rev (2012); Johnson, Ocean sci (2010) ! ------------------------------------------------------------------------------------ ! Required inputs for the air-sea flux module: -! - Seawater concentration (nanomoles per liter) and Sea surface salinity +! - Seawater concentration (nanomoles per liter) and Sea surface salinity ! (parts per thousand) read from namelist (netCDF) ! - Concentration in the gas-phase (pptv), air temperature (K), 10m windspeed (m/s), ! surface pressure (atm), sea surface temperature (K): all from other modules ! ------------------------------------------------------------------------------------ ! Key subroutines: -! ocean_emis_readnl(..): Read salinity from namelist (user_nl_cam). +! ocean_emis_readnl(..): Read salinity from namelist (user_nl_cam). ! Salinity not time-dependent. Flux depends very weakly on it -! ocean_emis_init(...): Interpolate salinity, initialize the library for the flux +! ocean_emis_init(...): Interpolate salinity, initialize the library for the flux ! reading time-dependent seawater conc. from user_nl_cam ! ocean_emis_advance(...): process the seawater concentration -! ocean_emis_getflux(...): calculate the air-sea flux (upward or downward), +! ocean_emis_getflux(...): calculate the air-sea flux (upward or downward), ! then add to total surface flux (sflx) ! ------------------------------------------------------------------------------------ ! Last built: 9 March 2018. ! Written by: Siyuan Wang (ACOM/NCAR) siyuan@ucar.edu -! Acknowledgement: Francis Vitt (NCAR). and of course Dr. Peppurr too +! Acknowledgement: Francis Vitt (NCAR). and of course Dr. Peppurr too ! ==================================================================================== module ocean_emis @@ -33,7 +33,7 @@ module ocean_emis use tracer_data, only : trfld,trfile use chem_mods, only : gas_pcnst use cam_logfile, only : iulog - use ioFileMod, only : getfil + use ioFileMod, only : getfil implicit none @@ -57,9 +57,9 @@ module ocean_emis logical :: switch_bubble type(Csw), allocatable :: Csw_nM(:) - integer :: n_Csw_files + integer :: n_Csw_files - real(r8), allocatable :: salinity(:,:) + real(r8), allocatable :: salinity(:,:) ! ================ ! Air-sea exchange @@ -69,32 +69,32 @@ module ocean_emis Integer, Parameter :: HowManySalts = 5 ! Change this number if you wanna add more salts Integer, Parameter :: HowManySaltProperties = 7 ! Don't touch this (unless you wanna add more fields) - Type GasLib + Type GasLib Character(16) :: CmpdName Real(r8), Dimension(HowManyProperties) :: CmpdProperties End Type GasLib - Type SaltLib + Type SaltLib Character(16) :: SaltName - Real(r8), Dimension(HowManySaltProperties) :: SaltProperties + Real(r8), Dimension(HowManySaltProperties) :: SaltProperties End Type SaltLib Type(GasLib), Dimension(HowManyMolecules) :: GasList ! Library for the trace gas properties Type(SaltLib), Dimension(HowManySalts) :: SaltList ! Library for the salt properties - ! =========================== + ! =========================== ! seawater concentration: ! =========================== - character(len=cl) :: csw_specifier(gas_pcnst) = '' + character(len=cl) :: csw_specifier(gas_pcnst) = '' character(len=24) :: csw_time_type = 'CYCLICAL' ! 'CYCLICAL' | 'SERIAL' | 'INTERP_MISSING_MONTHS' integer :: csw_cycle_yr = 0 - logical :: bubble_mediated_transfer = .false. + logical :: bubble_mediated_transfer = .false. character(len=cl) :: ocean_salinity_file = 'NONE' contains -!-------------------------------------------------------------------------------- -!-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- subroutine ocean_emis_readnl(nlfile) use namelist_utils, only : find_group_name @@ -105,7 +105,7 @@ subroutine ocean_emis_readnl(nlfile) integer :: unitn, ierr character(len=*), parameter :: subname = 'ocean_emis_readnl' - ! =================== + ! =================== ! Namelist definition ! =================== namelist /ocean_emis_nl/ ocean_salinity_file @@ -125,7 +125,7 @@ subroutine ocean_emis_readnl(nlfile) end if close(unitn) end if - + ! ============================ ! Broadcast namelist variables ! ============================ @@ -151,7 +151,7 @@ subroutine ocean_emis_init() use pio, only : file_desc_t, pio_inq_dimid, pio_inq_dimlen, pio_inq_varid, pio_get_var use pio, only : PIO_NOWRITE, PIO_NOERR use pio, only : pio_seterrorhandling, PIO_BCAST_ERROR, pio_closefile - use phys_grid, only : get_ncols_p, get_rlon_all_p, get_rlat_all_p + use phys_grid, only : get_ncols_p, get_rlon_all_p, get_rlat_all_p use interpolate_data, only : lininterp_init, lininterp, interp_type, lininterp_finish use mo_constants, only : pi @@ -162,19 +162,19 @@ subroutine ocean_emis_init() real(r8), allocatable :: file_lats(:), file_lons(:) real(r8), allocatable :: wrk2d(:,:) real(r8) :: to_lats(pcols), to_lons(pcols) - type(interp_type) :: lon_wgts, lat_wgts + type(interp_type) :: lon_wgts, lat_wgts real(r8), parameter :: zero=0_r8, twopi=2_r8*pi, degs2rads = pi/180._r8 character(len=*), parameter :: subname = 'ocean_emis_init' - + if (trim(ocean_salinity_file) == 'NONE') return call getfil( ocean_salinity_file, filen, 0 ) call cam_pio_openfile( fid, filen, PIO_NOWRITE) - + call pio_seterrorhandling(fid, PIO_BCAST_ERROR) - + ierr = pio_inq_dimid( fid, 'lon', dimid ) if (ierr /= PIO_NOERR) then call endrun(subname//': pio_inq_dimid lon FAILED') @@ -225,6 +225,7 @@ subroutine ocean_emis_init() endif allocate(salinity(pcols,begchunk:endchunk)) + salinity = 0._r8 do c=begchunk,endchunk @@ -235,17 +236,22 @@ subroutine ocean_emis_init() call lininterp_init(file_lons, file_nlon, to_lons, ncols, 2, lon_wgts, zero, twopi) call lininterp_init(file_lats, file_nlat, to_lats, ncols, 1, lat_wgts) - call lininterp(wrk2d, file_nlon, file_nlat, salinity(1:ncols,c), ncols, lon_wgts, lat_wgts) + call lininterp(wrk2d, file_nlon, file_nlat, salinity(1:ncols,c), ncols, lon_wgts, lat_wgts) call lininterp_finish(lon_wgts) call lininterp_finish(lat_wgts) end do + ! fill in missing values with climatology for modern-day + where(salinity < 0._r8) + salinity = 33.0_r8 + end where + deallocate( file_lons, file_lats ) deallocate( wrk2d ) - call addfld('OCN_SALINITY', horiz_only, 'A', 'parts per thousands', 'ocean salinity' ) + call addfld('OCN_SALINITY', horiz_only, 'A', 'parts per thousands', 'ocean salinity' ) ! ====================================================== ! initializing the libraries for the air-sea flux module @@ -253,17 +259,17 @@ subroutine ocean_emis_init() Call CmpLibInitialization() Call SaltLibInitialization() - ! --------------------------------------------- + ! --------------------------------------------- ! Read seawater concentration: WSY ! --------------------------------------------- call cseawater_ini() call pio_closefile (fid) - + end subroutine ocean_emis_init -!-------------------------------------------------------------------------------- -!-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- subroutine ocean_emis_advance( pbuf2d, state ) ! ------------------------------- ! check serial case for time span @@ -274,7 +280,7 @@ subroutine ocean_emis_advance( pbuf2d, state ) use tracer_data, only : advance_trcdata use physics_buffer, only : physics_buffer_desc - type(physics_state), intent(in) :: state(begchunk:endchunk) + type(physics_state), intent(in) :: state(begchunk:endchunk) type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer :: m @@ -286,12 +292,12 @@ subroutine ocean_emis_advance( pbuf2d, state ) end subroutine ocean_emis_advance -!-------------------------------------------------------------------------------- -!-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- subroutine ocean_emis_getflux(lchnk, ncol, state, u10, sst, ocnfrac, icefrac, sflx) use physics_types, only : physics_state - use ppgrid, only : pver + use ppgrid, only : pver integer, intent(in) :: lchnk, ncol type(physics_state), target, intent(in) :: state ! Physics state variables @@ -301,13 +307,13 @@ subroutine ocean_emis_getflux(lchnk, ncol, state, u10, sst, ocnfrac, icefrac, sf real(r8), intent(in) :: icefrac(:) ! Ice fraction real(r8), intent(inout) :: sflx(:,:) ! Surface emissions (kg/m^2/s) - integer :: m, isec, SpeciesID - real(r8) :: Csw_col(ncol) - real(r8) :: MW_species - real(r8) :: oceanflux_kg_m2_s(ncol) + integer :: i, m, isec, SpeciesID + real(r8) :: Csw_col(ncol) + real(r8) :: MW_species + real(r8) :: oceanflux_kg_m2_s(ncol) if (trim(ocean_salinity_file) == 'NONE') return - + ! ================================================== ! Get seawater concentrations and calculate the flux ! ================================================== @@ -317,28 +323,30 @@ subroutine ocean_emis_getflux(lchnk, ncol, state, u10, sst, ocnfrac, icefrac, sf isec = 1 Csw_col(:ncol) = Csw_nM(m)%scalefactor*Csw_nM(m)%fields(isec)%data(:ncol,1,lchnk) - MW_species = MolecularWeight(SpeciesIndex( Csw_nM(m)%species )) + MW_species = MolecularWeight(SpeciesIndex( Csw_nM(m)%species )) call cnst_get_ind( trim(Csw_nM(m)%species), SpeciesID, abort=.true. ) oceanflux_kg_m2_s = 0.0_r8 - where (ocnfrac(:ncol) >= 0.2_r8 .and. Csw_col(:ncol) >= 0._r8) ! calculate flux only for ocean - oceanflux_kg_m2_s(:ncol) = Flux_kg_m2_s( & - Csw_nM(m)%species, & ! name of species - state%q(:ncol,pver,SpeciesID) * (28.97_r8/MW_species) * 1.0e+12_r8, & ! air concentration (ppt) - Csw_col(:ncol), & ! sea water concentration (nM) - state%t(:ncol,pver), & ! air temperature (K) - u10(:ncol), & ! wind speed at 10m (m/s) <- should use this - state%ps(:ncol) / 101325.0_r8, & ! surface pressure (atm) - sst(:ncol), & ! sea surface temperautre (K) - salinity(:ncol,lchnk), & ! ocean salinity (parts per thousands) - switch_bubble, & ! bubble-mediated transfer: on or off - ncol ) - end where + do i = 1,ncol + if (ocnfrac(i) >= 0.2_r8 .and. Csw_col(i) >= 0._r8) then + ! calculate flux only for ocean + oceanflux_kg_m2_s(i) = Flux_kg_m2_s( & + Csw_nM(m)%species, & ! name of species + state%q(i,pver,SpeciesID) * (28.97_r8/MW_species) * 1.0e+12_r8, & ! air concentration (ppt) + Csw_col(i), & ! sea water concentration (nM) + state%t(i,pver), & ! air temperature (K) + u10(i), & ! wind speed at 10m (m/s) <- should use this + state%ps(i) / 101325.0_r8, & ! surface pressure (atm) + sst(i), & ! sea surface temperautre (K) + salinity(i,lchnk), & ! ocean salinity (parts per thousands) + switch_bubble ) ! bubble-mediated transfer: on or off + end if + end do ! =========================================================================== - ! Add the ocean flux to the other fluxes + ! Add the ocean flux to the other fluxes ! Make sure this ocean module is called after other surface emissions are set ! =========================================================================== sflx(:ncol,SpeciesID) = sflx(:ncol,SpeciesID) + oceanflux_kg_m2_s(:ncol) * ocnfrac(:ncol) @@ -355,10 +363,8 @@ subroutine ocean_emis_getflux(lchnk, ncol, state, u10, sst, ocnfrac, icefrac, sf end subroutine ocean_emis_getflux - -!-------------------------------------------------------------------------------- -!-------------------------------------------------------------------------------- - + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- Subroutine CmpLibInitialization() ! ===================================================================================== ! This is the lookup table for molecular weight, Vb, and Henry's law constant @@ -377,7 +383,7 @@ Subroutine CmpLibInitialization() GasList(2) = GasLib('C2H5OH', (/ 46.07_r8, 2.0_r8, 6.0_r8, 0.0_r8, 1.0_r8, 0.0_r8, 0.0_r8, & 0.0_r8, 0.0_r8, 0.0_r8, 0.0_r8, 0.0_r8, 0.0_r8, 0.0_r8, 190.0_r8, 6500.0_r8 /)) GasList(3) = GasLib('CH2O', (/ 30.03_r8, 1.0_r8, 2.0_r8, 0.0_r8, 1.0_r8, 0.0_r8, 0.0_r8, & - 0.0_r8, 0.0_r8, 0.0_r8, 1.0_r8, 0.0_r8, 0.0_r8, 0.0_r8, 3230.0_r8, 7100.0_r8 /)) + 0.0_r8, 0.0_r8, 0.0_r8, 1.0_r8, 0.0_r8, 0.0_r8, 0.0_r8, 3230.0_r8, 7100.0_r8 /)) GasList(4) = GasLib('CH3CHO', (/ 44.05_r8, 2.0_r8, 4.0_r8, 0.0_r8, 1.0_r8, 0.0_r8, 0.0_r8, & 0.0_r8, 0.0_r8, 0.0_r8, 1.0_r8, 0.0_r8, 0.0_r8, 0.0_r8, 12.9_r8, 5890.0_r8/)) GasList(5) = GasLib('PROPANAL', (/ 58.08_r8, 3.0_r8, 6.0_r8, 0.0_r8, 1.0_r8, 0.0_r8, 0.0_r8, & @@ -409,10 +415,12 @@ Subroutine CmpLibInitialization() ! -------------------------------------------------------------------------------- End Subroutine CmpLibInitialization + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- Subroutine SaltLibInitialization() ! ================================================================================ - ! This is the lookup table for common solutes in seawater and the parameters to - ! calculate the dynamic viscosity of seawater. + ! This is the lookup table for common solutes in seawater and the parameters to + ! calculate the dynamic viscosity of seawater. ! You may add other solutes or change the mass fractions. ! -------------------------------------------------------------------------------- ! Col 1: mass fraction of solute @@ -431,6 +439,8 @@ Subroutine SaltLibInitialization() ! --------------------------------------------- End Subroutine SaltLibInitialization + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- Function SpeciesIndex(SpeciesName) ! ============================================== ! This function is to look for the species index @@ -439,7 +449,7 @@ Function SpeciesIndex(SpeciesName) Character(Len=16) :: SpeciesName SpeciesIndex = -1 ! return -1 if species is not found - + Do i = 1, HowManyMolecules If (trim(SpeciesName) == trim(GasList(i)%CmpdName)) Then SpeciesIndex = i @@ -448,13 +458,15 @@ Function SpeciesIndex(SpeciesName) End Do End Function SpeciesIndex - Function Flux_kg_m2_s(SpeciesName,Cgas_ppt,Cwater_nM,T_air_K,u10_m_s,P_atm,T_water_K,& - Salinity_PartsPerThousand,switch_bubble,ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function Flux_kg_m2_s(SpeciesName,Cgas_ppt,Cwater_nM,T_air_K,u10_m_s,P_atm,T_water_K,& + Salinity_PartsPerThousand,switch_bubble) ! =========================================================================== ! This is the main module function. Input variables: ! --------------------------------------------------------------------------- ! - SpeciesName: name of species - ! - Cgas_ppt: mixing ratio (parts per trillion) of trace gas of interest + ! - Cgas_ppt: mixing ratio (parts per trillion) of trace gas of interest ! in the gas-phase (lowest modeling layer) ! - Cwater_nM: concentration of trace gas of interest in the surface ocean ! - T_air_K: temperature in the lowest modeling layer @@ -463,52 +475,51 @@ Function Flux_kg_m2_s(SpeciesName,Cgas_ppt,Cwater_nM,T_air_K,u10_m_s,P_atm,T_wat ! - T_water_K: sea surface temperature ! - Salinity_PartsPerThousand: surface ocean salinity ! - switch_bubble: bubble-mediated transfer switch - ! All must be 1D arrays with same dimension(ncol, so CESM-compatible) ! =========================================================================== - Integer :: ncol, SpeciesID - Character(16) :: SpeciesName - Real(r8), Dimension(ncol) :: Flux_kg_m2_s - Real(r8), Dimension(ncol) :: Cgas_ppt, Cwater_nM, T_air_K, u10_m_s, P_atm, T_water_K, Salinity_PartsPerThousand - Real(r8), Dimension(ncol) :: H_gas_over_liquid_dimless, kt_m_s - Logical :: switch_bubble + Character(16),intent(in) :: SpeciesName + Real(r8),intent(in) :: Cgas_ppt, Cwater_nM, T_air_K, u10_m_s, P_atm, T_water_K, Salinity_PartsPerThousand + Logical ,intent(in) :: switch_bubble - where(Salinity_PartsPerThousand .lt. 0.0_r8) Salinity_PartsPerThousand = 33.0_r8 + Integer :: SpeciesID + Real(r8) :: H_gas_over_liquid_dimless, kt_m_s - SpeciesID = SpeciesIndex(SpeciesName) - H_gas_over_liquid_dimless = 1.0_r8/(Henry_M_atm(SpeciesID,T_water_K,Salinity_PartsPerThousand,ncol)*& + SpeciesID = SpeciesIndex(SpeciesName) + H_gas_over_liquid_dimless = 1.0_r8/(Henry_M_atm(SpeciesID,T_water_K,Salinity_PartsPerThousand)*& 0.082_r8*T_water_K) If (switch_bubble) then ! -------------------------------------------------------- ! k_water parameterization with bubble-induced enhancement ! -------------------------------------------------------- kt_m_s = (1.0_r8/k_water_m_s_bubble(SpeciesID, T_water_K, Salinity_PartsPerThousand, & - u10_m_s, Cgas_ppt, P_atm, T_air_K, ncol) & - + 1.0_r8/k_air_m_s(SpeciesID, u10_m_s, T_air_K, P_atm, ncol)& + u10_m_s, Cgas_ppt, P_atm, T_air_K) & + + 1.0_r8/k_air_m_s(SpeciesID, u10_m_s, T_air_K, P_atm)& /H_gas_over_liquid_dimless)**(-1.0_r8) else ! ------------------------------------------------ ! Original k_water parameterization, scaled to CO2 ! ------------------------------------------------ - kt_m_s = (1.0_r8/k_water_m_s(SpeciesID, T_water_K, Salinity_PartsPerThousand, u10_m_s, ncol) & - + 1.0_r8/k_air_m_s(SpeciesID, u10_m_s, T_air_K, P_atm, ncol)/H_gas_over_liquid_dimless)**(-1.0_r8) + kt_m_s = (1.0_r8/k_water_m_s(SpeciesID, T_water_K, Salinity_PartsPerThousand, u10_m_s) & + + 1.0_r8/k_air_m_s(SpeciesID, u10_m_s, T_air_K, P_atm)/H_gas_over_liquid_dimless)**(-1.0_r8) endif Flux_kg_m2_s = kt_m_s * (Cwater_nM*1E-9_r8*1000.0_r8 & - Cgas_ppt*1E-12_r8*(101325.0_r8*P_atm)/8.314_r8/T_air_K/H_gas_over_liquid_dimless) & ! g/m2/s * MolecularWeight(SpeciesIndex(SpeciesName)) / 1000.0_r8 ! convert to kg/m2/s End Function Flux_kg_m2_s - - Function k_air_m_s(SpeciesIndex, u10_m_s, T_air_K, P_atm, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function k_air_m_s(SpeciesIndex, u10_m_s, T_air_K, P_atm) use shr_const_mod, only: vonKarman=>SHR_CONST_KARMAN ! ============================================================================= - ! Air-side transfer velocity. Slightly modified NOAA COARE (Fairall et al 2003; - ! Feffery et al 2010), as recommended by Johnson Ocean Sci. 2010. + ! Air-side transfer velocity. Slightly modified NOAA COARE (Fairall et al 2003; + ! Feffery et al 2010), as recommended by Johnson Ocean Sci. 2010. ! Dynamic viscosity of air: Tsilingiris 2008 ! ============================================================================= - Integer :: ncol, SpeciesIndex - Real(r8), Dimension(ncol) :: k_air_m_s - Real(r8), Dimension(ncol) :: u10_m_s, T_air_K, P_atm, ustar_m_s, DragCoeff - Real(r8), Dimension(ncol) :: DynamicViscosityAir_kg_m_s, DensityAir_kg_m3, DiffusivityInAir, SchmidtNumberInAir + Integer ,intent(in) :: SpeciesIndex + Real(r8),intent(in) :: u10_m_s, T_air_K, P_atm + + Real(r8) :: ustar_m_s, DragCoeff + Real(r8) :: DynamicViscosityAir_kg_m_s, DensityAir_kg_m3, DiffusivityInAir, SchmidtNumberInAir ! WSY: If local friction velocity is available from the model, might as well use that? ustar_m_s = u10_m_s * sqrt(6.1E-4_r8 + 6.3E-5_r8 * u10_m_s) @@ -516,53 +527,53 @@ Function k_air_m_s(SpeciesIndex, u10_m_s, T_air_K, P_atm, ncol) DynamicViscosityAir_kg_m_s = 1.715747771E-5_r8 + 4.722402075E-8_r8 * (T_air_K-273.15_r8) & - 3.663027156E-10_r8 * ((T_air_K-273.15_r8)**2.0_r8) & + 1.873236686E-12_r8 * ((T_air_K-273.15_r8)**3.0_r8) & - - 8.050218737E-14_r8 * ((T_air_K-273.15_r8)**4.0_r8) + - 8.050218737E-14_r8 * ((T_air_K-273.15_r8)**4.0_r8) DensityAir_kg_m3 = 1.293393662_r8 - 5.538444326e-3_r8 * (T_air_K-273.15_r8) & + 3.860201577e-5_r8 * (T_air_K-273.15_r8)**2.0_r8 & - 5.2536065e-7_r8 * (T_air_K-273.15_r8)**3.0_r8 - DiffusivityInAir = DiffusivityInAir_cm2_s(SpeciesIndex, T_air_K, P_atm, ncol) - SchmidtNumberInAir = DynamicViscosityAir_kg_m_s / DensityAir_kg_m3 / (DiffusivityInAir/10000.0_r8) + DiffusivityInAir = DiffusivityInAir_cm2_s(SpeciesIndex, T_air_K, P_atm) + SchmidtNumberInAir = DynamicViscosityAir_kg_m_s / DensityAir_kg_m3 / (DiffusivityInAir/10000.0_r8) k_air_m_s = 1E-3_r8 + ustar_m_s / (13.3_r8*(SchmidtNumberInAir**0.5_r8)+(DragCoeff**(-0.5_r8))-& 5.0_r8+log(SchmidtNumberInAir)/2.0_r8/vonKarman) End Function k_air_m_s - - - - Function k_water_m_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, u10_m_s, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function k_water_m_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, u10_m_s) ! ================================================================================ ! Water-side transfer velocity. Ref: Nightingale et al (2000). Salinity considered ! ================================================================================ - Integer :: ncol, SpeciesIndex - Real(r8), Dimension(ncol) :: k_water_m_s - Real(r8), Dimension(ncol) :: T_water_K, Salinity_PartsPerThousand, u10_m_s - Real(r8), Dimension(ncol) :: DiffusivityInWater, SchmidtNumberInWater - Real(r8) :: SchmidtNumberInWater_CO2ref + Integer ,intent(in) :: SpeciesIndex + Real(r8),intent(in) :: T_water_K, Salinity_PartsPerThousand, u10_m_s + + Real(r8) :: DiffusivityInWater, SchmidtNumberInWater + Real(r8) :: SchmidtNumberInWater_CO2ref + SchmidtNumberInWater_CO2ref = 660.0_r8 ! this is the Schmidt number of CO2 at 20 degC in fresh water - DiffusivityInWater = DiffusivityInWater_cm2_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, ncol) - SchmidtNumberInWater = DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand, ncol) / 1000.0_r8 & - / DensityWater_kg_m3(T_water_K,Salinity_PartsPerThousand,ncol)/(DiffusivityInWater/10000.0_r8) + DiffusivityInWater = DiffusivityInWater_cm2_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand) + SchmidtNumberInWater = DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand) / 1000.0_r8 & + / DensityWater_kg_m3(T_water_K,Salinity_PartsPerThousand)/(DiffusivityInWater/10000.0_r8) k_water_m_s = ((0.222_r8*(u10_m_s**2.0_r8)+0.333_r8*u10_m_s)*& ((SchmidtNumberInWater/SchmidtNumberInWater_CO2ref)**(-0.5_r8)))/360000.0_r8 End Function k_water_m_s - - - - Function k_water_m_s_bubble(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, u10_m_s, Cgas_ppt, P_atm, T_air_K, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function k_water_m_s_bubble(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, u10_m_s, Cgas_ppt, P_atm, T_air_K) ! ============================================================== ! Water-side transfer velocity. Ref: Asher and Wanninkhof (1998). ! ============================================================== - Integer :: ncol, SpeciesIndex - Real(r8), Dimension(ncol) :: k_water_m_s_bubble - Real(r8), Dimension(ncol) :: T_water_K, Salinity_PartsPerThousand, u10_m_s, Cgas_ppt, P_atm, T_air_K - Real(r8), Dimension(ncol) :: DiffusivityInWater, SchmidtNumberInWater - Real(r8), Dimension(ncol) :: FracCoverage_WhiteCaps, OstwaldSolubilityCoefficient - DiffusivityInWater = DiffusivityInWater_cm2_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, ncol) - SchmidtNumberInWater = DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand, ncol) / 1000.0_r8 & - / DensityWater_kg_m3(T_water_K,Salinity_PartsPerThousand,ncol)/(DiffusivityInWater/10000.0_r8) - FracCoverage_WhiteCaps = 2.56e-6_r8 * (u10_m_s - 1.77_r8)**3.0_r8 - OstwaldSolubilityCoefficient = Henry_M_atm(SpeciesIndex,T_water_K,Salinity_PartsPerThousand,ncol) ! just Henry's law (M/atm) + Integer, intent(in) :: SpeciesIndex + Real(r8),intent(in) :: T_water_K, Salinity_PartsPerThousand, u10_m_s, Cgas_ppt, P_atm, T_air_K + + Real(r8) :: DiffusivityInWater, SchmidtNumberInWater + Real(r8) :: FracCoverage_WhiteCaps, OstwaldSolubilityCoefficient + + DiffusivityInWater = DiffusivityInWater_cm2_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand) + SchmidtNumberInWater = DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand) / 1000.0_r8 & + / DensityWater_kg_m3(T_water_K,Salinity_PartsPerThousand)/(DiffusivityInWater/10000.0_r8) + FracCoverage_WhiteCaps = 2.56e-6_r8 * (u10_m_s - 1.77_r8)**3.0_r8 + OstwaldSolubilityCoefficient = Henry_M_atm(SpeciesIndex,T_water_K,Salinity_PartsPerThousand) ! just Henry's law (M/atm) OstwaldSolubilityCoefficient = OstwaldSolubilityCoefficient * (Cgas_ppt*1.0E-12_r8*P_atm) ! mol / L OstwaldSolubilityCoefficient = OstwaldSolubilityCoefficient * 0.082_r8 * T_air_K / P_atm ! L / L k_water_m_s_bubble = ((47.0_r8*u10_m_s + FracCoverage_WhiteCaps*(115200.0_r8 - 47.0_r8* u10_m_s)) & @@ -570,40 +581,46 @@ Function k_water_m_s_bubble(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, + FracCoverage_WhiteCaps * (-37.0_r8/OstwaldSolubilityCoefficient & + 6120.0_r8*(OstwaldSolubilityCoefficient**(-0.37_r8)) *(SchmidtNumberInWater**(-0.18_r8)))) & * 2.8e-6_r8 - End Function k_water_m_s_bubble - - + End Function k_water_m_s_bubble - Function DiffusivityInAir_cm2_s(SpeciesIndex, T_air_K, P_atm, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function DiffusivityInAir_cm2_s(SpeciesIndex, T_air_K, P_atm) ! ============================ ! Ref: Johnson Ocean Sci. 2010 ! ============================ - Integer :: ncol, SpeciesIndex - Real(r8), Dimension(ncol) :: DiffusivityInAir_cm2_s, T_air_K, P_atm + Integer ,intent(in) :: SpeciesIndex + Real(r8),intent(in) :: T_air_K, P_atm + Real(r8), parameter :: MW_air = 28.97_r8 ! molecular weight for air Real(r8), parameter :: Va = 20.1_r8 ! molar volume for air Real(r8) :: Vb, MW_species + Vb = LiquidMolarVolume_cm3_mol(SpeciesIndex) MW_species = MolecularWeight(SpeciesIndex) DiffusivityInAir_cm2_s = 0.001_r8 * (T_air_K**1.75_r8) & ! oh f* me * (((MW_air + MW_species)/(MW_air*MW_species))**0.5_r8) & / ((P_atm*(Va**(1.0_r8/3.0_r8)+Vb**(1.0_r8/3.0_r8)))**2.0_r8) - End Function DiffusivityInAir_cm2_s - + End Function DiffusivityInAir_cm2_s - Function DiffusivityInWater_cm2_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function DiffusivityInWater_cm2_s(SpeciesIndex, T_water_K, Salinity_PartsPerThousand) ! ================================================= ! Ref: Johnson Ocean Sci. 2010. Salinity considered ! ================================================= - Integer :: ncol, SpeciesIndex - Real(r8), Dimension(ncol) :: DiffusivityInWater_cm2_s, DynamicViscosityWater, T_water_K, Salinity_PartsPerThousand + Integer, intent(in) :: SpeciesIndex + Real(r8),intent(in) :: T_water_K, Salinity_PartsPerThousand + Real(r8), parameter :: AssociationFactor = 2.6_r8 ! ... for water - Real(r8) :: Vb, MW_species + Real(r8) :: DynamicViscosityWater, Vb, MW_species + Vb = LiquidMolarVolume_cm3_mol(SpeciesIndex) MW_species = MolecularWeight(SpeciesIndex) - DynamicViscosityWater = DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand, ncol) + + DynamicViscosityWater = DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand) ! ------------------------------------------------- ! Wilke and Chang 1955: this seems to be a bit high ! ------------------------------------------------- @@ -617,47 +634,51 @@ Function DiffusivityInWater_cm2_s(SpeciesIndex, T_water_K, Salinity_PartsPerThou End Function DiffusivityInWater_cm2_s - - Function DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function DynamicViscosityWater_g_m_s(T_water_K, Salinity_PartsPerThousand) ! ================================================= ! Ref: Johnson Ocean Sci. 2010. Salinity considered ! ================================================= - Integer :: ncol - Real(r8), Dimension(ncol) :: DynamicViscosityWater_g_m_s, T_water_K, Salinity_PartsPerThousand - Real(r8), Dimension(ncol) :: MassFrac_water, DynamicViscosityPureWater_g_m_s, SaltViscosity, sum_w_ln_SaltViscosity - Integer :: j, n + Real(r8),intent(in) :: T_water_K, Salinity_PartsPerThousand + + Real(r8) :: MassFrac_water, DynamicViscosityPureWater_g_m_s, SaltViscosity, sum_w_ln_SaltViscosity + Integer :: n + sum_w_ln_SaltViscosity = 0.0_r8 MassFrac_water = 1.0_r8 - Salinity_PartsPerThousand / 1000.0_r8 DynamicViscosityPureWater_g_m_s = ((T_water_K-273.15_r8)+246.0_r8) & - / (0.05594_r8*(T_water_K-273.15_r8)**2.0_r8+5.2842_r8*(T_water_K-273.15_r8)+137.37_r8) - Do j = 1, ncol - If (Salinity_PartsPerThousand(j) == 0.0_r8) Then ! pure water - DynamicViscosityWater_g_m_s(j) = DynamicViscosityPureWater_g_m_s(j) + / (0.05594_r8*(T_water_K-273.15_r8)**2.0_r8+5.2842_r8*(T_water_K-273.15_r8)+137.37_r8) + + If (Salinity_PartsPerThousand == 0.0_r8) Then ! pure water + DynamicViscosityWater_g_m_s = DynamicViscosityPureWater_g_m_s Else ! salty water Do n = 1, HowManySalts - SaltViscosity(j) = exp((SaltList(n)%SaltProperties(2) * & - (Salinity_PartsPerThousand(j)/1000.0_r8)**SaltList(n)%SaltProperties(3) & + SaltViscosity = exp((SaltList(n)%SaltProperties(2) * & + (Salinity_PartsPerThousand/1000.0_r8)**SaltList(n)%SaltProperties(3) & + SaltList(n)%SaltProperties(4)) & - / (SaltList(n)%SaltProperties(5)*(T_water_K(j)-273.15_r8) + 1.0_r8)) & - / (SaltList(n)%SaltProperties(6) * (Salinity_PartsPerThousand(j) / & + / (SaltList(n)%SaltProperties(5)*(T_water_K-273.15_r8) + 1.0_r8)) & + / (SaltList(n)%SaltProperties(6) * (Salinity_PartsPerThousand / & 1000.0_r8)**SaltList(n)%SaltProperties(7) + 1.0_r8) - sum_w_ln_SaltViscosity(j) = sum_w_ln_SaltViscosity(j) + (Salinity_PartsPerThousand(j)/1000.0_r8) & - * SaltList(n)%SaltProperties(1) * log(SaltViscosity(j)) + sum_w_ln_SaltViscosity = sum_w_ln_SaltViscosity + (Salinity_PartsPerThousand/1000.0_r8) & + * SaltList(n)%SaltProperties(1) * log(SaltViscosity) End Do - DynamicViscosityWater_g_m_s(j) = exp(MassFrac_water(j) & - * log(DynamicViscosityPureWater_g_m_s(j)) + sum_w_ln_SaltViscosity(j)) + DynamicViscosityWater_g_m_s = exp(MassFrac_water & + * log(DynamicViscosityPureWater_g_m_s) + sum_w_ln_SaltViscosity) Endif - End Do - End Function DynamicViscosityWater_g_m_s + End Function DynamicViscosityWater_g_m_s - Function DensityWater_kg_m3(T_water_K, Salinity_PartsPerThousand, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function DensityWater_kg_m3(T_water_K, Salinity_PartsPerThousand) ! ==================================================== ! Ref: Millero and Poisson (1981). Salinity considered ! ==================================================== - Integer :: ncol - Real(r8), Dimension(ncol) :: DensityWater_kg_m3, T_water_K, Salinity_PartsPerThousand - Real(r8), Dimension(ncol) :: DensityPureWater_kg_m3, FactorA, FactorB, FactorC + Real(r8), intent(in) :: T_water_K, Salinity_PartsPerThousand + + Real(r8) :: DensityPureWater_kg_m3, FactorA, FactorB, FactorC + DensityPureWater_kg_m3 = 999.842594_r8 + 0.06793952_r8*(T_water_K-273.15_r8) & - 0.00909529_r8*((T_water_K-273.15_r8)**2.0_r8) & + 0.0001001685_r8*((T_water_K-273.15_r8)**3.0_r8) & @@ -669,41 +690,46 @@ Function DensityWater_kg_m3(T_water_K, Salinity_PartsPerThousand, ncol) FactorC = 0.00048314_r8 DensityWater_kg_m3 = DensityPureWater_kg_m3 + FactorA*Salinity_PartsPerThousand & + FactorB*(Salinity_PartsPerThousand**(2.0_r8/3.0_r8)) + FactorC*Salinity_PartsPerThousand - End Function DensityWater_kg_m3 + End Function DensityWater_kg_m3 - Function Henry_M_atm(SpeciesIndex, T_water_K, Salinity_PartsPerThousand, ncol) + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- + Real(r8) Function Henry_M_atm(SpeciesIndex, T_water_K, Salinity_PartsPerThousand) ! ========================================================================================= ! Ref: Sander compilation 2015. Salt-in or salt-out estimated based on Setschenow constants ! ========================================================================================= - Integer :: ncol, j - Integer :: SpeciesIndex - Real(r8), Dimension(ncol) :: Henry_M_atm, T_water_K, Salinity_PartsPerThousand - Real(r8), Dimension(ncol) :: Heff_M_atm_PureWater, Setschenow, Heff_M_atm_SaltyWater + Integer, intent(in) :: SpeciesIndex + Real(r8), intent(in) :: T_water_K, Salinity_PartsPerThousand + + Real(r8) :: Heff_M_atm_PureWater, Setschenow, Heff_M_atm_SaltyWater + Heff_M_atm_PureWater = GasList(SpeciesIndex)%CmpdProperties(15) * & exp(GasList(SpeciesIndex)%CmpdProperties(16) * (1.0_r8/T_water_K - 1.0_r8/298.0_r8)) - Do j = 1, ncol - If (Salinity_PartsPerThousand(j)==0.0_r8) Then - Henry_M_atm(j) = Heff_M_atm_PureWater(j) - Else - Setschenow(j) = log(LiquidMolarVolume_cm3_mol(SpeciesIndex)) * & - (7.33532E-4_r8 + 3.39615E-5_r8 * log(Heff_M_atm_PureWater(j)) & - - 2.40888E-6_r8 * ((log(Heff_M_atm_PureWater(j)))**2.0_r8) & - + 1.57114E-7_r8 * ((log(Heff_M_atm_PureWater(j)))**3.0_r8)) - Heff_M_atm_SaltyWater(j) = Heff_M_atm_PureWater(j) * 10.0_r8**(Setschenow(j)*Salinity_PartsPerThousand(j)) - Henry_M_atm(j) = Heff_M_atm_SaltyWater(j) - Endif - End Do - End Function Henry_M_atm + If (Salinity_PartsPerThousand==0.0_r8) Then + Henry_M_atm = Heff_M_atm_PureWater + Else + Setschenow = log(LiquidMolarVolume_cm3_mol(SpeciesIndex)) * & + (7.33532E-4_r8 + 3.39615E-5_r8 * log(Heff_M_atm_PureWater) & + - 2.40888E-6_r8 * ((log(Heff_M_atm_PureWater))**2.0_r8) & + + 1.57114E-7_r8 * ((log(Heff_M_atm_PureWater))**3.0_r8)) + Heff_M_atm_SaltyWater = Heff_M_atm_PureWater * 10.0_r8**(Setschenow*Salinity_PartsPerThousand) + Henry_M_atm = Heff_M_atm_SaltyWater + Endif + + End Function Henry_M_atm + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- Function MolecularWeight(SpeciesIndex) Real(r8) :: MolecularWeight Integer :: SpeciesIndex MolecularWeight = GasList(SpeciesIndex)%CmpdProperties(1) End Function MolecularWeight - + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- Function LiquidMolarVolume_cm3_mol(SpeciesIndex) ! =========================================================================== ! If no measurements available, i.e. GasList(SpeciesIndex)%CmpdProperties(14) @@ -712,7 +738,7 @@ Function LiquidMolarVolume_cm3_mol(SpeciesIndex) Real(r8) :: LiquidMolarVolume_cm3_mol Integer :: SpeciesIndex - If (GasList(SpeciesIndex)%CmpdProperties(14)/=0.0_r8) Then + If (GasList(SpeciesIndex)%CmpdProperties(14)/=0.0_r8) Then LiquidMolarVolume_cm3_mol = GasList(SpeciesIndex)%CmpdProperties(14) Else LiquidMolarVolume_cm3_mol = 7.0_r8*GasList(SpeciesIndex)%CmpdProperties(2) ! C @@ -731,18 +757,20 @@ Function LiquidMolarVolume_cm3_mol(SpeciesIndex) End Function LiquidMolarVolume_cm3_mol + !-------------------------------------------------------------------------------- + !-------------------------------------------------------------------------------- subroutine cseawater_ini() - use mo_chem_utls, only : get_spc_ndx - use tracer_data, only : trcdata_init - use cam_pio_utils, only : cam_pio_openfile + use mo_chem_utls, only : get_spc_ndx + use tracer_data, only : trcdata_init + use cam_pio_utils, only : cam_pio_openfile use pio, only : pio_inquire, pio_nowrite, pio_closefile, pio_inq_varndims use pio, only : pio_inq_varname, file_desc_t, pio_get_att, PIO_NOERR, PIO_GLOBAL - use pio, only : pio_seterrorhandling, PIO_BCAST_ERROR - use string_utils, only : GLC + use pio, only : pio_seterrorhandling, PIO_BCAST_ERROR + use string_utils, only : GLC integer :: i, j, l, m, n, nn, astat, vid, ierr, nvars, isec - integer :: indx(gas_pcnst) + integer :: indx(gas_pcnst) type(file_desc_t) :: ncid character(len=16) :: csw_species(gas_pcnst) character(len=256) :: csw_filenam(gas_pcnst) @@ -766,7 +794,7 @@ subroutine cseawater_ini() character(len=*), parameter :: subname = 'cseawater_ini' - ! ======================================================== + ! ======================================================== ! Read sea water concentration specifier from the namelist ! ======================================================== @@ -827,7 +855,7 @@ subroutine cseawater_ini() ! ------------------------------------------- ! Setup the seawater concentration type array ! ------------------------------------------- - do m=1,n_Csw_files + do m=1,n_Csw_files Csw_nM(m)%spc_ndx = csw_indexes(indx(m)) Csw_nM(m)%units = 'nM' Csw_nM(m)%species = csw_species(indx(m)) @@ -898,9 +926,9 @@ subroutine cseawater_ini() deallocate(vndims) ! Global attribute 'input_method' overrides the srf_emis_type namelist setting on - ! a file-by-file basis. If the emis file does not contain the 'input_method' + ! a file-by-file basis. If the emis file does not contain the 'input_method' ! attribute then the srf_emis_type namelist setting is used. - ierr = pio_get_att(ncid, PIO_GLOBAL, 'input_method', file_interp_type) + ierr = pio_get_att(ncid, PIO_GLOBAL, 'input_method', file_interp_type) if ( ierr == PIO_NOERR) then l = GLC(file_interp_type) csw_time_type(1:l) = file_interp_type(1:l) @@ -932,5 +960,4 @@ subroutine cseawater_ini() end subroutine cseawater_ini - end module ocean_emis diff --git a/src/chemistry/mozart/tracer_cnst.F90 b/src/chemistry/mozart/tracer_cnst.F90 index 803e3e1061..9c51b6cec8 100644 --- a/src/chemistry/mozart/tracer_cnst.F90 +++ b/src/chemistry/mozart/tracer_cnst.F90 @@ -13,7 +13,7 @@ module tracer_cnst implicit none private ! all unless made public - save + save public :: tracer_cnst_init public :: num_tracer_cnst @@ -94,7 +94,7 @@ subroutine tracer_cnst_init() call addfld(trim(fields(i)%fldnam), (/ 'lev' /), & 'I','mol/mol', 'prescribed tracer constituent' ) - enddo + enddo allocate(data_q(pcols,pver,num_tracer_cnst,begchunk:endchunk), stat=istat) call handle_err(istat, 'tracer_cnst_init: ERROR allocating data_q') @@ -169,7 +169,7 @@ subroutine tracer_cnst_defaultopts( & tracer_cnst_cycle_yr_out, & tracer_cnst_fixed_ymd_out,& tracer_cnst_fixed_tod_out & - ) + ) implicit none @@ -231,7 +231,7 @@ subroutine tracer_cnst_adv( pbuf2d, state ) implicit none - type(physics_state), intent(in):: state(begchunk:endchunk) + type(physics_state), intent(in):: state(begchunk:endchunk) type(physics_buffer_desc), pointer :: pbuf2d(:,:) integer :: i,ind,c,ncol @@ -311,12 +311,13 @@ subroutine get_cnst_data_ptr(name, state, q, pbuf) integer :: lchnk integer :: ncol integer :: inv_id, idx + character(len=80) :: error_str lchnk = state%lchnk ncol = state%ncol ! make sure the requested constituent can be provided - inv_id = get_inv_ndx(name) + inv_id = get_inv_ndx(name) if (.not. inv_id > 0) then if (masterproc) then write(iulog,*) 'get_cnst_data_ptr: '//name//' is not a prescribed tracer constituent' @@ -326,6 +327,13 @@ subroutine get_cnst_data_ptr(name, state, q, pbuf) call get_fld_ndx( fields, name, idx ) + if (idx<1) then + write(error_str,*) 'get_cnst_data_ptr: ',trim(name),' not found ... idx : ',idx + if (masterproc) then + write(iulog,*) error_str + end if + call endrun(error_str) + end if call get_fld_data( fields, name, data_q(:,:,idx,lchnk), ncol, lchnk, pbuf ) data_q(:ncol,:,idx,lchnk) = data_q(:ncol,:,idx,lchnk)*fix_mass(inv_id)/mwdry ! vmr->mmr diff --git a/src/chemistry/pp_ghg_mam4/chem_mech.doc b/src/chemistry/pp_ghg_mam4/chem_mech.doc new file mode 100644 index 0000000000..5c976202f5 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/chem_mech.doc @@ -0,0 +1,161 @@ + + + Solution species + ( 1) bc_a1 (C) + ( 2) bc_a4 (C) + ( 3) CFC11 (CFCl3) + ( 4) CFC12 (CF2Cl2) + ( 5) CH4 + ( 6) CO2 + ( 7) DMS (CH3SCH3) + ( 8) dst_a1 (AlSiO5) + ( 9) dst_a2 (AlSiO5) + ( 10) dst_a3 (AlSiO5) + ( 11) H2O2 + ( 12) H2SO4 + ( 13) N2O + ( 14) ncl_a1 (NaCl) + ( 15) ncl_a2 (NaCl) + ( 16) ncl_a3 (NaCl) + ( 17) num_a1 (H) + ( 18) num_a2 (H) + ( 19) num_a3 (H) + ( 20) num_a4 (H) + ( 21) pom_a1 (C) + ( 22) pom_a4 (C) + ( 23) SO2 + ( 24) so4_a1 (NH4HSO4) + ( 25) so4_a2 (NH4HSO4) + ( 26) so4_a3 (NH4HSO4) + ( 27) soa_a1 (C) + ( 28) soa_a2 (C) + ( 29) SOAE (C) + ( 30) SOAG (C) + ( 31) H2O + + + Invariant species + ( 1) M + ( 2) O2 + ( 3) N2 + ( 4) HO2 + ( 5) OH + ( 6) NO3 + ( 7) O3 + ( 8) HALONS + + + Column integrals + ( 1) O3 - 0.000E+00 + ( 2) O2 - 0.000E+00 + +Class List +========== + Explicit + -------- + ( 1) CO2 + + Implicit + -------- + ( 1) bc_a1 + ( 2) bc_a4 + ( 3) CFC11 + ( 4) CFC12 + ( 5) CH4 + ( 6) DMS + ( 7) dst_a1 + ( 8) dst_a2 + ( 9) dst_a3 + ( 10) H2O2 + ( 11) H2SO4 + ( 12) N2O + ( 13) ncl_a1 + ( 14) ncl_a2 + ( 15) ncl_a3 + ( 16) num_a1 + ( 17) num_a2 + ( 18) num_a3 + ( 19) num_a4 + ( 20) pom_a1 + ( 21) pom_a4 + ( 22) SO2 + ( 23) so4_a1 + ( 24) so4_a2 + ( 25) so4_a3 + ( 26) soa_a1 + ( 27) soa_a2 + ( 28) SOAE + ( 29) SOAG + ( 30) H2O + + Photolysis + jh2o2 ( 1) H2O2 + hv -> 2*OH rate = ** User defined ** ( 1) + jsoa_a1 ( 2) soa_a1 + hv -> (No products) rate = ** User defined ** ( 2) + jsoa_a2 ( 3) soa_a2 + hv -> (No products) rate = ** User defined ** ( 3) + + Reactions + lyman_alpha ( 1) H2O -> (No products) rate = ** User defined ** ( 4) + OH_H2O2 ( 2) OH + H2O2 -> H2O + HO2 rate = 1.80E-12 ( 5) + usr_HO2_HO2 ( 3) HO2 + HO2 -> H2O2 + O2 rate = ** User defined ** ( 6) + n2o_loss ( 4) N2O -> (No products) rate = ** User defined ** ( 7) + cfc11_loss ( 5) CFC11 -> (No products) rate = ** User defined ** ( 8) + cfc12_loss ( 6) CFC12 -> (No products) rate = ** User defined ** ( 9) + ch4_loss ( 7) CH4 -> 2*H2O rate = ** User defined ** ( 10) + DMS_NO3 ( 8) DMS + NO3 -> SO2 + {HNO3} rate = 1.90E-13*exp( 520./t) ( 11) + DMS_OHa ( 9) DMS + OH -> SO2 rate = 1.10E-11*exp( -280./t) ( 12) + SO2_OH_M ( 10) SO2 + OH + M -> H2SO4 troe : ko=2.90E-31*(300/t)**4.10 ( 13) + ki=1.70E-12*(300/t)**-0.20 + f=0.60 + usr_DMS_OH ( 11) DMS + OH -> 0.5*SO2 + 0.5*HO2 rate = ** User defined ** ( 14) + SOAE_tau ( 12) SOAE -> SOAG rate = 1.16E-05 ( 15) + +Extraneous prod/loss species + ( 1) bc_a1 (dataset) + ( 2) bc_a4 (dataset) + ( 3) H2O (dataset) + ( 4) num_a1 (dataset) + ( 5) num_a2 (dataset) + ( 6) num_a4 (dataset) + ( 7) pom_a1 (dataset) + ( 8) pom_a4 (dataset) + ( 9) SO2 (dataset) + (10) so4_a1 (dataset) + (11) so4_a2 (dataset) + + + Equation Report + + d(bc_a1)/dt = 0 + d(bc_a4)/dt = 0 + d(CFC11)/dt = - r5*CFC11 + d(CFC12)/dt = - r6*CFC12 + d(CH4)/dt = - r7*CH4 + d(CO2)/dt = 0 + d(DMS)/dt = - r8*NO3*DMS - r9*OH*DMS - r11*OH*DMS + d(dst_a1)/dt = 0 + d(dst_a2)/dt = 0 + d(dst_a3)/dt = 0 + d(H2O2)/dt = r3 + - j1*H2O2 - r2*OH*H2O2 + d(H2SO4)/dt = r10*OH*M*SO2 + d(N2O)/dt = - r4*N2O + d(ncl_a1)/dt = 0 + d(ncl_a2)/dt = 0 + d(ncl_a3)/dt = 0 + d(num_a1)/dt = 0 + d(num_a2)/dt = 0 + d(num_a3)/dt = 0 + d(num_a4)/dt = 0 + d(pom_a1)/dt = 0 + d(pom_a4)/dt = 0 + d(SO2)/dt = r8*NO3*DMS + r9*OH*DMS + .5*r11*OH*DMS + - r10*OH*M*SO2 + d(so4_a1)/dt = 0 + d(so4_a2)/dt = 0 + d(so4_a3)/dt = 0 + d(soa_a1)/dt = - j2*soa_a1 + d(soa_a2)/dt = - j3*soa_a2 + d(SOAE)/dt = - r12*SOAE + d(SOAG)/dt = r12*SOAE + d(H2O)/dt = r2*OH*H2O2 + 2*r7*CH4 + - r1*H2O diff --git a/src/chemistry/pp_ghg_mam4/chem_mech.in b/src/chemistry/pp_ghg_mam4/chem_mech.in new file mode 100644 index 0000000000..2d0365a8a5 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/chem_mech.in @@ -0,0 +1,179 @@ +* Comments +* User-given Tag Description: WACCM_SC_MAM4 +* Tag database identifier : MZ312_WACCM_SC_MAM4_20221214 +* Tag created by : lke +* Tag created from branch : WACCM_SC_MAM4 +* Tag created on : 2022-12-14 15:17:17.723566-07 +* Comments for this tag follow: +* lke : 2022-12-14 : Specified chemistry (SC) WACCM mechanism, with updated simple SOA. +* fvitt : 2023-03-17 : Copied from waccm_sc_mam4 to ghg_mam4 and add CO2 for CAM7 prognostic GHGs + + SPECIES + + Solution + bc_a1 -> C, + bc_a4 -> C, + CFC11 -> CFCl3, + CFC12 -> CF2Cl2, + CH4, + CO2, + DMS -> CH3SCH3, + dst_a1 -> AlSiO5, + dst_a2 -> AlSiO5, + dst_a3 -> AlSiO5, + H2O2, + H2SO4, + N2O, + ncl_a1 -> NaCl, + ncl_a2 -> NaCl, + ncl_a3 -> NaCl, + num_a1 -> H, + num_a2 -> H, + num_a3 -> H, + num_a4 -> H, + pom_a1 -> C, + pom_a4 -> C, + SO2, + so4_a1 -> NH4HSO4, + so4_a2 -> NH4HSO4, + so4_a3 -> NH4HSO4, + soa_a1 -> C, + soa_a2 -> C, + SOAE -> C, + SOAG -> C, + H2O + End Solution + + + Fixed + M, O2, N2, HO2, OH, NO3, O3, HALONS->CFCl3 + End Fixed + + Col-int + O3 = 0. + O2 = 0. + End Col-int + + Not-Transported + + End Not-Transported + + END Species + + + Solution classes + Explicit + CO2 + End Explicit + + Implicit + bc_a1 + bc_a4 + CFC11 + CFC12 + CH4 + DMS + dst_a1 + dst_a2 + dst_a3 + H2O2 + H2SO4 + N2O + ncl_a1 + ncl_a2 + ncl_a3 + num_a1 + num_a2 + num_a3 + num_a4 + pom_a1 + pom_a4 + SO2 + so4_a1 + so4_a2 + so4_a3 + soa_a1 + soa_a2 + SOAE + SOAG + H2O + End Implicit + + End Solution classes + + + CHEMISTRY + Photolysis +********************************* +*** odd-oxygen +********************************* +[jh2o2] H2O2 + hv -> 2*OH +********************************* +*** soa +********************************* +[jsoa_a1->,.0004*jno2] soa_a1 + hv -> +[jsoa_a2->,.0004*jno2] soa_a2 + hv -> + End Photolysis + + Reactions +********************************* +*** odd-hydrogen +********************************* +[lyman_alpha] H2O -> +[OH_H2O2] OH + H2O2 -> H2O + HO2 ; 1.8e-12 +[usr_HO2_HO2] HO2 + HO2 -> H2O2 + O2 +********************************* +*** odd-nitrogen +********************************* +[n2o_loss] N2O -> +********************************* +*** odd-chlorine +********************************* +[cfc11_loss] CFC11 -> +[cfc12_loss] CFC12 -> +********************************* +*** C1 +********************************* +[ch4_loss] CH4 -> 2*H2O +********************************* +*** Sulfur +********************************* +[DMS_NO3] DMS + NO3 -> SO2 + HNO3 ; 1.9e-13, 520 +[DMS_OHa] DMS + OH -> SO2 ; 1.1e-11, -280 +[SO2_OH_M] SO2 + OH + M -> H2SO4 ; 2.9e-31, 4.1, 1.7e-12, -0.2, 0.6 +[usr_DMS_OH] DMS + OH -> 0.5*SO2 + 0.5*HO2 +********************************* +*** SOA +********************************* +[SOAE_tau] SOAE -> SOAG ; 1.157e-05 + End Reactions + + Ext Forcing + bc_a1 <- dataset + bc_a4 <- dataset + H2O <- dataset + num_a1 <- dataset + num_a2 <- dataset + num_a4 <- dataset + pom_a1 <- dataset + pom_a4 <- dataset + SO2 <- dataset + so4_a1 <- dataset + so4_a2 <- dataset + End Ext Forcing + + End Chemistry + +SIMULATION PARAMETERS + + Version Options + model = cam + machine = intel + architecture = hybrid + vec_ftns = on + multitask = on + namemod = on + modules = on + End Version Options + +End Simulation Parameters diff --git a/src/chemistry/pp_ghg_mam4/chem_mods.F90 b/src/chemistry/pp_ghg_mam4/chem_mods.F90 new file mode 100644 index 0000000000..a6f3071ca0 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/chem_mods.F90 @@ -0,0 +1,50 @@ + module chem_mods +!-------------------------------------------------------------- +! ... Basic chemistry parameters and arrays +!-------------------------------------------------------------- + use shr_kind_mod, only : r8 => shr_kind_r8 + implicit none + save + integer, parameter :: phtcnt = 3, & ! number of photolysis reactions + rxntot = 15, & ! number of total reactions + gascnt = 12, & ! number of gas phase reactions + nabscol = 2, & ! number of absorbing column densities + gas_pcnst = 31, & ! number of "gas phase" species + nfs = 8, & ! number of "fixed" species + relcnt = 0, & ! number of relationship species + grpcnt = 0, & ! number of group members + nzcnt = 35, & ! number of non-zero matrix entries + extcnt = 11, & ! number of species with external forcing + clscnt1 = 1, & ! number of species in explicit class + clscnt2 = 0, & ! number of species in hov class + clscnt3 = 0, & ! number of species in ebi class + clscnt4 = 30, & ! number of species in implicit class + clscnt5 = 0, & ! number of species in rodas class + indexm = 1, & ! index of total atm density in invariant array + indexh2o = 0, & ! index of water vapor density + clsze = 1, & ! loop length for implicit chemistry + rxt_tag_cnt = 15, & + enthalpy_cnt = 0, & + nslvd = 0 + integer :: clscnt(5) = 0 + integer :: cls_rxt_cnt(4,5) = 0 + integer :: clsmap(gas_pcnst,5) = 0 + integer :: permute(gas_pcnst,5) = 0 + integer :: diag_map(clscnt4) = 0 + real(r8) :: adv_mass(gas_pcnst) = 0._r8 + real(r8) :: crb_mass(gas_pcnst) = 0._r8 + real(r8) :: fix_mass(max(1,nfs)) + real(r8), allocatable :: cph_enthalpy(:) + integer, allocatable :: cph_rid(:) + integer, allocatable :: num_rnts(:) + integer, allocatable :: rxt_tag_map(:) + real(r8), allocatable :: pht_alias_mult(:,:) + character(len=32), allocatable :: rxt_tag_lst(:) + character(len=16), allocatable :: pht_alias_lst(:,:) + character(len=16) :: inv_lst(max(1,nfs)) + character(len=16) :: extfrc_lst(max(1,extcnt)) + logical :: frc_from_dataset(max(1,extcnt)) + logical :: is_vector + logical :: is_scalar + character(len=16) :: slvd_lst(max(1,nslvd)) + end module chem_mods diff --git a/src/chemistry/pp_ghg_mam4/m_rxt_id.F90 b/src/chemistry/pp_ghg_mam4/m_rxt_id.F90 new file mode 100644 index 0000000000..2c6a0ed8db --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/m_rxt_id.F90 @@ -0,0 +1,18 @@ + module m_rxt_id + implicit none + integer, parameter :: rid_jh2o2 = 1 + integer, parameter :: rid_jsoa_a1 = 2 + integer, parameter :: rid_jsoa_a2 = 3 + integer, parameter :: rid_lyman_alpha = 4 + integer, parameter :: rid_OH_H2O2 = 5 + integer, parameter :: rid_usr_HO2_HO2 = 6 + integer, parameter :: rid_n2o_loss = 7 + integer, parameter :: rid_cfc11_loss = 8 + integer, parameter :: rid_cfc12_loss = 9 + integer, parameter :: rid_ch4_loss = 10 + integer, parameter :: rid_DMS_NO3 = 11 + integer, parameter :: rid_DMS_OHa = 12 + integer, parameter :: rid_SO2_OH_M = 13 + integer, parameter :: rid_usr_DMS_OH = 14 + integer, parameter :: rid_SOAE_tau = 15 + end module m_rxt_id diff --git a/src/chemistry/pp_ghg_mam4/m_spc_id.F90 b/src/chemistry/pp_ghg_mam4/m_spc_id.F90 new file mode 100644 index 0000000000..c4bfbe7ef3 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/m_spc_id.F90 @@ -0,0 +1,34 @@ + module m_spc_id + implicit none + integer, parameter :: id_bc_a1 = 1 + integer, parameter :: id_bc_a4 = 2 + integer, parameter :: id_CFC11 = 3 + integer, parameter :: id_CFC12 = 4 + integer, parameter :: id_CH4 = 5 + integer, parameter :: id_CO2 = 6 + integer, parameter :: id_DMS = 7 + integer, parameter :: id_dst_a1 = 8 + integer, parameter :: id_dst_a2 = 9 + integer, parameter :: id_dst_a3 = 10 + integer, parameter :: id_H2O2 = 11 + integer, parameter :: id_H2SO4 = 12 + integer, parameter :: id_N2O = 13 + integer, parameter :: id_ncl_a1 = 14 + integer, parameter :: id_ncl_a2 = 15 + integer, parameter :: id_ncl_a3 = 16 + integer, parameter :: id_num_a1 = 17 + integer, parameter :: id_num_a2 = 18 + integer, parameter :: id_num_a3 = 19 + integer, parameter :: id_num_a4 = 20 + integer, parameter :: id_pom_a1 = 21 + integer, parameter :: id_pom_a4 = 22 + integer, parameter :: id_SO2 = 23 + integer, parameter :: id_so4_a1 = 24 + integer, parameter :: id_so4_a2 = 25 + integer, parameter :: id_so4_a3 = 26 + integer, parameter :: id_soa_a1 = 27 + integer, parameter :: id_soa_a2 = 28 + integer, parameter :: id_SOAE = 29 + integer, parameter :: id_SOAG = 30 + integer, parameter :: id_H2O = 31 + end module m_spc_id diff --git a/src/chemistry/pp_ghg_mam4/mo_adjrxt.F90 b/src/chemistry/pp_ghg_mam4/mo_adjrxt.F90 new file mode 100644 index 0000000000..09ad314f66 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_adjrxt.F90 @@ -0,0 +1,28 @@ + module mo_adjrxt + private + public :: adjrxt + contains + subroutine adjrxt( rate, inv, m, ncol, nlev ) + use shr_kind_mod, only : r8 => shr_kind_r8 + use chem_mods, only : nfs, rxntot + implicit none +!-------------------------------------------------------------------- +! ... dummy arguments +!-------------------------------------------------------------------- + integer, intent(in) :: ncol, nlev + real(r8), intent(in) :: inv(ncol,nlev,nfs) + real(r8), intent(in) :: m(ncol,nlev) + real(r8), intent(inout) :: rate(ncol,nlev,rxntot) +!-------------------------------------------------------------------- +! ... local variables +!-------------------------------------------------------------------- + real(r8) :: im(ncol,nlev) + im(:,:) = 1._r8 / m(:,:) + rate(:,:, 5) = rate(:,:, 5) * inv(:,:, 5) + rate(:,:, 11) = rate(:,:, 11) * inv(:,:, 6) + rate(:,:, 12) = rate(:,:, 12) * inv(:,:, 5) + rate(:,:, 14) = rate(:,:, 14) * inv(:,:, 5) + rate(:,:, 6) = rate(:,:, 6) * inv(:,:, 4) * inv(:,:, 4) * im(:,:) + rate(:,:, 13) = rate(:,:, 13) * inv(:,:, 5) * inv(:,:, 1) + end subroutine adjrxt + end module mo_adjrxt diff --git a/src/chemistry/pp_ghg_mam4/mo_exp_sol.F90 b/src/chemistry/pp_ghg_mam4/mo_exp_sol.F90 new file mode 100644 index 0000000000..cfde22391a --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_exp_sol.F90 @@ -0,0 +1,79 @@ +module mo_exp_sol + private + public :: exp_sol + public :: exp_sol_inti +contains + subroutine exp_sol_inti + use mo_tracname, only : solsym + use chem_mods, only : clscnt1, clsmap + use ppgrid, only : pver + use cam_history, only : addfld + implicit none + integer :: i,j + do i = 1,clscnt1 + j = clsmap(i,1) + call addfld( trim(solsym(j))//'_CHMP', (/ 'lev' /), 'I', '/cm3/s', 'chemical production rate' ) + call addfld( trim(solsym(j))//'_CHML', (/ 'lev' /), 'I', '/cm3/s', 'chemical loss rate' ) + enddo + end subroutine exp_sol_inti + subroutine exp_sol( base_sol, reaction_rates, het_rates, extfrc, delt, xhnm, ncol, lchnk, ltrop ) + !----------------------------------------------------------------------- + ! ... Exp_sol advances the volumetric mixing ratio + ! forward one time step via the fully explicit + ! Euler scheme + !----------------------------------------------------------------------- + use chem_mods, only : clscnt1, extcnt, gas_pcnst, clsmap, rxntot + use ppgrid, only : pcols, pver + use mo_prod_loss, only : exp_prod_loss + use mo_indprd, only : indprd + use shr_kind_mod, only : r8 => shr_kind_r8 + use cam_history, only : outfld + use mo_tracname, only : solsym + implicit none + !----------------------------------------------------------------------- + ! ... Dummy arguments + !----------------------------------------------------------------------- + integer, intent(in) :: ncol ! columns in chunck + integer, intent(in) :: lchnk ! chunk id + real(r8), intent(in) :: delt ! time step (s) + real(r8), intent(in) :: het_rates(ncol,pver,max(1,gas_pcnst)) ! het rates (1/cm^3/s) + real(r8), intent(in) :: reaction_rates(ncol,pver,rxntot) ! rxt rates (1/cm^3/s) + real(r8), intent(in) :: extfrc(ncol,pver,extcnt) ! "external insitu forcing" (1/cm^3/s) + real(r8), intent(in) :: xhnm(ncol,pver) + integer, intent(in) :: ltrop(pcols) ! chemistry troposphere boundary (index) + real(r8), intent(inout) :: base_sol(ncol,pver,gas_pcnst) ! working mixing ratios (vmr) + !----------------------------------------------------------------------- + ! ... Local variables + !----------------------------------------------------------------------- + integer :: i, k, l, m + real(r8), dimension(ncol,pver,clscnt1) :: & + prod, & + loss, & + ind_prd + real(r8), dimension(ncol,pver) :: wrk + !----------------------------------------------------------------------- + ! ... Put "independent" production in the forcing + !----------------------------------------------------------------------- + call indprd( 1, ind_prd, clscnt1, base_sol, extfrc, & + reaction_rates, ncol ) + !----------------------------------------------------------------------- + ! ... Form F(y) + !----------------------------------------------------------------------- + call exp_prod_loss( prod, loss, base_sol, reaction_rates, het_rates ) + !----------------------------------------------------------------------- + ! ... Solve for the mixing ratio at t(n+1) + !----------------------------------------------------------------------- + do m = 1,clscnt1 + l = clsmap(m,1) + do i = 1,ncol + do k = ltrop(i)+1,pver + base_sol(i,k,l) = base_sol(i,k,l) + delt * (prod(i,k,m) + ind_prd(i,k,m) - loss(i,k,m)) + end do + end do + wrk(:,:) = (prod(:,:,m) + ind_prd(:,:,m))*xhnm + call outfld( trim(solsym(l))//'_CHMP', wrk(:,:), ncol, lchnk ) + wrk(:,:) = (loss(:,:,m))*xhnm + call outfld( trim(solsym(l))//'_CHML', wrk(:,:), ncol, lchnk ) + end do + end subroutine exp_sol +end module mo_exp_sol diff --git a/src/chemistry/pp_ghg_mam4/mo_imp_sol.F90 b/src/chemistry/pp_ghg_mam4/mo_imp_sol.F90 new file mode 100644 index 0000000000..d885728ba4 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_imp_sol.F90 @@ -0,0 +1,392 @@ +module mo_imp_sol + use shr_kind_mod, only : r8 => shr_kind_r8 + use chem_mods, only : clscnt4, gas_pcnst, clsmap + use cam_logfile, only : iulog + implicit none + private + public :: imp_slv_inti, imp_sol + save + real(r8), parameter :: rel_err = 1.e-3_r8 + real(r8), parameter :: high_rel_err = 1.e-4_r8 + !----------------------------------------------------------------------- + ! Newton-Raphson iteration limits + !----------------------------------------------------------------------- + integer, parameter :: itermax = 11 + integer, parameter :: cut_limit = 5 + real(r8), parameter :: small = 1.e-40_r8 + real(r8) :: epsilon(clscnt4) + logical :: factor(itermax) +contains + subroutine imp_slv_inti + !----------------------------------------------------------------------- + ! ... Initialize the implict solver + !----------------------------------------------------------------------- + use mo_chem_utls, only : get_spc_ndx + implicit none + !----------------------------------------------------------------------- + ! ... Local variables + !----------------------------------------------------------------------- + integer :: m, ox_ndx, o3a_ndx + real(r8) :: eps(gas_pcnst) + factor(:) = .true. + eps(:) = rel_err + ox_ndx = get_spc_ndx( 'OX' ) + if( ox_ndx < 1 ) then + ox_ndx = get_spc_ndx( 'O3' ) + end if + if( ox_ndx > 0 ) then + eps(ox_ndx) = high_rel_err + end if + m = get_spc_ndx( 'NO' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'NO2' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'NO3' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'HNO3' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'HO2NO2' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'N2O5' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'OH' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'HO2' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + o3a_ndx = get_spc_ndx( 'O3A' ) + if( o3a_ndx > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'XNO' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'XNO2' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'XNO3' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'XHNO3' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'XHO2NO2' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'XNO2NO3' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + m = get_spc_ndx( 'NO2XNO3' ) + if( m > 0 ) then + eps(m) = high_rel_err + end if + do m = 1,clscnt4 + epsilon(m) = eps(clsmap(m,4)) + end do + end subroutine imp_slv_inti + subroutine imp_sol( base_sol, reaction_rates, het_rates, extfrc, delt, & + ncol,nlev, lchnk, prod_out, loss_out ) + !----------------------------------------------------------------------- + ! ... imp_sol advances the volumetric mixing ratio + ! forward one time step via the fully implicit euler scheme. + ! this source is meant for small l1 cache machines such as + ! the intel pentium and itanium cpus + !----------------------------------------------------------------------- + use chem_mods, only : rxntot, extcnt, nzcnt, permute, cls_rxt_cnt + use mo_tracname, only : solsym + use mo_lin_matrix, only : linmat + use mo_nln_matrix, only : nlnmat + use mo_lu_factor, only : lu_fac + use mo_lu_solve, only : lu_slv + use mo_prod_loss, only : imp_prod_loss + use mo_indprd, only : indprd + use time_manager, only : get_nstep + use perf_mod, only : t_startf, t_stopf + implicit none + !----------------------------------------------------------------------- + ! ... dummy args + !----------------------------------------------------------------------- + integer, intent(in) :: ncol ! columns in chunck + integer, intent(in) :: nlev + integer, intent(in) :: lchnk ! chunk id + real(r8), intent(in) :: delt ! time step (s) + real(r8), intent(in) :: reaction_rates(ncol,nlev,max(1,rxntot)) ! rxt rates (1/cm^3/s) + real(r8), intent(in) :: extfrc(ncol,nlev,max(1,extcnt)) ! external in-situ forcing (1/cm^3/s) + real(r8), intent(in) :: het_rates(ncol,nlev,max(1,gas_pcnst)) ! washout rates (1/s) + real(r8), intent(inout) :: base_sol(ncol,nlev,gas_pcnst) ! species mixing ratios (vmr) + real(r8), intent(out) :: prod_out(ncol,nlev,max(1,clscnt4)) + real(r8), intent(out) :: loss_out(ncol,nlev,max(1,clscnt4)) + !----------------------------------------------------------------------- + ! ... local variables + !----------------------------------------------------------------------- + integer :: nr_iter, & + lev, & + i, & + j, & + k, l, & + m + integer :: fail_cnt, cut_cnt, stp_con_cnt + integer :: nstep + real(r8) :: interval_done, dt, dti + real(r8) :: max_delta(max(1,clscnt4)) + real(r8) :: sys_jac(max(1,nzcnt)) + real(r8) :: lin_jac(max(1,nzcnt)) + real(r8), dimension(max(1,clscnt4)) :: & + solution, & + forcing, & + iter_invariant, & + prod, & + loss + real(r8) :: lrxt(max(1,rxntot)) + real(r8) :: lsol(max(1,gas_pcnst)) + real(r8) :: lhet(max(1,gas_pcnst)) + real(r8), dimension(ncol,nlev,max(1,clscnt4)) :: & + ind_prd + logical :: convergence + logical :: frc_mask, iter_conv + logical :: converged(max(1,clscnt4)) + solution(:) = 0._r8 + !----------------------------------------------------------------------- + ! ... class independent forcing + !----------------------------------------------------------------------- + if( cls_rxt_cnt(1,4) > 0 .or. extcnt > 0 ) then + call indprd( 4, ind_prd, clscnt4, base_sol, extfrc, & + reaction_rates, ncol ) + else + do m = 1,max(1,clscnt4) + ind_prd(:,:,m) = 0._r8 + end do + end if + level_loop : do lev = 1,nlev + column_loop : do i = 1,ncol + !----------------------------------------------------------------------- + ! ... transfer from base to local work arrays + !----------------------------------------------------------------------- + do m = 1,rxntot + lrxt(m) = reaction_rates(i,lev,m) + end do + if( gas_pcnst > 0 ) then + do m = 1,gas_pcnst + lhet(m) = het_rates(i,lev,m) + end do + end if + !----------------------------------------------------------------------- + ! ... time step loop + !----------------------------------------------------------------------- + dt = delt + cut_cnt = 0 + fail_cnt = 0 + stp_con_cnt = 0 + interval_done = 0._r8 + time_step_loop : do + dti = 1._r8 / dt + !----------------------------------------------------------------------- + ! ... transfer from base to local work arrays + !----------------------------------------------------------------------- + do m = 1,gas_pcnst + lsol(m) = base_sol(i,lev,m) + end do + !----------------------------------------------------------------------- + ! ... transfer from base to class array + !----------------------------------------------------------------------- + do k = 1,clscnt4 + j = clsmap(k,4) + m = permute(k,4) + solution(m) = lsol(j) + end do + !----------------------------------------------------------------------- + ! ... set the iteration invariant part of the function f(y) + !----------------------------------------------------------------------- + if( cls_rxt_cnt(1,4) > 0 .or. extcnt > 0 ) then + do m = 1,clscnt4 + iter_invariant(m) = dti * solution(m) + ind_prd(i,lev,m) + end do + else + do m = 1,clscnt4 + iter_invariant(m) = dti * solution(m) + end do + end if + !----------------------------------------------------------------------- + ! ... the linear component + !----------------------------------------------------------------------- + if( cls_rxt_cnt(2,4) > 0 ) then + call t_startf( 'lin_mat' ) + call linmat( lin_jac, lsol, lrxt, lhet ) + call t_stopf( 'lin_mat' ) + end if + !======================================================================= + ! the newton-raphson iteration for f(y) = 0 + !======================================================================= + iter_loop : do nr_iter = 1,itermax + !----------------------------------------------------------------------- + ! ... the non-linear component + !----------------------------------------------------------------------- + if( factor(nr_iter) ) then + call t_startf( 'nln_mat' ) + call nlnmat( sys_jac, lsol, lrxt, lin_jac, dti ) + call t_stopf( 'nln_mat' ) + !----------------------------------------------------------------------- + ! ... factor the "system" matrix + !----------------------------------------------------------------------- + call t_startf( 'lu_fac' ) + call lu_fac( sys_jac ) + call t_stopf( 'lu_fac' ) + end if + !----------------------------------------------------------------------- + ! ... form f(y) + !----------------------------------------------------------------------- + call t_startf( 'prod_loss' ) + call imp_prod_loss( prod, loss, lsol, lrxt, lhet ) + call t_stopf( 'prod_loss' ) + do m = 1,clscnt4 + forcing(m) = solution(m)*dti - (iter_invariant(m) + prod(m) - loss(m)) + end do + !----------------------------------------------------------------------- + ! ... solve for the mixing ratio at t(n+1) + !----------------------------------------------------------------------- + call t_startf( 'lu_slv' ) + call lu_slv( sys_jac, forcing ) + call t_stopf( 'lu_slv' ) + do m = 1,clscnt4 + solution(m) = solution(m) + forcing(m) + end do + !----------------------------------------------------------------------- + ! ... convergence measures + !----------------------------------------------------------------------- + if( nr_iter > 1 ) then + do k = 1,clscnt4 + m = permute(k,4) + if( abs(solution(m)) > 1.e-20_r8 ) then + max_delta(k) = abs( forcing(m)/solution(m) ) + else + max_delta(k) = 0._r8 + end if + end do + end if + !----------------------------------------------------------------------- + ! ... limit iterate + !----------------------------------------------------------------------- + where( solution(:) < 0._r8 ) + solution(:) = 0._r8 + endwhere + !----------------------------------------------------------------------- + ! ... transfer latest solution back to work array + !----------------------------------------------------------------------- + do k = 1,clscnt4 + j = clsmap(k,4) + m = permute(k,4) + lsol(j) = solution(m) + end do + !----------------------------------------------------------------------- + ! ... check for convergence + !----------------------------------------------------------------------- + converged(:) = .true. + if( nr_iter > 1 ) then + do k = 1,clscnt4 + m = permute(k,4) + frc_mask = abs( forcing(m) ) > small + if( frc_mask ) then + converged(k) = abs(forcing(m)) <= epsilon(k)*abs(solution(m)) + else + converged(k) = .true. + end if + end do + convergence = all( converged(:) ) + if( convergence ) then + exit + end if + end if + end do iter_loop + !----------------------------------------------------------------------- + ! ... check for newton-raphson convergence + !----------------------------------------------------------------------- + if( .not. convergence ) then + !----------------------------------------------------------------------- + ! ... non-convergence + !----------------------------------------------------------------------- + fail_cnt = fail_cnt + 1 + nstep = get_nstep() + write(iulog,'('' imp_sol: Time step '',1p,e21.13,'' failed to converge @ (lchnk,lev,col,nstep) = '',4i6)') & + dt,lchnk,lev,i,nstep + stp_con_cnt = 0 + if( cut_cnt < cut_limit ) then + cut_cnt = cut_cnt + 1 + if( cut_cnt < cut_limit ) then + dt = .5_r8 * dt + else + dt = .1_r8 * dt + end if + cycle time_step_loop + else + write(iulog,'('' imp_sol: Failed to converge @ (lchnk,lev,col,nstep,dt,time) = '',4i6,1p,2e21.13)') & + lchnk,lev,i,nstep,dt,interval_done+dt + do m = 1,clscnt4 + if( .not. converged(m) ) then + write(iulog,'(1x,a8,1x,1pe10.3)') solsym(clsmap(m,4)), max_delta(m) + end if + end do + end if + end if + !----------------------------------------------------------------------- + ! ... check for interval done + !----------------------------------------------------------------------- + interval_done = interval_done + dt + if( abs( delt - interval_done ) <= .0001_r8 ) then + if( fail_cnt > 0 ) then + write(iulog,*) 'imp_sol : @ (lchnk,lev,col) = ',lchnk,lev,i,' failed ',fail_cnt,' times' + end if + exit time_step_loop + else + !----------------------------------------------------------------------- + ! ... transfer latest solution back to base array + !----------------------------------------------------------------------- + if( convergence ) then + stp_con_cnt = stp_con_cnt + 1 + end if + do m = 1,gas_pcnst + base_sol(i,lev,m) = lsol(m) + end do + if( stp_con_cnt >= 2 ) then + dt = 2._r8*dt + stp_con_cnt = 0 + end if + dt = min( dt,delt-interval_done ) + ! write(iulog,'('' imp_sol: New time step '',1p,e21.13)') dt + end if + end do time_step_loop + !----------------------------------------------------------------------- + ! ... Transfer latest solution back to base array + !----------------------------------------------------------------------- + cls_loop: do k = 1,clscnt4 + j = clsmap(k,4) + m = permute(k,4) + base_sol(i,lev,j) = solution(m) + ! output diagnostics + prod_out(i,lev,k) = prod(k) + ind_prd(i,lev,k) + loss_out(i,lev,k) = loss(k) + end do cls_loop + end do column_loop + end do level_loop + end subroutine imp_sol +end module mo_imp_sol diff --git a/src/chemistry/pp_ghg_mam4/mo_indprd.F90 b/src/chemistry/pp_ghg_mam4/mo_indprd.F90 new file mode 100644 index 0000000000..6906fcf304 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_indprd.F90 @@ -0,0 +1,61 @@ + module mo_indprd + use shr_kind_mod, only : r8 => shr_kind_r8 + private + public :: indprd + contains + subroutine indprd( class, prod, nprod, y, extfrc, rxt, ncol ) + use chem_mods, only : gas_pcnst, extcnt, rxntot + use ppgrid, only : pver + implicit none +!-------------------------------------------------------------------- +! ... dummy arguments +!-------------------------------------------------------------------- + integer, intent(in) :: class + integer, intent(in) :: ncol + integer, intent(in) :: nprod + real(r8), intent(in) :: y(ncol,pver,gas_pcnst) + real(r8), intent(in) :: rxt(ncol,pver,rxntot) + real(r8), intent(in) :: extfrc(ncol,pver,extcnt) + real(r8), intent(inout) :: prod(ncol,pver,nprod) +!-------------------------------------------------------------------- +! ... "independent" production for Explicit species +!-------------------------------------------------------------------- + if( class == 1 ) then + prod(:,:,1) = 0._r8 +!-------------------------------------------------------------------- +! ... "independent" production for Implicit species +!-------------------------------------------------------------------- + else if( class == 4 ) then + prod(:,:,1) = + extfrc(:,:,1) + prod(:,:,2) = + extfrc(:,:,2) + prod(:,:,3) = 0._r8 + prod(:,:,4) = 0._r8 + prod(:,:,5) = 0._r8 + prod(:,:,6) = 0._r8 + prod(:,:,7) = 0._r8 + prod(:,:,8) = 0._r8 + prod(:,:,9) = 0._r8 + prod(:,:,10) =rxt(:,:,6) + prod(:,:,11) = 0._r8 + prod(:,:,12) = 0._r8 + prod(:,:,13) = 0._r8 + prod(:,:,14) = 0._r8 + prod(:,:,15) = 0._r8 + prod(:,:,16) = + extfrc(:,:,4) + prod(:,:,17) = + extfrc(:,:,5) + prod(:,:,18) = 0._r8 + prod(:,:,19) = + extfrc(:,:,6) + prod(:,:,20) = + extfrc(:,:,7) + prod(:,:,21) = + extfrc(:,:,8) + prod(:,:,22) = + extfrc(:,:,9) + prod(:,:,23) = + extfrc(:,:,10) + prod(:,:,24) = + extfrc(:,:,11) + prod(:,:,25) = 0._r8 + prod(:,:,26) = 0._r8 + prod(:,:,27) = 0._r8 + prod(:,:,28) = 0._r8 + prod(:,:,29) = 0._r8 + prod(:,:,30) = + extfrc(:,:,3) + end if + end subroutine indprd + end module mo_indprd diff --git a/src/chemistry/pp_ghg_mam4/mo_lin_matrix.F90 b/src/chemistry/pp_ghg_mam4/mo_lin_matrix.F90 new file mode 100644 index 0000000000..7b32b664f5 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_lin_matrix.F90 @@ -0,0 +1,71 @@ + module mo_lin_matrix + private + public :: linmat + contains + subroutine linmat01( mat, y, rxt, het_rates ) +!---------------------------------------------- +! ... linear matrix entries for implicit species +!---------------------------------------------- + use chem_mods, only : gas_pcnst, rxntot, nzcnt + use shr_kind_mod, only : r8 => shr_kind_r8 + implicit none +!---------------------------------------------- +! ... dummy arguments +!---------------------------------------------- + real(r8), intent(in) :: y(gas_pcnst) + real(r8), intent(in) :: rxt(rxntot) + real(r8), intent(in) :: het_rates(max(1,gas_pcnst)) + real(r8), intent(inout) :: mat(nzcnt) + mat(1) = -( het_rates(1) ) + mat(2) = -( het_rates(2) ) + mat(3) = -( rxt(8) + het_rates(3) ) + mat(4) = -( rxt(9) + het_rates(4) ) + mat(5) = -( rxt(10) + het_rates(5) ) + mat(7) = -( rxt(11) + rxt(12) + rxt(14) + het_rates(7) ) + mat(9) = -( het_rates(8) ) + mat(10) = -( het_rates(9) ) + mat(11) = -( het_rates(10) ) + mat(12) = -( rxt(1) + rxt(5) + het_rates(11) ) + mat(14) = -( het_rates(12) ) + mat(25) = rxt(13) + mat(15) = -( rxt(7) + het_rates(13) ) + mat(16) = -( het_rates(14) ) + mat(17) = -( het_rates(15) ) + mat(18) = -( het_rates(16) ) + mat(19) = -( het_rates(17) ) + mat(20) = -( het_rates(18) ) + mat(21) = -( het_rates(19) ) + mat(22) = -( het_rates(20) ) + mat(23) = -( het_rates(21) ) + mat(24) = -( het_rates(22) ) + mat(26) = -( rxt(13) + het_rates(23) ) + mat(8) = rxt(11) + rxt(12) + .500_r8*rxt(14) + mat(27) = -( het_rates(24) ) + mat(28) = -( het_rates(25) ) + mat(29) = -( het_rates(26) ) + mat(30) = -( rxt(2) + het_rates(27) ) + mat(31) = -( rxt(3) + het_rates(28) ) + mat(32) = -( rxt(15) + het_rates(29) ) + mat(34) = -( het_rates(30) ) + mat(33) = rxt(15) + mat(35) = -( rxt(4) + het_rates(31) ) + mat(13) = rxt(5) + mat(6) = 2.000_r8*rxt(10) + end subroutine linmat01 + subroutine linmat( mat, y, rxt, het_rates ) +!---------------------------------------------- +! ... linear matrix entries for implicit species +!---------------------------------------------- + use chem_mods, only : gas_pcnst, rxntot, nzcnt + use shr_kind_mod, only : r8 => shr_kind_r8 + implicit none +!---------------------------------------------- +! ... dummy arguments +!---------------------------------------------- + real(r8), intent(in) :: y(gas_pcnst) + real(r8), intent(in) :: rxt(rxntot) + real(r8), intent(in) :: het_rates(max(1,gas_pcnst)) + real(r8), intent(inout) :: mat(nzcnt) + call linmat01( mat, y, rxt, het_rates ) + end subroutine linmat + end module mo_lin_matrix diff --git a/src/chemistry/pp_ghg_mam4/mo_lu_factor.F90 b/src/chemistry/pp_ghg_mam4/mo_lu_factor.F90 new file mode 100644 index 0000000000..d981e77137 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_lu_factor.F90 @@ -0,0 +1,56 @@ + module mo_lu_factor + private + public :: lu_fac + contains + subroutine lu_fac01( lu ) + use shr_kind_mod, only : r8 => shr_kind_r8 + implicit none +!----------------------------------------------------------------------- +! ... dummy args +!----------------------------------------------------------------------- + real(r8), intent(inout) :: lu(:) + lu(1) = 1._r8 / lu(1) + lu(2) = 1._r8 / lu(2) + lu(3) = 1._r8 / lu(3) + lu(4) = 1._r8 / lu(4) + lu(5) = 1._r8 / lu(5) + lu(6) = lu(6) * lu(5) + lu(7) = 1._r8 / lu(7) + lu(8) = lu(8) * lu(7) + lu(9) = 1._r8 / lu(9) + lu(10) = 1._r8 / lu(10) + lu(11) = 1._r8 / lu(11) + lu(12) = 1._r8 / lu(12) + lu(13) = lu(13) * lu(12) + lu(14) = 1._r8 / lu(14) + lu(15) = 1._r8 / lu(15) + lu(16) = 1._r8 / lu(16) + lu(17) = 1._r8 / lu(17) + lu(18) = 1._r8 / lu(18) + lu(19) = 1._r8 / lu(19) + lu(20) = 1._r8 / lu(20) + lu(21) = 1._r8 / lu(21) + lu(22) = 1._r8 / lu(22) + lu(23) = 1._r8 / lu(23) + lu(24) = 1._r8 / lu(24) + lu(26) = 1._r8 / lu(26) + lu(27) = 1._r8 / lu(27) + lu(28) = 1._r8 / lu(28) + lu(29) = 1._r8 / lu(29) + lu(30) = 1._r8 / lu(30) + lu(31) = 1._r8 / lu(31) + lu(32) = 1._r8 / lu(32) + lu(33) = lu(33) * lu(32) + lu(34) = 1._r8 / lu(34) + lu(35) = 1._r8 / lu(35) + end subroutine lu_fac01 + subroutine lu_fac( lu ) + use shr_kind_mod, only : r8 => shr_kind_r8 + implicit none +!----------------------------------------------------------------------- +! ... dummy args +!----------------------------------------------------------------------- + real(r8), intent(inout) :: lu(:) + call lu_fac01( lu ) + end subroutine lu_fac + end module mo_lu_factor diff --git a/src/chemistry/pp_ghg_mam4/mo_lu_solve.F90 b/src/chemistry/pp_ghg_mam4/mo_lu_solve.F90 new file mode 100644 index 0000000000..574861e9b1 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_lu_solve.F90 @@ -0,0 +1,87 @@ + module mo_lu_solve + private + public :: lu_slv + contains + subroutine lu_slv01( lu, b ) + use shr_kind_mod, only : r8 => shr_kind_r8 + use chem_mods, only : clscnt4, nzcnt + implicit none +!----------------------------------------------------------------------- +! ... Dummy args +!----------------------------------------------------------------------- + real(r8), intent(in) :: lu(:) + real(r8), intent(inout) :: b(:) +!----------------------------------------------------------------------- +! ... Local variables +!----------------------------------------------------------------------- +!----------------------------------------------------------------------- +! ... solve L * y = b +!----------------------------------------------------------------------- + b(30) = b(30) - lu(6) * b(5) + b(22) = b(22) - lu(8) * b(6) + b(30) = b(30) - lu(13) * b(10) + b(29) = b(29) - lu(33) * b(28) + end subroutine lu_slv01 + subroutine lu_slv02( lu, b ) + use shr_kind_mod, only : r8 => shr_kind_r8 + use chem_mods, only : clscnt4, nzcnt + implicit none +!----------------------------------------------------------------------- +! ... Dummy args +!----------------------------------------------------------------------- + real(r8), intent(in) :: lu(:) + real(r8), intent(inout) :: b(:) +!----------------------------------------------------------------------- +! ... Local variables +!----------------------------------------------------------------------- +!----------------------------------------------------------------------- +! ... solve L * y = b +!----------------------------------------------------------------------- +!----------------------------------------------------------------------- +! ... Solve U * x = y +!----------------------------------------------------------------------- + b(30) = b(30) * lu(35) + b(29) = b(29) * lu(34) + b(28) = b(28) * lu(32) + b(27) = b(27) * lu(31) + b(26) = b(26) * lu(30) + b(25) = b(25) * lu(29) + b(24) = b(24) * lu(28) + b(23) = b(23) * lu(27) + b(22) = b(22) * lu(26) + b(11) = b(11) - lu(25) * b(22) + b(21) = b(21) * lu(24) + b(20) = b(20) * lu(23) + b(19) = b(19) * lu(22) + b(18) = b(18) * lu(21) + b(17) = b(17) * lu(20) + b(16) = b(16) * lu(19) + b(15) = b(15) * lu(18) + b(14) = b(14) * lu(17) + b(13) = b(13) * lu(16) + b(12) = b(12) * lu(15) + b(11) = b(11) * lu(14) + b(10) = b(10) * lu(12) + b(9) = b(9) * lu(11) + b(8) = b(8) * lu(10) + b(7) = b(7) * lu(9) + b(6) = b(6) * lu(7) + b(5) = b(5) * lu(5) + b(4) = b(4) * lu(4) + b(3) = b(3) * lu(3) + b(2) = b(2) * lu(2) + b(1) = b(1) * lu(1) + end subroutine lu_slv02 + subroutine lu_slv( lu, b ) + use shr_kind_mod, only : r8 => shr_kind_r8 + use chem_mods, only : clscnt4, nzcnt + implicit none +!----------------------------------------------------------------------- +! ... Dummy args +!----------------------------------------------------------------------- + real(r8), intent(in) :: lu(:) + real(r8), intent(inout) :: b(:) + call lu_slv01( lu, b ) + call lu_slv02( lu, b ) + end subroutine lu_slv + end module mo_lu_solve diff --git a/src/chemistry/pp_ghg_mam4/mo_nln_matrix.F90 b/src/chemistry/pp_ghg_mam4/mo_nln_matrix.F90 new file mode 100644 index 0000000000..c48389b422 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_nln_matrix.F90 @@ -0,0 +1,100 @@ + module mo_nln_matrix + use shr_kind_mod, only : r8 => shr_kind_r8 + private + public :: nlnmat + contains + subroutine nlnmat( mat, y, rxt, lmat, dti ) + use chem_mods, only : gas_pcnst, rxntot, nzcnt + implicit none +!---------------------------------------------- +! ... dummy arguments +!---------------------------------------------- + real(r8), intent(in) :: dti + real(r8), intent(in) :: lmat(nzcnt) + real(r8), intent(in) :: y(gas_pcnst) + real(r8), intent(in) :: rxt(rxntot) + real(r8), intent(inout) :: mat(nzcnt) + call nlnmat_finit( mat, lmat, dti ) + end subroutine nlnmat + subroutine nlnmat_finit( mat, lmat, dti ) + use chem_mods, only : gas_pcnst, rxntot, nzcnt + implicit none +!---------------------------------------------- +! ... dummy arguments +!---------------------------------------------- + real(r8), intent(in) :: dti + real(r8), intent(in) :: lmat(nzcnt) + real(r8), intent(inout) :: mat(nzcnt) +!---------------------------------------------- +! ... local variables +!---------------------------------------------- +!---------------------------------------------- +! ... complete matrix entries implicit species +!---------------------------------------------- + mat( 1) = lmat( 1) + mat( 2) = lmat( 2) + mat( 3) = lmat( 3) + mat( 4) = lmat( 4) + mat( 5) = lmat( 5) + mat( 6) = lmat( 6) + mat( 7) = lmat( 7) + mat( 8) = lmat( 8) + mat( 9) = lmat( 9) + mat( 10) = lmat( 10) + mat( 11) = lmat( 11) + mat( 12) = lmat( 12) + mat( 13) = lmat( 13) + mat( 14) = lmat( 14) + mat( 15) = lmat( 15) + mat( 16) = lmat( 16) + mat( 17) = lmat( 17) + mat( 18) = lmat( 18) + mat( 19) = lmat( 19) + mat( 20) = lmat( 20) + mat( 21) = lmat( 21) + mat( 22) = lmat( 22) + mat( 23) = lmat( 23) + mat( 24) = lmat( 24) + mat( 25) = lmat( 25) + mat( 26) = lmat( 26) + mat( 27) = lmat( 27) + mat( 28) = lmat( 28) + mat( 29) = lmat( 29) + mat( 30) = lmat( 30) + mat( 31) = lmat( 31) + mat( 32) = lmat( 32) + mat( 33) = lmat( 33) + mat( 34) = lmat( 34) + mat( 35) = lmat( 35) + mat( 1) = mat( 1) - dti + mat( 2) = mat( 2) - dti + mat( 3) = mat( 3) - dti + mat( 4) = mat( 4) - dti + mat( 5) = mat( 5) - dti + mat( 7) = mat( 7) - dti + mat( 9) = mat( 9) - dti + mat( 10) = mat( 10) - dti + mat( 11) = mat( 11) - dti + mat( 12) = mat( 12) - dti + mat( 14) = mat( 14) - dti + mat( 15) = mat( 15) - dti + mat( 16) = mat( 16) - dti + mat( 17) = mat( 17) - dti + mat( 18) = mat( 18) - dti + mat( 19) = mat( 19) - dti + mat( 20) = mat( 20) - dti + mat( 21) = mat( 21) - dti + mat( 22) = mat( 22) - dti + mat( 23) = mat( 23) - dti + mat( 24) = mat( 24) - dti + mat( 26) = mat( 26) - dti + mat( 27) = mat( 27) - dti + mat( 28) = mat( 28) - dti + mat( 29) = mat( 29) - dti + mat( 30) = mat( 30) - dti + mat( 31) = mat( 31) - dti + mat( 32) = mat( 32) - dti + mat( 34) = mat( 34) - dti + mat( 35) = mat( 35) - dti + end subroutine nlnmat_finit + end module mo_nln_matrix diff --git a/src/chemistry/pp_ghg_mam4/mo_phtadj.F90 b/src/chemistry/pp_ghg_mam4/mo_phtadj.F90 new file mode 100644 index 0000000000..aaa43829fe --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_phtadj.F90 @@ -0,0 +1,24 @@ + module mo_phtadj + private + public :: phtadj + contains + subroutine phtadj( p_rate, inv, m, ncol, nlev ) + use chem_mods, only : nfs, phtcnt + use shr_kind_mod, only : r8 => shr_kind_r8 + implicit none +!-------------------------------------------------------------------- +! ... dummy arguments +!-------------------------------------------------------------------- + integer, intent(in) :: ncol, nlev + real(r8), intent(in) :: inv(ncol,nlev,max(1,nfs)) + real(r8), intent(in) :: m(ncol,nlev) + real(r8), intent(inout) :: p_rate(ncol,nlev,max(1,phtcnt)) +!-------------------------------------------------------------------- +! ... local variables +!-------------------------------------------------------------------- + integer :: k + real(r8) :: im(ncol,nlev) + do k = 1,nlev + end do + end subroutine phtadj + end module mo_phtadj diff --git a/src/chemistry/pp_ghg_mam4/mo_prod_loss.F90 b/src/chemistry/pp_ghg_mam4/mo_prod_loss.F90 new file mode 100644 index 0000000000..d502e216a3 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_prod_loss.F90 @@ -0,0 +1,101 @@ + module mo_prod_loss + use shr_kind_mod, only : r8 => shr_kind_r8 + private + public :: exp_prod_loss + public :: imp_prod_loss + contains + subroutine exp_prod_loss( prod, loss, y, rxt, het_rates ) + use ppgrid, only : pver + implicit none +!-------------------------------------------------------------------- +! ... dummy args +!-------------------------------------------------------------------- + real(r8), dimension(:,:,:), intent(out) :: & + prod, & + loss + real(r8), intent(in) :: y(:,:,:) + real(r8), intent(in) :: rxt(:,:,:) + real(r8), intent(in) :: het_rates(:,:,:) +!-------------------------------------------------------------------- +! ... loss and production for Explicit method +!-------------------------------------------------------------------- + loss(:,:,1) = ( + het_rates(:,:,6))* y(:,:,6) + prod(:,:,1) = 0._r8 + end subroutine exp_prod_loss + subroutine imp_prod_loss( prod, loss, y, rxt, het_rates ) + use ppgrid, only : pver + implicit none +!-------------------------------------------------------------------- +! ... dummy args +!-------------------------------------------------------------------- + real(r8), dimension(:), intent(out) :: & + prod, & + loss + real(r8), intent(in) :: y(:) + real(r8), intent(in) :: rxt(:) + real(r8), intent(in) :: het_rates(:) +!-------------------------------------------------------------------- +! ... loss and production for Implicit method +!-------------------------------------------------------------------- + loss(1) = ( + het_rates(1))* y(1) + prod(1) = 0._r8 + loss(2) = ( + het_rates(2))* y(2) + prod(2) = 0._r8 + loss(3) = ( + rxt(8) + het_rates(3))* y(3) + prod(3) = 0._r8 + loss(4) = ( + rxt(9) + het_rates(4))* y(4) + prod(4) = 0._r8 + loss(5) = ( + rxt(10) + het_rates(5))* y(5) + prod(5) = 0._r8 + loss(6) = ( + rxt(11) + rxt(12) + rxt(14) + het_rates(7))* y(7) + prod(6) = 0._r8 + loss(7) = ( + het_rates(8))* y(8) + prod(7) = 0._r8 + loss(8) = ( + het_rates(9))* y(9) + prod(8) = 0._r8 + loss(9) = ( + het_rates(10))* y(10) + prod(9) = 0._r8 + loss(10) = ( + rxt(1) + rxt(5) + het_rates(11))* y(11) + prod(10) = 0._r8 + loss(11) = ( + het_rates(12))* y(12) + prod(11) =rxt(13)*y(23) + loss(12) = ( + rxt(7) + het_rates(13))* y(13) + prod(12) = 0._r8 + loss(13) = ( + het_rates(14))* y(14) + prod(13) = 0._r8 + loss(14) = ( + het_rates(15))* y(15) + prod(14) = 0._r8 + loss(15) = ( + het_rates(16))* y(16) + prod(15) = 0._r8 + loss(16) = ( + het_rates(17))* y(17) + prod(16) = 0._r8 + loss(17) = ( + het_rates(18))* y(18) + prod(17) = 0._r8 + loss(18) = ( + het_rates(19))* y(19) + prod(18) = 0._r8 + loss(19) = ( + het_rates(20))* y(20) + prod(19) = 0._r8 + loss(20) = ( + het_rates(21))* y(21) + prod(20) = 0._r8 + loss(21) = ( + het_rates(22))* y(22) + prod(21) = 0._r8 + loss(22) = ( + rxt(13) + het_rates(23))* y(23) + prod(22) = (rxt(11) +rxt(12) +.500_r8*rxt(14))*y(7) + loss(23) = ( + het_rates(24))* y(24) + prod(23) = 0._r8 + loss(24) = ( + het_rates(25))* y(25) + prod(24) = 0._r8 + loss(25) = ( + het_rates(26))* y(26) + prod(25) = 0._r8 + loss(26) = ( + rxt(2) + het_rates(27))* y(27) + prod(26) = 0._r8 + loss(27) = ( + rxt(3) + het_rates(28))* y(28) + prod(27) = 0._r8 + loss(28) = ( + rxt(15) + het_rates(29))* y(29) + prod(28) = 0._r8 + loss(29) = ( + het_rates(30))* y(30) + prod(29) =rxt(15)*y(29) + loss(30) = ( + rxt(4) + het_rates(31))* y(31) + prod(30) =2.000_r8*rxt(10)*y(5) +rxt(5)*y(11) + end subroutine imp_prod_loss + end module mo_prod_loss diff --git a/src/chemistry/pp_ghg_mam4/mo_rxt_rates_conv.F90 b/src/chemistry/pp_ghg_mam4/mo_rxt_rates_conv.F90 new file mode 100644 index 0000000000..0030b06714 --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_rxt_rates_conv.F90 @@ -0,0 +1,27 @@ +module mo_rxt_rates_conv + use shr_kind_mod, only : r8 => shr_kind_r8 + implicit none + private + public :: set_rates +contains + subroutine set_rates( rxt_rates, sol, ncol ) + real(r8), intent(inout) :: rxt_rates(:,:,:) + real(r8), intent(in) :: sol(:,:,:) + integer, intent(in) :: ncol + rxt_rates(:ncol,:, 1) = rxt_rates(:ncol,:, 1)*sol(:ncol,:, 11) ! rate_const*H2O2 + rxt_rates(:ncol,:, 2) = rxt_rates(:ncol,:, 2)*sol(:ncol,:, 27) ! rate_const*soa_a1 + rxt_rates(:ncol,:, 3) = rxt_rates(:ncol,:, 3)*sol(:ncol,:, 28) ! rate_const*soa_a2 + rxt_rates(:ncol,:, 4) = rxt_rates(:ncol,:, 4)*sol(:ncol,:, 31) ! rate_const*H2O + rxt_rates(:ncol,:, 5) = rxt_rates(:ncol,:, 5)*sol(:ncol,:, 11) ! rate_const*OH*H2O2 + ! rate_const + rxt_rates(:ncol,:, 7) = rxt_rates(:ncol,:, 7)*sol(:ncol,:, 13) ! rate_const*N2O + rxt_rates(:ncol,:, 8) = rxt_rates(:ncol,:, 8)*sol(:ncol,:, 3) ! rate_const*CFC11 + rxt_rates(:ncol,:, 9) = rxt_rates(:ncol,:, 9)*sol(:ncol,:, 4) ! rate_const*CFC12 + rxt_rates(:ncol,:, 10) = rxt_rates(:ncol,:, 10)*sol(:ncol,:, 5) ! rate_const*CH4 + rxt_rates(:ncol,:, 11) = rxt_rates(:ncol,:, 11)*sol(:ncol,:, 7) ! rate_const*NO3*DMS + rxt_rates(:ncol,:, 12) = rxt_rates(:ncol,:, 12)*sol(:ncol,:, 7) ! rate_const*OH*DMS + rxt_rates(:ncol,:, 13) = rxt_rates(:ncol,:, 13)*sol(:ncol,:, 23) ! rate_const*OH*M*SO2 + rxt_rates(:ncol,:, 14) = rxt_rates(:ncol,:, 14)*sol(:ncol,:, 7) ! rate_const*OH*DMS + rxt_rates(:ncol,:, 15) = rxt_rates(:ncol,:, 15)*sol(:ncol,:, 29) ! rate_const*SOAE + end subroutine set_rates +end module mo_rxt_rates_conv diff --git a/src/chemistry/pp_ghg_mam4/mo_setrxt.F90 b/src/chemistry/pp_ghg_mam4/mo_setrxt.F90 new file mode 100644 index 0000000000..6b94705faa --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_setrxt.F90 @@ -0,0 +1,85 @@ + + module mo_setrxt + + use shr_kind_mod, only : r8 => shr_kind_r8 + + private + public :: setrxt + public :: setrxt_hrates + + contains + + subroutine setrxt( rate, temp, m, ncol ) + + use ppgrid, only : pver, pcols + use shr_kind_mod, only : r8 => shr_kind_r8 + use chem_mods, only : rxntot + use mo_jpl, only : jpl + + implicit none + +!------------------------------------------------------- +! ... dummy arguments +!------------------------------------------------------- + integer, intent(in) :: ncol + real(r8), intent(in) :: temp(pcols,pver) + real(r8), intent(in) :: m(ncol,pver) + real(r8), intent(inout) :: rate(ncol,pver,rxntot) + +!------------------------------------------------------- +! ... local variables +!------------------------------------------------------- + integer :: n + real(r8) :: itemp(ncol,pver) + real(r8) :: exp_fac(ncol,pver) + real(r8) :: ko(ncol,pver) + real(r8) :: kinf(ncol,pver) + + rate(:,:,5) = 1.8e-12_r8 + rate(:,:,15) = 1.157e-05_r8 + itemp(:ncol,:) = 1._r8 / temp(:ncol,:) + n = ncol*pver + rate(:,:,11) = 1.9e-13_r8 * exp( 520._r8 * itemp(:,:) ) + rate(:,:,12) = 1.1e-11_r8 * exp( -280._r8 * itemp(:,:) ) + + itemp(:,:) = 300._r8 * itemp(:,:) + + ko(:,:) = 2.9e-31_r8 * itemp(:,:)**4.1_r8 + kinf(:,:) = 1.7e-12_r8 * itemp(:,:)**(-0.2_r8) + call jpl( rate(1,1,13), m, 0.6_r8, ko, kinf, n ) + + end subroutine setrxt + + + subroutine setrxt_hrates( rate, temp, m, ncol, kbot ) + + use ppgrid, only : pver, pcols + use shr_kind_mod, only : r8 => shr_kind_r8 + use chem_mods, only : rxntot + use mo_jpl, only : jpl + + implicit none + +!------------------------------------------------------- +! ... dummy arguments +!------------------------------------------------------- + integer, intent(in) :: ncol + integer, intent(in) :: kbot + real(r8), intent(in) :: temp(pcols,pver) + real(r8), intent(in) :: m(ncol,pver) + real(r8), intent(inout) :: rate(ncol,pver,rxntot) + +!------------------------------------------------------- +! ... local variables +!------------------------------------------------------- + integer :: n + real(r8) :: itemp(ncol,kbot) + real(r8) :: exp_fac(ncol,kbot) + real(r8) :: ko(ncol,kbot) + real(r8) :: kinf(ncol,kbot) + real(r8) :: wrk(ncol,kbot) + + + end subroutine setrxt_hrates + + end module mo_setrxt diff --git a/src/chemistry/pp_ghg_mam4/mo_sim_dat.F90 b/src/chemistry/pp_ghg_mam4/mo_sim_dat.F90 new file mode 100644 index 0000000000..04177a1f6e --- /dev/null +++ b/src/chemistry/pp_ghg_mam4/mo_sim_dat.F90 @@ -0,0 +1,146 @@ + + module mo_sim_dat + + private + public :: set_sim_dat + + contains + + subroutine set_sim_dat + + use chem_mods, only : clscnt, cls_rxt_cnt, clsmap, permute, adv_mass, fix_mass, crb_mass + use chem_mods, only : diag_map + use chem_mods, only : phtcnt, rxt_tag_cnt, rxt_tag_lst, rxt_tag_map + use chem_mods, only : pht_alias_lst, pht_alias_mult + use chem_mods, only : extfrc_lst, inv_lst, slvd_lst + use chem_mods, only : enthalpy_cnt, cph_enthalpy, cph_rid, num_rnts, rxntot + use cam_abortutils,only : endrun + use mo_tracname, only : solsym + use chem_mods, only : frc_from_dataset + use chem_mods, only : is_scalar, is_vector + use shr_kind_mod, only : r8 => shr_kind_r8 + use cam_logfile, only : iulog + + implicit none + +!-------------------------------------------------------------- +! ... local variables +!-------------------------------------------------------------- + integer :: ios + + is_scalar = .true. + is_vector = .false. + + clscnt(:) = (/ 1, 0, 0, 30, 0 /) + + cls_rxt_cnt(:,1) = (/ 0, 0, 0, 1 /) + cls_rxt_cnt(:,4) = (/ 1, 14, 0, 30 /) + + solsym(: 31) = (/ 'bc_a1 ','bc_a4 ','CFC11 ','CFC12 ','CH4 ', & + 'CO2 ','DMS ','dst_a1 ','dst_a2 ','dst_a3 ', & + 'H2O2 ','H2SO4 ','N2O ','ncl_a1 ','ncl_a2 ', & + 'ncl_a3 ','num_a1 ','num_a2 ','num_a3 ','num_a4 ', & + 'pom_a1 ','pom_a4 ','SO2 ','so4_a1 ','so4_a2 ', & + 'so4_a3 ','soa_a1 ','soa_a2 ','SOAE ','SOAG ', & + 'H2O ' /) + + adv_mass(: 31) = (/ 12.011000_r8, 12.011000_r8, 137.367503_r8, 120.913206_r8, 16.040600_r8, & + 44.009800_r8, 62.132400_r8, 135.064039_r8, 135.064039_r8, 135.064039_r8, & + 34.013600_r8, 98.078400_r8, 44.012880_r8, 58.442468_r8, 58.442468_r8, & + 58.442468_r8, 1.007400_r8, 1.007400_r8, 1.007400_r8, 1.007400_r8, & + 12.011000_r8, 12.011000_r8, 64.064800_r8, 115.107340_r8, 115.107340_r8, & + 115.107340_r8, 12.011000_r8, 12.011000_r8, 12.011000_r8, 12.011000_r8, & + 18.014200_r8 /) + + crb_mass(: 31) = (/ 12.011000_r8, 12.011000_r8, 12.011000_r8, 12.011000_r8, 12.011000_r8, & + 12.011000_r8, 24.022000_r8, 0.000000_r8, 0.000000_r8, 0.000000_r8, & + 0.000000_r8, 0.000000_r8, 0.000000_r8, 0.000000_r8, 0.000000_r8, & + 0.000000_r8, 0.000000_r8, 0.000000_r8, 0.000000_r8, 0.000000_r8, & + 12.011000_r8, 12.011000_r8, 0.000000_r8, 0.000000_r8, 0.000000_r8, & + 0.000000_r8, 12.011000_r8, 12.011000_r8, 12.011000_r8, 12.011000_r8, & + 0.000000_r8 /) + + fix_mass(: 8) = (/ 0.00000000_r8, 31.9988000_r8, 28.0134800_r8, 33.0062000_r8, 17.0068000_r8, & + 62.0049400_r8, 47.9982000_r8, 137.367503_r8 /) + + clsmap(: 1,1) = (/ 6 /) + clsmap(: 30,4) = (/ 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, & + 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, & + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 /) + + permute(: 30,4) = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, & + 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, & + 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 /) + + diag_map(: 30) = (/ 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, & + 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, & + 24, 26, 27, 28, 29, 30, 31, 32, 34, 35 /) + + extfrc_lst(: 11) = (/ 'bc_a1 ','bc_a4 ','H2O ','num_a1 ','num_a2 ', & + 'num_a4 ','pom_a1 ','pom_a4 ','SO2 ','so4_a1 ', & + 'so4_a2 ' /) + + frc_from_dataset(: 11) = (/ .true., .true., .true., .true., .true., & + .true., .true., .true., .true., .true., & + .true. /) + + inv_lst(: 8) = (/ 'M ', 'O2 ', 'N2 ', 'HO2 ', 'OH ', & + 'NO3 ', 'O3 ', 'HALONS ' /) + + if( allocated( rxt_tag_lst ) ) then + deallocate( rxt_tag_lst ) + end if + allocate( rxt_tag_lst(rxt_tag_cnt),stat=ios ) + if( ios /= 0 ) then + write(iulog,*) 'set_sim_dat: failed to allocate rxt_tag_lst; error = ',ios + call endrun + end if + if( allocated( rxt_tag_map ) ) then + deallocate( rxt_tag_map ) + end if + allocate( rxt_tag_map(rxt_tag_cnt),stat=ios ) + if( ios /= 0 ) then + write(iulog,*) 'set_sim_dat: failed to allocate rxt_tag_map; error = ',ios + call endrun + end if + rxt_tag_lst( 1: 15) = (/ 'jh2o2 ', 'jsoa_a1 ', & + 'jsoa_a2 ', 'lyman_alpha ', & + 'OH_H2O2 ', 'usr_HO2_HO2 ', & + 'n2o_loss ', 'cfc11_loss ', & + 'cfc12_loss ', 'ch4_loss ', & + 'DMS_NO3 ', 'DMS_OHa ', & + 'SO2_OH_M ', 'usr_DMS_OH ', & + 'SOAE_tau ' /) + rxt_tag_map(:rxt_tag_cnt) = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, & + 11, 12, 13, 14, 15 /) + if( allocated( pht_alias_lst ) ) then + deallocate( pht_alias_lst ) + end if + allocate( pht_alias_lst(phtcnt,2),stat=ios ) + if( ios /= 0 ) then + write(iulog,*) 'set_sim_dat: failed to allocate pht_alias_lst; error = ',ios + call endrun + end if + if( allocated( pht_alias_mult ) ) then + deallocate( pht_alias_mult ) + end if + allocate( pht_alias_mult(phtcnt,2),stat=ios ) + if( ios /= 0 ) then + write(iulog,*) 'set_sim_dat: failed to allocate pht_alias_mult; error = ',ios + call endrun + end if + pht_alias_lst(:,1) = (/ ' ', ' ', ' ' /) + pht_alias_lst(:,2) = (/ ' ', 'jno2 ', 'jno2 ' /) + pht_alias_mult(:,1) = (/ 1._r8, 1._r8, 1._r8 /) + pht_alias_mult(:,2) = (/ 1._r8, .0004_r8, .0004_r8 /) + allocate( num_rnts(rxntot-phtcnt),stat=ios ) + if( ios /= 0 ) then + write(iulog,*) 'set_sim_dat: failed to allocate num_rnts; error = ',ios + call endrun + end if + num_rnts(:) = (/ 1, 2, 2, 1, 1, 1, 1, 2, 2, 3, & + 2, 1 /) + + end subroutine set_sim_dat + + end module mo_sim_dat diff --git a/src/control/cam_budget.F90 b/src/control/cam_budget.F90 new file mode 100644 index 0000000000..1ae7fd20f4 --- /dev/null +++ b/src/control/cam_budget.F90 @@ -0,0 +1,398 @@ +module cam_budget + !---------------------------------------------------------------------------- + ! + ! Adds support for energy and mass snapshots and budgets using cam_history api. + ! + ! Public functions/subroutines: + ! + ! cam_budget_init + ! cam_budget_em_snapshot + ! cam_budget_em_register + ! cam_budget_get_global + ! cam_budget_readnl + ! budget_ind_byname + ! is_cam_budget + !----------------------------------------------------------------------- + + use cam_abortutils, only: endrun + use cam_history, only: addfld, add_default, horiz_only + use cam_history_support, only: max_fieldname_len + use cam_logfile, only: iulog + use cam_thermo, only: thermo_budget_vars, thermo_budget_vars_descriptor, & + thermo_budget_vars_unit, thermo_budget_vars_massv, thermo_budget_num_vars,teidx,wvidx,wlidx,wiidx + use shr_kind_mod, only: r8 => shr_kind_r8 + use shr_kind_mod, only: cl => shr_kind_cl + use spmd_utils, only: masterproc, masterprocid, mpicom + + implicit none + private + save + + ! Public interfaces + public :: & + cam_budget_init, &! initialize budget variables + cam_budget_em_snapshot, &! define a snapshot and add to history buffer + cam_budget_em_register, &! define a budget and add to history buffer + cam_budget_get_global, &! get global budget from history buffer + cam_budget_readnl, &! read budget namelist setting + is_cam_budget ! return logical if budget_defined + + ! Private + real(r8) :: dstepsize + integer, parameter :: budget_array_max = 500 ! max number of budgets + character*3 :: budget_optype(budget_array_max) = '' ! allows 'dif' or 'sum' + character*3 :: budget_pkgtype(budget_array_max) = '' ! allows 'phy' or 'dyn' + + ! Public data + integer, public, protected :: budget_num = 0 ! current number of defined budgets. + character(cl), public, protected :: budget_name(budget_array_max) = '' ! budget names + character(cl), public, protected :: budget_longname(budget_array_max) = '' ! descriptive name of budget + character(cl), public, protected :: budget_stagename(budget_array_max)= '' ! shortname of both of the 3 char snapshot components + character(cl), public, protected :: budget_stg1name(budget_array_max) = '' ! The 1st of 2 snapshots used to calculate a budget + character(cl), public, protected :: budget_stg2name(budget_array_max) = '' ! The 2nd of 2 snapshots used to calculate a budget + + integer, public, protected :: thermo_budget_histfile_num = 1 ! The history tape number for budget fields + logical, public, protected :: thermo_budget_history = .false. ! Turn budgeting on or off + + + !============================================================================================== +CONTAINS + !============================================================================================== + ! + ! Read namelist variables. + subroutine cam_budget_readnl(nlfile) + use dycore, only: dycore_is + use namelist_utils, only: find_group_name + use spmd_utils, only: mpi_character, mpi_logical, mpi_integer, mpi_success + use shr_string_mod, only: shr_string_toUpper + use string_utils, only: int2str + + ! Dummy argument: filepath for file containing namelist input + character(len=*), intent(in) :: nlfile + + ! Local variables + integer :: unitn, ierr + character(len=*), parameter :: subname = 'cam_budget_readnl :: ' + + namelist /thermo_budget_nl/ thermo_budget_history, thermo_budget_histfile_num + !----------------------------------------------------------------------- + + if (masterproc) then + open(newunit=unitn, file=trim(nlfile), status='old') + call find_group_name(unitn, 'thermo_budget_nl', status=ierr) + if (ierr == 0) then + read(unitn, thermo_budget_nl, iostat=ierr) + if (ierr /= 0) then + call endrun(subname//'ERROR reading namelist, thermo_budget_nl, errcode = '//int2str(ierr)) + end if + end if + close(unitn) + end if + + ! Broadcast namelist variables + call mpi_bcast(thermo_budget_history , 1 , mpi_logical , masterprocid, mpicom, ierr) + if (ierr /= mpi_success) call endrun(subname//": FATAL: mpi_bcast: thermo_budget_history") + call mpi_bcast(thermo_budget_histfile_num , 1 , mpi_integer , masterprocid, mpicom, ierr) + if (ierr /= mpi_success) call endrun(subname//": FATAL: mpi_bcast: thermo_budget_histfile_num") + + ! Write out thermo_budget options + if (masterproc) then + if (thermo_budget_history) then + if (dycore_is('EUL').or.dycore_is('FV').or.dycore_is('FV3')) then + call endrun(subname//'ERROR thermodynamic budgets not implemented for this dycore') + else + write(iulog,*)'Thermo budgets will be written to the log file and diagnostics saved to history file:',& + thermo_budget_histfile_num + end if + end if + end if + end subroutine cam_budget_readnl + + !============================================================================================== + + subroutine cam_budget_init() + use time_manager, only: get_step_size + + dstepsize=get_step_size() + + end subroutine cam_budget_init + + !============================================================================================== + + subroutine cam_budget_em_snapshot (name, pkgtype, longname) + use dycore, only: dycore_is + use cam_grid_support, only: cam_grid_id + + character(len=*), intent(in) :: & + name ! budget name used as variable name in history file output (8 char max) + character(len=*), intent(in) :: & + pkgtype ! budget type either phy or dyn + character(len=*), intent(in) :: & + longname ! value for long_name attribute in netcdf output (128 char max, defaults to name) + + character (cl) :: errmsg + character (len=max_fieldname_len) :: name_str + character (cl) :: desc_str, units_str + character (cl) :: gridname + integer :: ivars + character(len=*), parameter :: sub='cam_budget_em_snapshot' + logical :: use_cslam ! using cslam transport for mass tracers + !----------------------------------------------------------------------- + + if (thermo_budget_history) then + ! FVM grid is only registered when using cslam + use_cslam=cam_grid_id('FVM')>0 + + do ivars=1, thermo_budget_num_vars + write(name_str,*) TRIM(ADJUSTL(thermo_budget_vars(ivars))),"_",TRIM(ADJUSTL(name)) + write(desc_str,*) TRIM(ADJUSTL(thermo_budget_vars_descriptor(ivars)))," ", & + TRIM(ADJUSTL(longname)) + write(units_str,*) TRIM(ADJUSTL(thermo_budget_vars_unit(ivars))) + + if (budget_num < budget_array_max) then + budget_num = budget_num + 1 + else + write(errmsg, *) sub, ': Maximum number of budgets reached - increase budget_array_max parameter ' + call endrun(errmsg) + end if + ! set budget name and constants + budget_name(budget_num) = trim(name_str) + budget_longname(budget_num) = trim(desc_str) + + budget_pkgtype(budget_num)=pkgtype + budget_stagename(budget_num)= trim(name) + + if (pkgtype=='phy') then + gridname='physgrid' + else + if (dycore_is('SE')) then + if (use_cslam .and. thermo_budget_vars_massv(ivars)) then + gridname='FVM' + else + gridname='GLL' + end if + else if (dycore_is('MPAS')) then + gridname='mpas_cell' + else + write(errmsg, *) sub, ': budget_add is only supported for MPAS and SE dycores' + call endrun(errmsg) + end if + end if + call addfld (TRIM(ADJUSTL(name_str)), horiz_only, 'N', TRIM(ADJUSTL(units_str)), & + TRIM(ADJUSTL(desc_str)), gridname=trim(gridname)) + call add_default(TRIM(ADJUSTL(name_str)), thermo_budget_histfile_num, 'N') + end do + end if + end subroutine cam_budget_em_snapshot + + !============================================================================== + + subroutine cam_budget_em_register (name, stg1name, stg2name, pkgtype, optype, longname) + use dycore, only: dycore_is + use cam_grid_support, only: cam_grid_id + + ! Register a budget. + + character(len=*), intent(in) :: & + name,stg1name,stg2name ! budget name used as variable name in history file output (8 char max) + + character(len=*), intent(in) :: & + pkgtype ! budget type either phy or dyn + + character(len=*), intent(in) :: & + optype ! dif (difference) or sum + + character(len=*), intent(in) :: & + longname ! value for long_name attribute in netcdf output (128 char max, defaults to name) + + character(len=*), parameter :: sub='cam_budget_em_register' + character(cl) :: errmsg + character(len=1) :: opchar + character (len=max_fieldname_len) :: name_str + character (cl) :: desc_str, units_str + character (cl) :: gridname + character (cl) :: strstg1, strstg2 + integer :: ivars + logical :: use_cslam ! true => use cslam to transport mass variables + !----------------------------------------------------------------------- + + if (thermo_budget_history) then + ! the FVM gridname is only defined when use_cslam is true. + use_cslam=cam_grid_id('FVM')>0 + + ! register history budget variables + do ivars=1, thermo_budget_num_vars + write(name_str,*) TRIM(ADJUSTL(thermo_budget_vars(ivars))),"_",TRIM(ADJUSTL(name)) + write(strstg1,*) TRIM(ADJUSTL(thermo_budget_vars(ivars))),"_",TRIM(ADJUSTL(stg1name)) + write(strstg2,*) TRIM(ADJUSTL(thermo_budget_vars(ivars))),"_",TRIM(ADJUSTL(stg2name)) + write(desc_str,*) TRIM(ADJUSTL(thermo_budget_vars_descriptor(ivars)))," ", & + TRIM(ADJUSTL(longname)) + write(units_str,*) TRIM(ADJUSTL(thermo_budget_vars_unit(ivars))) + + if (budget_num < budget_array_max) then + budget_num = budget_num + 1 + else + write(errmsg, *) sub, ': Maximum number of budgets reached - increase budget_array_max parameter ' + call endrun(errmsg) + end if + budget_pkgtype(budget_num)=pkgtype + + ! set budget name and constants + budget_name(budget_num) = trim(name_str) + budget_longname(budget_num) = trim(desc_str) + + if (optype=='dif') then + opchar='-' + else if (optype=='sum') then + opchar='+' + else + write(errmsg,*) sub, ': FATAL: unknown operation type, expecting "sum" or "dif":', optype + call endrun(errmsg) + end if + budget_stg1name(budget_num) = trim(adjustl(strstg1)) + budget_stg2name(budget_num) = trim(adjustl(strstg2)) + budget_stagename(budget_num)= trim(adjustl(strstg1))//trim(opchar)//trim(adjustl(strstg2)) + budget_optype(budget_num)=optype + + if (pkgtype=='phy') then + gridname='physgrid' + else + if (dycore_is('SE')) then + if (use_cslam .and. thermo_budget_vars_massv(ivars)) then + gridname='FVM' + else + gridname='GLL' + end if + else if (dycore_is('MPAS')) then + gridname='mpas_cell' + else + write(errmsg, *) sub, ': budget_add is only supported for MPAS and SE dycores' + call endrun(errmsg) + end if + end if + call addfld (TRIM(ADJUSTL(name_str)), horiz_only, 'N', TRIM(ADJUSTL(units_str)),TRIM(ADJUSTL(desc_str)), & + gridname=gridname,optype=optype,op_f1name=TRIM(ADJUSTL(strstg1)),op_f2name=TRIM(ADJUSTL(strstg2))) + call add_default(TRIM(ADJUSTL(name_str)), thermo_budget_histfile_num, 'N') + end do + end if + end subroutine cam_budget_em_register + + !============================================================================== + + subroutine cam_budget_get_global (name, me_idx, global) + + use cam_history, only: get_field_properties + use cam_history_support, only: active_entry,ptapes + use cam_thermo, only: thermo_budget_vars_massv + + ! Get the global integral of a budget. Endrun will be called + ! when name is not found. + !-----------------------------Arguments--------------------------------- + character(len=*), intent(in) :: name ! budget name + integer, intent(in) :: me_idx ! mass energy variable index + real(r8), intent(out) :: global ! global integral of the budget field + + !---------------------------Local workspace----------------------------- + type (active_entry), pointer :: tape(:) ! history tapes + character (len=max_fieldname_len) :: name_str + character(cl) :: errmsg + integer :: b_ind ! budget index + integer :: h_ind(ptapes) ! hentry index + integer :: m_ind ! masterlist index + integer :: idx,pidx,midx,uidx ! substring index for sum dif char + integer :: m ! budget index + logical :: found ! true if global integral found + + character(len=*), parameter :: sub='cam_budget_get_global' + !----------------------------------------------------------------------- + ! Initialize tape pointer here to avoid initialization only on first invocation + nullify(tape) + + name_str='' + write(name_str,*) TRIM(ADJUSTL(name)) + + midx=index(name_str, '-') + pidx=index(name_str, '+') + idx=midx+pidx + + ! check for budget using stagename short format (stg1//op//stg2) where stg1 is name without thermo string appended + if (idx /= 0 .and. (midx==0 .or. pidx==0)) then + write(name_str,*) TRIM(ADJUSTL(thermo_budget_vars(me_idx)))//"_"//trim(adjustl(name_str(1:idx)))// & + TRIM(ADJUSTL(thermo_budget_vars(me_idx)))//"_"//TRIM(ADJUSTL(name_str(idx+1:))) + end if + + uidx=index(name_str, '_') + if (uidx == 0) then + !This is a stage name need to append the type of thermo variable using input index + write(name_str,*) TRIM(ADJUSTL(thermo_budget_vars(me_idx)))//"_"//trim(adjustl(name_str(1:))) + end if + + b_ind=budget_ind_byname(trim(adjustl(name_str))) + + if (b_ind < 0) call endrun(sub//': FATAL field name '//name//' not found'//' looked for '//trim(adjustl(name_str))) + + write(name_str,*) TRIM(ADJUSTL(budget_name(b_ind))) + + ! Find budget name in list and return global value + call get_field_properties(trim(adjustl(name_str)), found, tape_out=tape, ff_out=m_ind, f_out=h_ind) + + if (found.and.h_ind(thermo_budget_histfile_num)>0) then + call tape(thermo_budget_histfile_num)%hlist(h_ind(thermo_budget_histfile_num))%get_global(global) + if (.not. thermo_budget_vars_massv(me_idx)) & + global=global/dstepsize + else + write(errmsg,*) sub, ': FATAL: name not found: ', trim(name) + call endrun(errmsg) + end if + + CONTAINS + pure function budget_ind_byname (name) + ! + ! Get the index of a budget. Ret -1 for not found + !-----------------------------Arguments--------------------------------- + character(len=*), intent(in) :: name ! budget name + + !---------------------------Local workspace----------------------------- + integer :: budget_ind_byname ! function return + integer :: m ! budget index + !----------------------------------------------------------------------- + ! Find budget name in list + budget_ind_byname = -1 + do m = 1, budget_num + if (trim(adjustl(name)) == trim(adjustl(budget_name(m))).or. & + trim(adjustl(name)) == trim(adjustl(budget_stagename(m)))) then + budget_ind_byname = m + return + end if + end do + end function budget_ind_byname + end subroutine cam_budget_get_global + !============================================================================== + + pure function is_cam_budget(name) + + ! Get the index of a budget. + + !-----------------------------Arguments--------------------------------- + character(len=*), intent(in) :: name ! budget name + + !---------------------------Local workspace----------------------------- + logical :: is_cam_budget ! function return + integer :: m ! budget index + !----------------------------------------------------------------------- + + ! Find budget name in list of defined budgets + + is_cam_budget = .false. + do m = 1, budget_num + if (trim(adjustl(name)) == trim(adjustl(budget_name(m))).or. & + trim(adjustl(name)) == trim(adjustl(budget_stagename(m)))) then + is_cam_budget = .true. + return + end if + end do + end function is_cam_budget + + !=========================================================================== + +end module cam_budget diff --git a/src/control/cam_comp.F90 b/src/control/cam_comp.F90 index b92e02b000..f4091fda1a 100644 --- a/src/control/cam_comp.F90 +++ b/src/control/cam_comp.F90 @@ -16,9 +16,7 @@ module cam_comp use spmd_utils, only: masterproc, mpicom use cam_control_mod, only: cam_ctrl_init, cam_ctrl_set_orbit use runtime_opts, only: read_namelist -use time_manager, only: timemgr_init, get_step_size, & - get_nstep, is_first_step, is_first_restart_step - +use time_manager, only: timemgr_init, get_nstep use camsrfexch, only: cam_out_t, cam_in_t use ppgrid, only: begchunk, endchunk use physics_types, only: physics_state, physics_tend @@ -393,7 +391,8 @@ subroutine cam_run4( cam_out, cam_in, rstwr, nlend, & ! file output. ! !----------------------------------------------------------------------- - use cam_history, only: wshist, wrapup + use dycore_budget, only: print_budget + use cam_history, only: wshist, wrapup, hstwr use cam_restart, only: cam_write_restart use qneg_module, only: qneg_print_summary use time_manager, only: is_last_step @@ -436,6 +435,8 @@ subroutine cam_run4( cam_out, cam_in, rstwr, nlend, & call qneg_print_summary(is_last_step()) + call print_budget(hstwr) + call shr_sys_flush(iulog) end subroutine cam_run4 diff --git a/src/control/cam_history.F90 b/src/control/cam_history.F90 index 5b0e6f47f2..677544bdc3 100644 --- a/src/control/cam_history.F90 +++ b/src/control/cam_history.F90 @@ -49,7 +49,8 @@ module cam_history field_info, active_entry, hentry, & horiz_only, write_hist_coord_attrs, & write_hist_coord_vars, interp_info_t, & - lookup_hist_coord_indices, get_hist_coord_index + lookup_hist_coord_indices, get_hist_coord_index, & + field_op_len use string_utils, only: date2yyyymmdd, sec2hms use sat_hist, only: is_satfile use solar_parms_data, only: solar_parms_on, kp=>solar_parms_kp, ap=>solar_parms_ap @@ -68,19 +69,28 @@ module cam_history public :: cam_history_snapshot_deactivate public :: cam_history_snapshot_activate + type grid_area_entry + integer :: decomp_type = -1 ! type of decomposition (e.g., physics or dynamics) + real(r8), allocatable :: wbuf(:,:) ! for area weights + end type grid_area_entry + type (grid_area_entry), target, allocatable:: grid_wts(:) ! area wts for each decomp type + type (grid_area_entry), pointer :: allgrids_wt(:) => null() ! area wts for each decomp type ! ! master_entry: elements of an entry in the master field list ! type master_entry - type (field_info) :: field ! field information + type (field_info) :: field ! field information character(len=max_fieldname_len) :: meridional_field = '' ! for vector fields character(len=max_fieldname_len) :: zonal_field = '' ! for vector fields - character(len=1) :: avgflag(ptapes) ! averaging flag - character(len=max_chars) :: time_op(ptapes) ! time operator (e.g. max, min, avg) - logical :: act_sometape ! Field is active on some tape - logical :: actflag(ptapes) ! Per tape active/inactive flag - integer :: htapeindx(ptapes)! This field's index on particular history tape - type(master_entry), pointer :: next_entry => null() ! The next master entry + character(len=1) :: avgflag(ptapes) ! averaging flag + character(len=max_chars) :: time_op(ptapes) ! time operator (e.g. max, min, avg) + character(len=field_op_len) :: field_op = '' ! field derived from sum or dif of field1 and field2 + character(len=max_fieldname_len) :: op_field1 = '' ! first field name to be operated on + character(len=max_fieldname_len) :: op_field2 = '' ! second field name to be operated on + logical :: act_sometape ! Field is active on some tape + logical :: actflag(ptapes) ! Per tape active/inactive flag + integer :: htapeindx(ptapes)! This field's index on particular history tape + type(master_entry), pointer :: next_entry => null() ! The next master entry end type master_entry type (master_entry), pointer :: masterlinkedlist => null() ! master field linkedlist top @@ -115,7 +125,7 @@ module cam_history ! ! The size of these parameters should match the assignments in restart_vars_setnames and restart_dims_setnames below ! - integer, parameter :: restartvarcnt = 38 + integer, parameter :: restartvarcnt = 45 integer, parameter :: restartdimcnt = 10 type(rvar_id) :: restartvars(restartvarcnt) type(rdim_id) :: restartdims(restartdimcnt) @@ -177,8 +187,7 @@ module cam_history ! Allowed history averaging flags ! This should match namelist_definition.xml => avgflag_pertape (+ ' ') - ! The presence of 'ABI' and 'XML' in this string is a coincidence - character(len=7), parameter :: HIST_AVG_FLAGS = ' ABIXML' + character(len=9), parameter :: HIST_AVG_FLAGS = ' ABILMNSX' character(len=22) ,parameter :: LT_DESC = 'mean (over local time)' ! local time description logical :: collect_column_output(ptapes) @@ -349,6 +358,8 @@ subroutine intht (model_doi_url_in) use cam_control_mod, only: restart_run, branch_run use sat_hist, only: sat_hist_init use spmd_utils, only: mpicom, masterprocid, mpi_character + use cam_grid_support, only: cam_grid_get_areawt + use cam_history_support, only: dim_index_2d ! !----------------------------------------------------------------------- ! @@ -367,8 +378,13 @@ subroutine intht (model_doi_url_in) integer :: enddim3 ! on-node chunk or lat end index integer :: day, sec ! day and seconds from base date integer :: rcode ! shr_sys_getenv return code + integer :: wtidx(1) ! area weight index + integer :: i,k,c,ib,ie,jb,je,count ! index + integer :: fdecomp ! field decomp + type(dim_index_2d) :: dimind ! 2-D dimension index + real(r8), pointer :: areawt(:) ! pointer to areawt values for attribute type(master_entry), pointer :: listentry - character(len=32) :: fldname ! temp variable used to produce a left justified field name + character(len=32) :: fldname ! temp variable used to produce a left justified field name ! in the formatted logfile output ! @@ -466,12 +482,43 @@ subroutine intht (model_doi_url_in) allocate(tape(t)%hlist(f)%sbuf(begdim1:enddim1,begdim2:enddim2,begdim3:enddim3)) tape(t)%hlist(f)%sbuf = 0._r8 endif + if (tape(t)%hlist(f)%avgflag .eq. 'N') then ! set up areawt weight buffer + fdecomp = tape(t)%hlist(f)%field%decomp_type + if (any(allgrids_wt(:)%decomp_type == fdecomp)) then + wtidx=MAXLOC(allgrids_wt(:)%decomp_type, MASK = allgrids_wt(:)%decomp_type .EQ. fdecomp) + tape(t)%hlist(f)%wbuf => allgrids_wt(wtidx(1))%wbuf + else + ! area weights not found for this grid, then create them + ! first check for an available spot in the array + if (any(allgrids_wt(:)%decomp_type == -1)) then + wtidx=MINLOC(allgrids_wt(:)%decomp_type) + else + call endrun('cam_history:intht: Error initializing allgrids_wt with area weights') + end if + allgrids_wt(wtidx)%decomp_type=fdecomp + areawt => cam_grid_get_areawt(fdecomp) + allocate(allgrids_wt(wtidx(1))%wbuf(begdim1:enddim1,begdim3:enddim3)) + allgrids_wt(wtidx(1))%wbuf(begdim1:enddim1,begdim3:enddim3)=0._r8 + count=0 + do c=begdim3,enddim3 + dimind = tape(t)%hlist(f)%field%get_dims(c) + ib=dimind%beg1 + ie=dimind%end1 + do i=ib,ie + count=count+1 + allgrids_wt(wtidx(1))%wbuf(i,c)=areawt(count) + end do + end do + tape(t)%hlist(f)%wbuf => allgrids_wt(wtidx(1))%wbuf + endif + endif if(tape(t)%hlist(f)%field%flag_xyfill .or. (avgflag_pertape(t) .eq. 'L')) then allocate (tape(t)%hlist(f)%nacs(begdim1:enddim1,begdim3:enddim3)) else allocate (tape(t)%hlist(f)%nacs(1,begdim3:enddim3)) end if tape(t)%hlist(f)%nacs(:,:) = 0 + tape(t)%hlist(f)%beg_nstep = 0 tape(t)%hlist(f)%field%meridional_complement = -1 tape(t)%hlist(f)%field%zonal_complement = -1 end do @@ -937,6 +984,47 @@ subroutine setup_interpolation_and_define_vector_complements() end if end subroutine setup_interpolation_and_define_vector_complements + subroutine define_composed_field_ids(t) + + ! Dummy arguments + integer, intent(in) :: t ! Current tape + + ! Local variables + integer :: f, ff + character(len=max_fieldname_len) :: field1 + character(len=max_fieldname_len) :: field2 + character(len=*), parameter :: subname='define_composed_field_ids' + logical :: is_composed + + do f = 1, nflds(t) + call composed_field_info(tape(t)%hlist(f)%field%name,is_composed,fname1=field1,fname2=field2) + if (is_composed) then + if (len_trim(field1) > 0 .and. len_trim(field2) > 0) then + ! set field1/field2 names for htape from the masterfield list + tape(t)%hlist(f)%op_field1=trim(field1) + tape(t)%hlist(f)%op_field2=trim(field2) + ! find ids for field1/2 + do ff = 1, nflds(t) + if (trim(field1) == trim(tape(t)%hlist(ff)%field%name)) then + tape(t)%hlist(f)%field%op_field1_id = ff + end if + if (trim(field2) == trim(tape(t)%hlist(ff)%field%name)) then + tape(t)%hlist(f)%field%op_field2_id = ff + end if + end do + if (tape(t)%hlist(f)%field%op_field1_id == -1) then + call endrun(trim(subname)//': No op_field1 match for '//trim(tape(t)%hlist(f)%field%name)) + end if + if (tape(t)%hlist(f)%field%op_field2_id == -1) then + call endrun(trim(subname)//': No op_field2 match for '//trim(tape(t)%hlist(f)%field%name)) + end if + else + call endrun(trim(subname)//': Component fields not found for composed field') + end if + end if + end do + end subroutine define_composed_field_ids + subroutine restart_vars_setnames() ! Local variable @@ -1077,6 +1165,25 @@ subroutine restart_vars_setnames() restartvars(rvindex)%fillset = .true. restartvars(rvindex)%ifill = 0 + rvindex = rvindex + 1 + restartvars(rvindex)%name = 'beg_nstep' + restartvars(rvindex)%type = pio_int + restartvars(rvindex)%ndims = 2 + restartvars(rvindex)%dims(1) = maxnflds_dim_ind + restartvars(rvindex)%dims(2) = ptapes_dim_ind + restartvars(rvindex)%fillset = .true. + restartvars(rvindex)%ifill = 0 + + rvindex = rvindex + 1 + restartvars(rvindex)%name = 'hbuf_integral' + restartvars(rvindex)%type = pio_double + restartvars(rvindex)%ndims = 2 + restartvars(rvindex)%dims(1) = maxnflds_dim_ind + restartvars(rvindex)%dims(2) = ptapes_dim_ind + restartvars(rvindex)%fillset = .true. + restartvars(rvindex)%ifill = 0 + + rvindex = rvindex + 1 restartvars(rvindex)%name = 'avgflag' restartvars(rvindex)%type = pio_char @@ -1217,6 +1324,48 @@ subroutine restart_vars_setnames() restartvars(rvindex)%fillset = .true. restartvars(rvindex)%ifill = 0 + rvindex = rvindex + 1 + restartvars(rvindex)%name = 'field_op' + restartvars(rvindex)%type = pio_char + restartvars(rvindex)%ndims = 3 + restartvars(rvindex)%dims(1) = max_chars_dim_ind + restartvars(rvindex)%dims(2) = maxnflds_dim_ind + restartvars(rvindex)%dims(3) = ptapes_dim_ind + + rvindex = rvindex + 1 + restartvars(rvindex)%name = 'op_field1_id' + restartvars(rvindex)%type = pio_int + restartvars(rvindex)%ndims = 2 + restartvars(rvindex)%dims(1) = maxnflds_dim_ind + restartvars(rvindex)%dims(2) = ptapes_dim_ind + restartvars(rvindex)%fillset = .true. + restartvars(rvindex)%ifill = 0 + + rvindex = rvindex + 1 + restartvars(rvindex)%name = 'op_field2_id' + restartvars(rvindex)%type = pio_int + restartvars(rvindex)%ndims = 2 + restartvars(rvindex)%dims(1) = maxnflds_dim_ind + restartvars(rvindex)%dims(2) = ptapes_dim_ind + restartvars(rvindex)%fillset = .true. + restartvars(rvindex)%ifill = 0 + + rvindex = rvindex + 1 + restartvars(rvindex)%name = 'op_field1' + restartvars(rvindex)%type = pio_char + restartvars(rvindex)%ndims = 3 + restartvars(rvindex)%dims(1) = max_fieldname_len_dim_ind + restartvars(rvindex)%dims(2) = maxnflds_dim_ind + restartvars(rvindex)%dims(3) = ptapes_dim_ind + + rvindex = rvindex + 1 + restartvars(rvindex)%name = 'op_field2' + restartvars(rvindex)%type = pio_char + restartvars(rvindex)%ndims = 3 + restartvars(rvindex)%dims(1) = max_fieldname_len_dim_ind + restartvars(rvindex)%dims(2) = maxnflds_dim_ind + restartvars(rvindex)%dims(3) = ptapes_dim_ind + end subroutine restart_vars_setnames subroutine restart_dims_setnames() @@ -1366,6 +1515,8 @@ subroutine write_restart_history ( File, & type(var_desc_t), pointer :: longname_desc type(var_desc_t), pointer :: units_desc type(var_desc_t), pointer :: hwrt_prec_desc + type(var_desc_t), pointer :: hbuf_integral_desc + type(var_desc_t), pointer :: beg_nstep_desc type(var_desc_t), pointer :: xyfill_desc type(var_desc_t), pointer :: mdims_desc ! mdim name indices type(var_desc_t), pointer :: mdimname_desc ! mdim names @@ -1378,6 +1529,11 @@ subroutine write_restart_history ( File, & type(var_desc_t), pointer :: interpolate_nlon_desc type(var_desc_t), pointer :: meridional_complement_desc type(var_desc_t), pointer :: zonal_complement_desc + type(var_desc_t), pointer :: field_op_desc + type(var_desc_t), pointer :: op_field1_id_desc + type(var_desc_t), pointer :: op_field2_id_desc + type(var_desc_t), pointer :: op_field1_desc + type(var_desc_t), pointer :: op_field2_desc integer, allocatable :: allmdims(:,:,:) integer, allocatable :: xyfill(:,:) @@ -1385,7 +1541,7 @@ subroutine write_restart_history ( File, & integer, allocatable :: interp_output(:) integer :: maxnflds - + real(r8) :: integral ! hbuf area weighted integral maxnflds = maxval(nflds) allocate(xyfill(maxnflds, ptapes)) @@ -1479,6 +1635,8 @@ subroutine write_restart_history ( File, & decomp_type_desc => restartvar_getdesc('decomp_type') numlev_desc => restartvar_getdesc('numlev') hwrt_prec_desc => restartvar_getdesc('hwrt_prec') + hbuf_integral_desc => restartvar_getdesc('hbuf_integral') + beg_nstep_desc => restartvar_getdesc('beg_nstep') sseq_desc => restartvar_getdesc('sampling_seq') cm_desc => restartvar_getdesc('cell_methods') @@ -1497,6 +1655,12 @@ subroutine write_restart_history ( File, & meridional_complement_desc => restartvar_getdesc('meridional_complement') zonal_complement_desc => restartvar_getdesc('zonal_complement') + field_op_desc => restartvar_getdesc('field_op') + op_field1_id_desc => restartvar_getdesc('op_field1_id') + op_field2_id_desc => restartvar_getdesc('op_field2_id') + op_field1_desc => restartvar_getdesc('op_field1') + op_field2_desc => restartvar_getdesc('op_field2') + mdims_desc => restartvar_getdesc('mdims') mdimname_desc => restartvar_getdesc('mdimnames') fillval_desc => restartvar_getdesc('fillvalue') @@ -1519,6 +1683,9 @@ subroutine write_restart_history ( File, & ierr = pio_put_var(File, numlev_desc,start,tape(t)%hlist(f)%field%numlev) ierr = pio_put_var(File, hwrt_prec_desc,start,tape(t)%hlist(f)%hwrt_prec) + call tape(t)%hlist(f)%get_global(integral) + ierr = pio_put_var(File, hbuf_integral_desc,start,integral) + ierr = pio_put_var(File, beg_nstep_desc,start,tape(t)%hlist(f)%beg_nstep) ierr = pio_put_var(File, sseq_desc,startc,tape(t)%hlist(f)%field%sampling_seq) ierr = pio_put_var(File, cm_desc,startc,tape(t)%hlist(f)%field%cell_methods) ierr = pio_put_var(File, longname_desc,startc,tape(t)%hlist(f)%field%long_name) @@ -1528,6 +1695,11 @@ subroutine write_restart_history ( File, & ierr = pio_put_var(File, fillval_desc,start, tape(t)%hlist(f)%field%fillvalue) ierr = pio_put_var(File, meridional_complement_desc,start, tape(t)%hlist(f)%field%meridional_complement) ierr = pio_put_var(File, zonal_complement_desc,start, tape(t)%hlist(f)%field%zonal_complement) + ierr = pio_put_var(File, field_op_desc,startc, tape(t)%hlist(f)%field%field_op) + ierr = pio_put_var(File, op_field1_id_desc,start, tape(t)%hlist(f)%field%op_field1_id) + ierr = pio_put_var(File, op_field2_id_desc,start, tape(t)%hlist(f)%field%op_field2_id) + ierr = pio_put_var(File, op_field1_desc,startc, tape(t)%hlist(f)%op_field1) + ierr = pio_put_var(File, op_field2_desc,startc, tape(t)%hlist(f)%op_field2) if(associated(tape(t)%hlist(f)%field%mdims)) then allmdims(1:size(tape(t)%hlist(f)%field%mdims),f,t) = tape(t)%hlist(f)%field%mdims else @@ -1591,11 +1763,13 @@ subroutine read_restart_history (File) use ioFileMod, only: getfil use sat_hist, only: sat_hist_define, sat_hist_init use cam_grid_support, only: cam_grid_read_dist_array, cam_grid_num_grids - use cam_history_support, only: get_hist_coord_index, add_hist_coord + use cam_history_support, only: get_hist_coord_index, add_hist_coord, dim_index_2d use constituents, only: cnst_get_ind, cnst_get_type_byind + use cam_grid_support, only: cam_grid_get_areawt use shr_sys_mod, only: shr_sys_getenv use spmd_utils, only: mpicom, mpi_character, masterprocid + use time_manager, only: get_nstep ! !----------------------------------------------------------------------- ! @@ -1619,8 +1793,11 @@ subroutine read_restart_history (File) character(len=max_string_len) :: locfn ! Local filename character(len=max_fieldname_len), allocatable :: tmpname(:,:) + character(len=max_fieldname_len), allocatable :: tmpf1name(:,:) + character(len=max_fieldname_len), allocatable :: tmpf2name(:,:) integer, allocatable :: decomp(:,:), tmpnumlev(:,:) - integer, pointer :: nacs(:,:) ! accumulation counter + integer, pointer :: nacs(:,:) ! outfld accumulation counter + integer :: beg_nstep ! start timestep of this slice for nstep accumulation counter character(len=max_fieldname_len) :: fname_tmp ! local copy of field name character(len=max_fieldname_len) :: dname_tmp ! local copy of dim name @@ -1635,7 +1812,15 @@ subroutine read_restart_history (File) type(var_desc_t) :: fillval_desc type(var_desc_t) :: meridional_complement_desc type(var_desc_t) :: zonal_complement_desc + type(var_desc_t) :: field_op_desc + type(var_desc_t) :: op_field1_id_desc + type(var_desc_t) :: op_field2_id_desc + type(var_desc_t) :: op_field1_desc + type(var_desc_t) :: op_field2_desc + type(dim_index_2d) :: dimind ! 2-D dimension index integer, allocatable :: tmpprec(:,:) + real(r8), allocatable :: tmpintegral(:,:) + integer, allocatable :: tmpbeg_nstep(:,:) integer, allocatable :: xyfill(:,:) integer, allocatable :: allmdims(:,:,:) integer, allocatable :: is_subcol(:,:) @@ -1658,6 +1843,8 @@ subroutine read_restart_history (File) integer :: fdecomp ! Grid ID for field integer :: idx character(len=3) :: mixing_ratio + integer :: c,ib,ie,jb,je,k,cnt,wtidx(1) + real(r8), pointer :: areawt(:) ! pointer to areawt values for attribute ! ! Get users logname and machine hostname @@ -1735,33 +1922,38 @@ subroutine read_restart_history (File) ierr = pio_inq_varid(File, 'lcltod_stop', vdesc) ierr = pio_get_var(File, vdesc, lcltod_stop(1:mtapes)) - - - allocate(tmpname(maxnflds, mtapes), decomp(maxnflds, mtapes), tmpnumlev(maxnflds,mtapes)) ierr = pio_inq_varid(File, 'field_name', vdesc) ierr = pio_get_var(File, vdesc, tmpname) - ierr = pio_inq_varid(File, 'decomp_type', vdesc) ierr = pio_get_var(File, vdesc, decomp) ierr = pio_inq_varid(File, 'numlev', vdesc) ierr = pio_get_var(File, vdesc, tmpnumlev) - allocate(tmpprec(maxnflds,mtapes)) + ierr = pio_inq_varid(File, 'hbuf_integral',vdesc) + allocate(tmpintegral(maxnflds,mtapes)) + ierr = pio_get_var(File, vdesc, tmpintegral(:,:)) + + ierr = pio_inq_varid(File, 'hwrt_prec',vdesc) + allocate(tmpprec(maxnflds,mtapes)) ierr = pio_get_var(File, vdesc, tmpprec(:,:)) - allocate(xyfill(maxnflds,mtapes)) + ierr = pio_inq_varid(File, 'beg_nstep',vdesc) + allocate(tmpbeg_nstep(maxnflds,mtapes)) + ierr = pio_get_var(File, vdesc, tmpbeg_nstep(:,:)) + ierr = pio_inq_varid(File, 'xyfill', vdesc) + allocate(xyfill(maxnflds,mtapes)) ierr = pio_get_var(File, vdesc, xyfill) - allocate(is_subcol(maxnflds,mtapes)) ierr = pio_inq_varid(File, 'is_subcol', vdesc) + allocate(is_subcol(maxnflds,mtapes)) ierr = pio_get_var(File, vdesc, is_subcol) !! interpolated output - allocate(interp_output(mtapes)) ierr = pio_inq_varid(File, 'interpolate_output', vdesc) + allocate(interp_output(mtapes)) ierr = pio_get_var(File, vdesc, interp_output) interpolate_output(1:mtapes) = interp_output(1:mtapes) > 0 if (ptapes > mtapes) then @@ -1816,6 +2008,13 @@ subroutine read_restart_history (File) end if end do + allocate(tmpf1name(maxnflds, mtapes), tmpf2name(maxnflds, mtapes)) + ierr = pio_inq_varid(File, 'op_field1', vdesc) + ierr = pio_get_var(File, vdesc, tmpf1name) + ierr = pio_inq_varid(File, 'op_field2', vdesc) + ierr = pio_get_var(File, vdesc, tmpf2name) + + ierr = pio_inq_varid(File, 'avgflag', avgflag_desc) ierr = pio_inq_varid(File, 'long_name', longname_desc) @@ -1826,6 +2025,9 @@ subroutine read_restart_history (File) ierr = pio_inq_varid(File, 'fillvalue', fillval_desc) ierr = pio_inq_varid(File, 'meridional_complement', meridional_complement_desc) ierr = pio_inq_varid(File, 'zonal_complement', zonal_complement_desc) + ierr = pio_inq_varid(File, 'field_op', field_op_desc) + ierr = pio_inq_varid(File, 'op_field1_id', op_field1_id_desc) + ierr = pio_inq_varid(File, 'op_field2_id', op_field2_id_desc) rgnht(:)=.false. @@ -1851,6 +2053,11 @@ subroutine read_restart_history (File) ierr = pio_get_var(File,fillval_desc, (/f,t/), tape(t)%hlist(f)%field%fillvalue) ierr = pio_get_var(File,meridional_complement_desc, (/f,t/), tape(t)%hlist(f)%field%meridional_complement) ierr = pio_get_var(File,zonal_complement_desc, (/f,t/), tape(t)%hlist(f)%field%zonal_complement) + tape(t)%hlist(f)%field%field_op(1:field_op_len) = ' ' + ierr = pio_get_var(File,field_op_desc, (/1,f,t/), tape(t)%hlist(f)%field%field_op) + call strip_null(tape(t)%hlist(f)%field%field_op) + ierr = pio_get_var(File,op_field1_id_desc, (/f,t/), tape(t)%hlist(f)%field%op_field1_id) + ierr = pio_get_var(File,op_field2_id_desc, (/f,t/), tape(t)%hlist(f)%field%op_field2_id) ierr = pio_get_var(File,avgflag_desc, (/f,t/), tape(t)%hlist(f)%avgflag) ierr = pio_get_var(File,longname_desc, (/1,f,t/), tape(t)%hlist(f)%field%long_name) ierr = pio_get_var(File,units_desc, (/1,f,t/), tape(t)%hlist(f)%field%units) @@ -1871,11 +2078,16 @@ subroutine read_restart_history (File) tape(t)%hlist(f)%field%is_subcol=.false. end if call strip_null(tmpname(f,t)) + call strip_null(tmpf1name(f,t)) + call strip_null(tmpf2name(f,t)) tape(t)%hlist(f)%field%name = tmpname(f,t) + tape(t)%hlist(f)%op_field1 = tmpf1name(f,t) + tape(t)%hlist(f)%op_field2 = tmpf2name(f,t) tape(t)%hlist(f)%field%decomp_type = decomp(f,t) tape(t)%hlist(f)%field%numlev = tmpnumlev(f,t) tape(t)%hlist(f)%hwrt_prec = tmpprec(f,t) - + tape(t)%hlist(f)%beg_nstep = tmpbeg_nstep(f,t) + call tape(t)%hlist(f)%put_global(tmpintegral(f,t)) ! If the field is an advected constituent set the mixing_ratio attribute fname_tmp = strip_suffix(tape(t)%hlist(f)%field%name) call cnst_get_ind(fname_tmp, idx, abort=.false.) @@ -1892,11 +2104,14 @@ subroutine read_restart_history (File) tape(t)%hlist(f)%field%mdims(i) = get_hist_coord_index(mdimnames(allmdims(i,f,t))) end do end if - end do end do - deallocate(tmpname, tmpnumlev, tmpprec, decomp, xyfill, is_subcol) + deallocate(tmpname, tmpnumlev, tmpprec, tmpbeg_nstep, decomp, xyfill, is_subcol, tmpintegral) deallocate(mdimnames) + deallocate(tmpf1name,tmpf2name) + + allocate(grid_wts(cam_grid_num_grids() + 1)) + allgrids_wt => grid_wts allocate(gridsontape(cam_grid_num_grids() + 1, ptapes)) gridsontape = -1 @@ -1943,7 +2158,39 @@ subroutine read_restart_history (File) exit end if end do + ! + !rebuild area wt array and set field wbuf pointer + ! + if (tape(t)%hlist(f)%avgflag .eq. 'N') then ! set up area weight buffer + nullify(tape(t)%hlist(f)%wbuf) + if (any(allgrids_wt(:)%decomp_type == tape(t)%hlist(f)%field%decomp_type)) then + wtidx=MAXLOC(allgrids_wt(:)%decomp_type, MASK = allgrids_wt(:)%decomp_type .EQ. fdecomp) + tape(t)%hlist(f)%wbuf => allgrids_wt(wtidx(1))%wbuf + else + ! area weights not found for this grid, then create them + ! first check for an available spot in the array + if (any(allgrids_wt(:)%decomp_type == -1)) then + wtidx=MINLOC(allgrids_wt(:)%decomp_type) + else + call endrun('cam_history.F90:read_restart_history: Error initializing allgrids_wt with area weights') + end if + allgrids_wt(wtidx)%decomp_type=fdecomp + areawt => cam_grid_get_areawt(fdecomp) + allocate(allgrids_wt(wtidx(1))%wbuf(begdim1:enddim1,begdim3:enddim3)) + cnt=0 + do c=begdim3,enddim3 + dimind = tape(t)%hlist(f)%field%get_dims(c) + ib=dimind%beg1 + ie=dimind%end1 + do i=ib,ie + cnt=cnt+1 + allgrids_wt(wtidx(1))%wbuf(i,c)=areawt(cnt) + end do + end do + tape(t)%hlist(f)%wbuf => allgrids_wt(wtidx(1))%wbuf + endif + endif end do end do ! @@ -2050,6 +2297,9 @@ subroutine read_restart_history (File) tape(t)%hlist(f)%nacs(1,:)= nacsval end if + ierr = pio_inq_varid(tape(t)%File, trim(fname_tmp)//'_nacs', vdesc) + call cam_pio_var_info(tape(t)%File, vdesc, nacsdimcnt, dimids, dimlens) + end do ! ! Done reading this history restart file @@ -2210,6 +2460,8 @@ subroutine AvgflagToString(avgflag, time_op) time_op(:) = 'mean' case ('B') time_op(:) = 'mean00z' + case ('N') + time_op(:) = 'mean_over_nsteps' case ('I') time_op(:) = ' ' case ('X') @@ -2430,6 +2682,8 @@ subroutine fldlst () end if + allocate(grid_wts(cam_grid_num_grids() + 1)) + allgrids_wt => grid_wts allocate(gridsontape(cam_grid_num_grids() + 1, ptapes)) gridsontape = -1 @@ -2510,6 +2764,7 @@ subroutine fldlst () do ff=1,nflds(t) nullify(tape(t)%hlist(ff)%hbuf) nullify(tape(t)%hlist(ff)%sbuf) + nullify(tape(t)%hlist(ff)%wbuf) nullify(tape(t)%hlist(ff)%nacs) nullify(tape(t)%hlist(ff)%varid) end do @@ -2580,6 +2835,9 @@ subroutine fldlst () end do end do + ! Initialize the field names/ids for each composed field on tapes + call define_composed_field_ids(t) + end do ! do t=1,ptapes deallocate(gridsontape) @@ -3283,6 +3541,7 @@ end subroutine subcol_field_avg_handler type (active_entry), pointer :: otape(:) ! Local history_tape pointer real(r8),pointer :: hbuf(:,:) ! history buffer + real(r8),pointer :: wbuf(:) ! area weights for field real(r8),pointer :: sbuf(:,:) ! variance buffer integer, pointer :: nacs(:) ! accumulation counter integer :: begdim2, enddim2, endi @@ -3322,6 +3581,9 @@ end subroutine subcol_field_avg_handler avgflag = otape(t)%hlist(f)%avgflag nacs => otape(t)%hlist(f)%nacs(:,c) hbuf => otape(t)%hlist(f)%hbuf(:,:,c) + if (associated(tape(t)%hlist(f)%wbuf)) then + wbuf => otape(t)%hlist(f)%wbuf(:,c) + endif if (associated(tape(t)%hlist(f)%sbuf)) then sbuf => otape(t)%hlist(f)%sbuf(:,:,c) endif @@ -3395,6 +3657,10 @@ end subroutine subcol_field_avg_handler call hbuf_accum_add00z(hbuf, ufield, nacs, dimind, pcols, & flag_xyfill, fillvalue) + case ('N') ! Time average over nsteps + call hbuf_accum_add(hbuf, ufield, nacs, dimind, pcols, & + flag_xyfill, fillvalue) + case ('X') ! Maximum over time call hbuf_accum_max (hbuf, ufield, nacs, dimind, pcols, & flag_xyfill, fillvalue) @@ -3433,6 +3699,10 @@ end subroutine subcol_field_avg_handler call hbuf_accum_add00z(hbuf, field, nacs, dimind, idim, & flag_xyfill, fillvalue) + case ('N') ! Time average over nsteps + call hbuf_accum_add (hbuf, field, nacs, dimind, idim, & + flag_xyfill, fillvalue) + case ('X') ! Maximum over time call hbuf_accum_max (hbuf, field, nacs, dimind, idim, & flag_xyfill, fillvalue) @@ -3464,7 +3734,7 @@ end subroutine outfld !####################################################################### - subroutine get_field_properties(fname, found, tape_out, ff_out, no_tape_check_in) + subroutine get_field_properties(fname, found, tape_out, ff_out, no_tape_check_in, f_out) implicit none ! @@ -3487,6 +3757,7 @@ subroutine get_field_properties(fname, found, tape_out, ff_out, no_tape_check_in type(active_entry), pointer, optional :: tape_out(:) integer, intent(out), optional :: ff_out logical, intent(in), optional :: no_tape_check_in + integer, intent(out), optional :: f_out(:) ! ! Local variables @@ -3515,6 +3786,9 @@ subroutine get_field_properties(fname, found, tape_out, ff_out, no_tape_check_in if (present(ff_out)) then ff_out = -1 end if + if (present(f_out)) then + f_out = -1 + end if ! ! If ( ff < 0 ), the field is not defined on the masterlist. This check @@ -3548,8 +3822,12 @@ subroutine get_field_properties(fname, found, tape_out, ff_out, no_tape_check_in if (present(ff_out)) then ff_out = ff end if - ! We found the info so we are done with the loop - exit + if (present(f_out)) then + f_out(t) = masterlist(ff)%thisentry%htapeindx(t) + else + ! only need to loop through all ptapes if f_out present + exit + end if end if end do @@ -3834,15 +4112,16 @@ subroutine h_override (t) type(master_entry), pointer :: listentry - avgflg = avgflag_pertape(t) - listentry=>masterlinkedlist do while(associated(listentry)) - call AvgflagToString(avgflg, listentry%time_op(t)) - listentry%avgflag(t) = avgflag_pertape(t) - listentry=>listentry%next_entry + ! Budgets require flag to be N, dont override + if (listentry%avgflag(t) /= 'N' ) then + call AvgflagToString(avgflg, listentry%time_op(t)) + listentry%avgflag(t) = avgflag_pertape(t) + end if + listentry=>listentry%next_entry end do end subroutine h_override @@ -4547,6 +4826,7 @@ end subroutine h_define subroutine h_normalize (f, t) use cam_history_support, only: dim_index_2d + use time_manager, only: get_nstep ! !----------------------------------------------------------------------- @@ -4572,10 +4852,13 @@ subroutine h_normalize (f, t) integer :: begdim3, enddim3 ! Chunk or block bounds integer :: k ! level integer :: i, ii + integer :: currstep, nsteps real(r8) :: variance, tmpfill logical :: flag_xyfill ! non-applicable xy points flagged with fillvalue character*1 :: avgflag ! averaging flag + character(len=max_chars) :: errmsg + character(len=*), parameter :: sub='H_NORMALIZE:' call t_startf ('h_normalize') @@ -4620,6 +4903,20 @@ subroutine h_normalize (f, t) end do end if end if + currstep=get_nstep() + if (avgflag == 'N' .and. currstep > 0) then + if( currstep > tape(t)%hlist(f)%beg_nstep) then + nsteps=currstep-tape(t)%hlist(f)%beg_nstep + do k=jb,je + tape(t)%hlist(f)%hbuf(ib:ie,k,c) = & + tape(t)%hlist(f)%hbuf(ib:ie,k,c) & + / nsteps + end do + else + write(errmsg,*) sub,'FATAL: bad nstep normalization, currstep, beg_nstep=',currstep,',',tape(t)%hlist(f)%beg_nstep + call endrun(trim(errmsg)) + end if + end if if (avgflag == 'S') then ! standard deviation ... ! from http://www.johndcook.com/blog/standard_deviation/ @@ -4647,6 +4944,7 @@ end subroutine h_normalize subroutine h_zero (f, t) use cam_history_support, only: dim_index_2d + use time_manager, only: get_nstep, is_first_restart_step ! !----------------------------------------------------------------------- ! @@ -4679,6 +4977,9 @@ subroutine h_zero (f, t) end do tape(t)%hlist(f)%nacs(:,:) = 0 + !Don't reset beg_nstep if this is a restart + if (.not. is_first_restart_step()) tape(t)%hlist(f)%beg_nstep = get_nstep() + call t_stopf ('h_zero') return @@ -4686,6 +4987,127 @@ end subroutine h_zero !####################################################################### + subroutine h_global (f, t) + + use cam_history_support, only: dim_index_2d + use shr_reprosum_mod, only: shr_reprosum_calc + use spmd_utils, only: mpicom + use shr_const_mod, only: PI => SHR_CONST_PI + ! + !----------------------------------------------------------------------- + ! + ! Purpose: compute globals of field + ! + ! Method: Loop through fields on the tape + ! + !----------------------------------------------------------------------- + ! + integer, intent(in) :: f ! field index + integer, intent(in) :: t ! tape index + ! + ! Local workspace + ! + type (dim_index_2d) :: dimind ! 2-D dimension index + integer :: ie ! dim3 index + integer :: count ! tmp index + integer :: i1 ! dim1 index + integer :: j1 ! dim2 index + integer :: fdims(3) ! array shape + integer :: begdim1,enddim1,begdim2,enddim2,begdim3,enddim3 ! + real(r8) :: globalsum(1) ! globalsum + real(r8), allocatable :: globalarr(:) ! globalarr values for this pe + + call t_startf ('h_global') + + ! wbuf contains the area weighting for this field decomposition + if (associated(tape(t)%hlist(f)%wbuf) ) then + + begdim1 = tape(t)%hlist(f)%field%begdim1 + enddim1 = tape(t)%hlist(f)%field%enddim1 + fdims(1) = enddim1 - begdim1 + 1 + begdim2 = tape(t)%hlist(f)%field%begdim2 + enddim2 = tape(t)%hlist(f)%field%enddim2 + fdims(2) = enddim2 - begdim2 + 1 + begdim3 = tape(t)%hlist(f)%field%begdim3 + enddim3 = tape(t)%hlist(f)%field%enddim3 + fdims(3) = enddim3 - begdim3 + 1 + + allocate(globalarr(fdims(1)*fdims(2)*fdims(3))) + count=0 + globalarr=0._r8 + do ie = begdim3, enddim3 + dimind = tape(t)%hlist(f)%field%get_dims(ie) + do j1 = dimind%beg2, dimind%end2 + do i1 = dimind%beg1, dimind%end1 + count=count+1 + globalarr(count)=globalarr(count)+tape(t)%hlist(f)%hbuf(i1,j1,ie)*tape(t)%hlist(f)%wbuf(i1,ie) + end do + end do + end do + ! call fixed-point algorithm + call shr_reprosum_calc (globalarr, globalsum, count, count, 1, commid=mpicom) + if (masterproc) write(iulog,*)'h_global:field:',trim(tape(t)%hlist(f)%field%name),' global integral=',globalsum(1) + ! store global entry for this history tape entry + call tape(t)%hlist(f)%put_global(globalsum(1)) + ! deallocate temp array + deallocate(globalarr) + end if + call t_stopf ('h_global') + end subroutine h_global + + subroutine h_field_op (f, t) + use cam_history_support, only: dim_index_2d + ! + !----------------------------------------------------------------------- + ! + ! Purpose: run field sum or dif opperation on all contructed fields + ! + ! Method: Loop through fields on the tape + ! + !----------------------------------------------------------------------- + ! + integer, intent(in) :: f ! field index + integer, intent(in) :: t ! tape index + ! + ! Local workspace + ! + type (dim_index_2d) :: dimind ! 2-D dimension index + integer :: c ! chunk index + integer :: f1,f2 ! fields to be operated on + integer :: begdim1, begdim2, begdim3 ! on-node chunk or lat start index + integer :: enddim1, enddim2, enddim3 ! on-node chunk or lat end index + character(len=field_op_len) :: optype ! field operation only sum or diff supported + + call t_startf ('h_field_op') + f1 = tape(t)%hlist(f)%field%op_field1_id + f2 = tape(t)%hlist(f)%field%op_field2_id + optype = trim(adjustl(tape(t)%hlist(f)%field%field_op)) + + begdim3 = tape(t)%hlist(f)%field%begdim3 + enddim3 = tape(t)%hlist(f)%field%enddim3 + + do c = begdim3, enddim3 + dimind = tape(t)%hlist(f)%field%get_dims(c) + if (trim(optype) == 'dif') then + tape(t)%hlist(f)%hbuf(dimind%beg1:dimind%end1,dimind%beg2:dimind%end2,c) = & + tape(t)%hlist(f1)%hbuf(dimind%beg1:dimind%end1,dimind%beg2:dimind%end2,c) - & + tape(t)%hlist(f2)%hbuf(dimind%beg1:dimind%end1,dimind%beg2:dimind%end2,c) + else if (trim(optype) == 'sum') then + tape(t)%hlist(f)%hbuf(dimind%beg1:dimind%end1,dimind%beg2:dimind%end2,c) = & + tape(t)%hlist(f1)%hbuf(dimind%beg1:dimind%end1,dimind%beg2:dimind%end2,c) + & + tape(t)%hlist(f2)%hbuf(dimind%beg1:dimind%end1,dimind%beg2:dimind%end2,c) + else + call endrun('h_field_op: ERROR: composed field operation type unknown:'//trim(optype)) + end if + end do + ! Set nsteps for composed fields using value of one of the component fields + tape(t)%hlist(f)%beg_nstep=tape(t)%hlist(f1)%beg_nstep + tape(t)%hlist(f)%nacs(:,:)=tape(t)%hlist(f1)%nacs(:,:) + call t_stopf ('h_field_op') + end subroutine h_field_op + + !####################################################################### + subroutine dump_field (f, t, restart) use cam_history_support, only: history_patch_t, dim_index_2d, dim_index_3d use cam_grid_support, only: cam_grid_write_dist_array, cam_grid_dimensions @@ -5158,13 +5580,23 @@ subroutine wshist (rgnht_in) ierr = pio_put_var (tape(t)%File, tape(t)%time_writtenid, startc, countc, (/ctime/)) if(.not. restart) then - !$OMP PARALLEL DO PRIVATE (F) - do f=1,nflds(t) - ! Normalized averaged fields - if (tape(t)%hlist(f)%avgflag /= 'I') then - call h_normalize (f, t) - end if - end do + !$OMP PARALLEL DO PRIVATE (F) + do f=1,nflds(t) + ! Normalize all non composed fields, composed fields are calculated next using the normalized components + if (tape(t)%hlist(f)%avgflag /= 'I'.and..not.tape(t)%hlist(f)%field%is_composed()) then + call h_normalize (f, t) + end if + end do + end if + + if(.not. restart) then + !$OMP PARALLEL DO PRIVATE (F) + do f=1,nflds(t) + ! calculate composed fields from normalized components + if (tape(t)%hlist(f)%field%is_composed()) then + call h_field_op (f, t) + end if + end do end if ! ! Write field to history tape. Note that this is NOT threaded due to netcdf limitations @@ -5175,11 +5607,14 @@ subroutine wshist (rgnht_in) end do call t_stopf ('dump_field') ! + ! Calculate globals + ! + do f=1,nflds(t) + call h_global(f, t) + end do + ! ! Zero history buffers and accumulators now that the fields have been written. ! - - - if(restart) then do f=1,nflds(t) if(associated(tape(t)%hlist(f)%varid)) then @@ -5205,7 +5640,8 @@ end subroutine wshist !####################################################################### subroutine addfld_1d(fname, vdim_name, avgflag, units, long_name, & - gridname, flag_xyfill, sampling_seq, standard_name, fill_value) + gridname, flag_xyfill, sampling_seq, standard_name, fill_value, & + optype, op_f1name, op_f2name) ! !----------------------------------------------------------------------- @@ -5234,7 +5670,9 @@ subroutine addfld_1d(fname, vdim_name, avgflag, units, long_name, & ! every other; only during LW/SW radiation calcs, etc. character(len=*), intent(in), optional :: standard_name ! CF standard name (max_chars) real(r8), intent(in), optional :: fill_value - + character(len=*), intent(in), optional :: optype ! currently 'dif' or 'sum' is supported + character(len=*), intent(in), optional :: op_f1name ! first field to be operated on + character(len=*), intent(in), optional :: op_f2name ! second field which is subtracted from or added to first field ! ! Local workspace ! @@ -5252,12 +5690,14 @@ subroutine addfld_1d(fname, vdim_name, avgflag, units, long_name, & dimnames(1) = trim(vdim_name) end if call addfld(fname, dimnames, avgflag, units, long_name, gridname, & - flag_xyfill, sampling_seq, standard_name, fill_value) + flag_xyfill, sampling_seq, standard_name, fill_value, optype, op_f1name, & + op_f2name) end subroutine addfld_1d subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & - gridname, flag_xyfill, sampling_seq, standard_name, fill_value) + gridname, flag_xyfill, sampling_seq, standard_name, fill_value, optype, & + op_f1name, op_f2name) ! !----------------------------------------------------------------------- @@ -5272,7 +5712,7 @@ subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & use cam_history_support, only: fillvalue, hist_coord_find_levels use cam_grid_support, only: cam_grid_id, cam_grid_is_zonal use cam_grid_support, only: cam_grid_get_coord_names - use constituents, only: pcnst, cnst_get_ind, cnst_get_type_byind + use constituents, only: cnst_get_ind, cnst_get_type_byind ! ! Arguments @@ -5290,6 +5730,9 @@ subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & ! every other; only during LW/SW radiation calcs, etc. character(len=*), intent(in), optional :: standard_name ! CF standard name (max_chars) real(r8), intent(in), optional :: fill_value + character(len=*), intent(in), optional :: optype ! currently 'dif' or 'sum' supported + character(len=*), intent(in), optional :: op_f1name ! first field to be operated on + character(len=*), intent(in), optional :: op_f2name ! second field which is subtracted from or added to first field ! ! Local workspace @@ -5299,10 +5742,13 @@ subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & character(len=128) :: errormsg character(len=3) :: mixing_ratio type(master_entry), pointer :: listentry + type(master_entry), pointer :: f1listentry,f2listentry integer :: dimcnt integer :: idx + character(len=*), parameter :: subname='ADDFLD_ND' + if (htapes_defined) then call endrun ('ADDFLD: Attempt to add field '//trim(fname)//' after history files set') end if @@ -5352,6 +5798,11 @@ subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & listentry%field%mixing_ratio = mixing_ratio listentry%field%meridional_complement = -1 listentry%field%zonal_complement = -1 + listentry%field%field_op = '' + listentry%field%op_field1_id = -1 + listentry%field%op_field2_id = -1 + listentry%op_field1 = '' + listentry%op_field2 = '' listentry%htapeindx(:) = -1 listentry%act_sometape = .false. listentry%actflag(:) = .false. @@ -5453,6 +5904,45 @@ subroutine addfld_nd(fname, dimnames, avgflag, units, long_name, & call AvgflagToString(avgflag, listentry%time_op(dimcnt)) end do + if (present(optype)) then + ! make sure optype is "sum" or "dif" + if (.not.(trim(optype) == 'dif' .or. trim(optype) == 'sum')) then + write(errormsg, '(2a)')': Fatal : optype must be "sum" or "dif" not ',trim(optype) + call endrun (trim(subname)//errormsg) + end if + listentry%field%field_op = optype + if (present(op_f1name).and.present(op_f2name)) then + ! Look for the field IDs + f1listentry => get_entry_by_name(masterlinkedlist, trim(op_f1name)) + f2listentry => get_entry_by_name(masterlinkedlist, trim(op_f2name)) + if (associated(f1listentry).and.associated(f2listentry)) then + listentry%op_field1=trim(op_f1name) + listentry%op_field2=trim(op_f2name) + else + write(errormsg, '(5a)') ': Attempt to create a composed field using (', & + trim(op_f1name), ', ', trim(op_f2name), & + ') but both fields have not been added to masterlist via addfld first' + call endrun (trim(subname)//errormsg) + end if + else + write(errormsg, *) ': Attempt to create a composed field but no component fields have been specified' + call endrun (trim(subname)//errormsg) + end if + + else + if (present(op_f1name)) then + write(errormsg, '(3a)') ': creating a composed field using component field 1:',& + trim(op_f1name),' but no field operation (optype=sum or dif) has been defined' + call endrun (trim(subname)//errormsg) + end if + if (present(op_f2name)) then + write(errormsg, '(3a)') ': creating a composed field using component field 2:',& + trim(op_f2name),' but no field operation (optype=sum or dif) has been defined' + call endrun (trim(subname)//errormsg) + end if + end if + + nullify(listentry%next_entry) call add_entry_to_master(listentry) @@ -5461,7 +5951,7 @@ end subroutine addfld_nd !####################################################################### - ! field_part_of_vector: Determinie if fname is part of a vector set + ! field_part_of_vector: Determine if fname is part of a vector set ! Optionally fill in the names of the vector set fields logical function field_part_of_vector(fname, meridional_name, zonal_name) @@ -5501,6 +5991,53 @@ logical function field_part_of_vector(fname, meridional_name, zonal_name) end function field_part_of_vector + !####################################################################### + ! composed field_info: Determine if a field is derived from a mathematical + ! operation using 2 other defined fields. Optionally, + ! retrieve names of the composing fields + subroutine composed_field_info(fname, is_composed, fname1, fname2) + + ! Dummy arguments + character(len=*), intent(in) :: fname + logical, intent(out) :: is_composed + character(len=*), optional, intent(out) :: fname1 + character(len=*), optional, intent(out) :: fname2 + + ! Local variables + type(master_entry), pointer :: listentry + character(len=128) :: errormsg + character(len=*), parameter :: subname='composed_field_info' + + listentry => get_entry_by_name(masterlinkedlist, fname) + if (associated(listentry)) then + if ( (len_trim(listentry%op_field1) > 0) .or. & + (len_trim(listentry%op_field2) > 0)) then + is_composed = .true. + else + is_composed = .false. + end if + if (is_composed) then + if (present(fname1)) then + fname1=trim(listentry%op_field1) + end if + if (present(fname2)) then + fname2=trim(listentry%op_field2) + end if + else + if (present(fname1)) then + fname1 = '' + end if + if (present(fname2)) then + fname2 = '' + end if + end if + else + write(errormsg, '(3a)') ': Field:',trim(fname),' not defined in masterlist' + call endrun (trim(subname)//errormsg) + end if + + end subroutine composed_field_info + ! register_vector_field: Register a pair of history field names as ! being a vector complement set. diff --git a/src/control/cam_history_buffers.F90 b/src/control/cam_history_buffers.F90 index f9a141247a..b26162753c 100644 --- a/src/control/cam_history_buffers.F90 +++ b/src/control/cam_history_buffers.F90 @@ -111,6 +111,7 @@ subroutine hbuf_accum_add (buf8, field, nacs, dimind, idim, flag_xyfill, fillval end subroutine hbuf_accum_add !####################################################################### + subroutine hbuf_accum_variance (hbuf, sbuf, field, nacs, dimind, idim, flag_xyfill, fillvalue) ! !----------------------------------------------------------------------- diff --git a/src/control/cam_history_support.F90 b/src/control/cam_history_support.F90 index 8251ebde95..495ce7b519 100644 --- a/src/control/cam_history_support.F90 +++ b/src/control/cam_history_support.F90 @@ -10,7 +10,6 @@ module cam_history_support !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! use shr_kind_mod, only: r8=>shr_kind_r8, shr_kind_cl, shr_kind_cxx - use shr_sys_mod, only: shr_sys_flush use pio, only: var_desc_t, file_desc_t use cam_abortutils, only: endrun use cam_logfile, only: iulog @@ -25,9 +24,10 @@ module cam_history_support integer, parameter, public :: max_string_len = shr_kind_cxx integer, parameter, public :: max_chars = shr_kind_cl ! max chars for char variables - integer, parameter, public :: fieldname_len = 32 ! max chars for field name - integer, parameter, public :: fieldname_suffix_len = 3 ! length of field name suffix ("&IC") - integer, parameter, public :: fieldname_lenp2 = fieldname_len + 2 ! allow for extra characters + integer, parameter, public :: field_op_len = 3 ! max chars for field operation string (sum/dif) + integer, parameter, public :: fieldname_len = 32 ! max chars for field name + integer, parameter, public :: fieldname_suffix_len = 3 ! length of field name suffix ("&IC") + integer, parameter, public :: fieldname_lenp2 = fieldname_len + 2 ! allow for extra characters ! max_fieldname_len = max chars for field name (including suffix) integer, parameter, public :: max_fieldname_len = fieldname_len + fieldname_suffix_len @@ -118,6 +118,10 @@ module cam_history_support integer :: meridional_complement ! meridional field id or -1 integer :: zonal_complement ! zonal field id or -1 + character(len=field_op_len) :: field_op = '' ! 'sum' or 'dif' + integer :: op_field1_id ! first field id or -1 + integer :: op_field2_id ! second field id or -1 + character(len=max_fieldname_len) :: name ! field name character(len=max_chars) :: long_name ! long name character(len=max_chars) :: units ! units @@ -127,6 +131,7 @@ module cam_history_support ! radiation calcs; etc. character(len=max_chars) :: cell_methods ! optional cell_methods attribute contains + procedure :: is_composed => field_info_is_composed procedure :: get_shape => field_info_get_shape procedure :: get_bounds => field_info_get_bounds procedure :: get_dims_2d => field_info_get_dims_2d @@ -153,17 +158,27 @@ module cam_history_support ! !--------------------------------------------------------------------------- type, public:: hentry - type (field_info) :: field ! field information - character(len=1) :: avgflag ! averaging flag - character(len=max_chars) :: time_op ! time operator (e.g. max, min, avg) + type (field_info) :: field ! field information + character(len=1) :: avgflag ! averaging flag + character(len=max_chars) :: time_op ! time operator (e.g. max, min, avg) + character(len=max_fieldname_len) :: op_field1 ! field1 name for sum or dif operation + character(len=max_fieldname_len) :: op_field2 ! field2 name for sum or dif operation - integer :: hwrt_prec ! history output precision + integer :: hwrt_prec ! history output precision real(r8), pointer :: hbuf(:,:,:) => NULL() + real(r8), private :: hbuf_integral ! area weighted integral of active field real(r8), pointer :: sbuf(:,:,:) => NULL() ! for standard deviation + real(r8), pointer :: wbuf(:,:) => NULL() ! pointer to area weights type(var_desc_t), pointer :: varid(:) => NULL() ! variable ids integer, pointer :: nacs(:,:) => NULL() ! accumulation counter type(var_desc_t), pointer :: nacs_varid => NULL() + integer :: beg_nstep ! starting time step for nstep normalization + type(var_desc_t), pointer :: beg_nstep_varid=> NULL() type(var_desc_t), pointer :: sbuf_varid => NULL() + type(var_desc_t), pointer :: wbuf_varid => NULL() + contains + procedure :: get_global => hentry_get_global + procedure :: put_global => hentry_put_global end type hentry !--------------------------------------------------------------------------- @@ -435,6 +450,14 @@ type(dim_index_3d) function field_info_get_dims_3d(this) result(dims) end function field_info_get_dims_3d + ! field_info_is_composed: Return whether this field is composed of two other fields + pure logical function field_info_is_composed(this) + class(field_info), intent(IN) :: this + + field_info_is_composed = ((trim(adjustl(this%field_op))=='sum' .or. trim(adjustl(this%field_op))=='dif') .and. & + this%op_field1_id /= -1 .and. this%op_field2_id /= -1) + end function field_info_is_composed + ! field_info_get_shape: Return a pointer to the field's global shape. ! Calculate it first if necessary subroutine field_info_get_shape(this, shape_out, rank_out) @@ -503,6 +526,26 @@ subroutine field_info_get_bounds(this, dim, beg, end) end subroutine field_info_get_bounds + subroutine hentry_get_global(this, gval) + + ! Dummy arguments + class(hentry) :: this + real(r8), intent(out) :: gval + + gval=this%hbuf_integral + + end subroutine hentry_get_global + + subroutine hentry_put_global(this, gval) + + ! Dummy arguments + class(hentry) :: this + real(r8), intent(in) :: gval + + this%hbuf_integral=gval + + end subroutine hentry_put_global + ! history_patch_write_attrs: Define coordinate variables and attributes ! for a patch subroutine history_patch_write_attrs(this, File) @@ -651,16 +694,8 @@ subroutine history_patch_write_vals(this, File) type(cam_grid_patch_t), pointer :: patchptr type(var_desc_t), pointer :: vardesc => NULL() ! PIO var desc character(len=128) :: errormsg - character(len=max_chars) :: lat_name - character(len=max_chars) :: lon_name - character(len=max_chars) :: col_name - character(len=max_chars) :: temp_str - integer :: dimid ! PIO dimension ID integer :: num_patches - integer :: temp1, temp2 - integer :: latid, lonid ! Coordinate dims integer :: i - logical :: col_only num_patches = size(this%patches) if (.not. associated(this%header_info)) then @@ -957,6 +992,9 @@ subroutine field_copy(f_out, f_in) f_out%meridional_complement = f_in%meridional_complement ! id or -1 f_out%zonal_complement = f_in%zonal_complement ! id or -1 + f_out%field_op = f_in%field_op ! sum,dif, or '' + f_out%op_field1_id = f_in%op_field1_id ! id or -1 + f_out%op_field2_id = f_in%op_field2_id ! id or -1 f_out%name = f_in%name ! field name f_out%long_name = f_in%long_name ! long name diff --git a/src/control/camsrfexch.F90 b/src/control/camsrfexch.F90 index 6715b6f4cd..de1ea4ce6e 100644 --- a/src/control/camsrfexch.F90 +++ b/src/control/camsrfexch.F90 @@ -61,6 +61,7 @@ module camsrfexch real(r8) :: co2prog(pcols) ! prognostic co2 real(r8) :: co2diag(pcols) ! diagnostic co2 real(r8) :: ozone(pcols) ! surface ozone concentration (mole/mole) + real(r8) :: lightning_flash_freq(pcols) ! cloud-to-ground lightning flash frequency (/min) real(r8) :: psl(pcols) real(r8) :: bcphiwet(pcols) ! wet deposition of hydrophilic black carbon real(r8) :: bcphidry(pcols) ! dry deposition of hydrophilic black carbon @@ -302,6 +303,7 @@ subroutine atm2hub_alloc( cam_out ) cam_out(c)%co2prog(:) = 0._r8 cam_out(c)%co2diag(:) = 0._r8 cam_out(c)%ozone(:) = 0._r8 + cam_out(c)%lightning_flash_freq(:) = 0._r8 cam_out(c)%psl(:) = 0._r8 cam_out(c)%bcphidry(:) = 0._r8 cam_out(c)%bcphodry(:) = 0._r8 @@ -319,18 +321,14 @@ subroutine atm2hub_alloc( cam_out ) cam_out(c)%dstwet4(:) = 0._r8 nullify(cam_out(c)%nhx_nitrogen_flx) - nullify(cam_out(c)%noy_nitrogen_flx) + allocate (cam_out(c)%nhx_nitrogen_flx(pcols), stat=ierror) + if ( ierror /= 0 ) call endrun(sub//': allocation error nhx_nitrogen_flx') + cam_out(c)%nhx_nitrogen_flx(:) = 0._r8 - if (active_Faxa_nhx) then - allocate (cam_out(c)%nhx_nitrogen_flx(pcols), stat=ierror) - if ( ierror /= 0 ) call endrun(sub//': allocation error nhx_nitrogen_flx') - cam_out(c)%nhx_nitrogen_flx(:) = 0._r8 - endif - if (active_Faxa_noy) then - allocate (cam_out(c)%noy_nitrogen_flx(pcols), stat=ierror) - if ( ierror /= 0 ) call endrun(sub//': allocation error noy_nitrogen_flx') - cam_out(c)%noy_nitrogen_flx(:) = 0._r8 - endif + nullify(cam_out(c)%noy_nitrogen_flx) + allocate (cam_out(c)%noy_nitrogen_flx(pcols), stat=ierror) + if ( ierror /= 0 ) call endrun(sub//': allocation error noy_nitrogen_flx') + cam_out(c)%noy_nitrogen_flx(:) = 0._r8 end do end subroutine atm2hub_alloc @@ -427,7 +425,7 @@ subroutine cam_export(state,cam_out,pbuf) integer :: psl_idx integer :: prec_dp_idx, snow_dp_idx, prec_sh_idx, snow_sh_idx integer :: prec_sed_idx,snow_sed_idx,prec_pcw_idx,snow_pcw_idx - integer :: srf_ozone_idx + integer :: srf_ozone_idx, lightning_idx real(r8), pointer :: psl(:) @@ -440,6 +438,7 @@ subroutine cam_export(state,cam_out,pbuf) real(r8), pointer :: prec_pcw(:) ! total precipitation from Hack convection real(r8), pointer :: snow_pcw(:) ! snow from Hack convection real(r8), pointer :: o3_ptr(:,:), srf_o3_ptr(:) + real(r8), pointer :: lightning_ptr(:) !----------------------------------------------------------------------- lchnk = state%lchnk @@ -457,6 +456,7 @@ subroutine cam_export(state,cam_out,pbuf) prec_pcw_idx = pbuf_get_index('PREC_PCW', errcode=i) snow_pcw_idx = pbuf_get_index('SNOW_PCW', errcode=i) srf_ozone_idx = pbuf_get_index('SRFOZONE', errcode=i) + lightning_idx = pbuf_get_index('LGHT_FLASH_FREQ', errcode=i) if (prec_dp_idx > 0) then call pbuf_get_field(pbuf, prec_dp_idx, prec_dp) @@ -516,6 +516,12 @@ subroutine cam_export(state,cam_out,pbuf) cam_out%ozone(:ncol) = o3_ptr(:ncol,pver) * mwdry/mwo3 ! mole/mole endif + ! get cloud to ground lightning flash freq (/min) to export to surface models + if (lightning_idx>0) then + call pbuf_get_field(pbuf, lightning_idx, lightning_ptr) + cam_out%lightning_flash_freq(:ncol) = lightning_ptr(:ncol) + end if + ! ! Precipation and snow rates from shallow convection, deep convection and stratiform processes. ! Compute total convective and stratiform precipitation and snow rates diff --git a/src/control/runtime_opts.F90 b/src/control/runtime_opts.F90 index 24d096c07c..cc2f4fd4a2 100644 --- a/src/control/runtime_opts.F90 +++ b/src/control/runtime_opts.F90 @@ -97,7 +97,9 @@ subroutine read_namelist(nlfilename, single_column, scmlat, scmlon) use qneg_module, only: qneg_readnl use lunar_tides, only: lunar_tides_readnl use upper_bc, only: ubc_readnl + use cam_budget, only: cam_budget_readnl use phys_grid_ctem, only: phys_grid_ctem_readnl + use mo_lightning, only: lightning_readnl #if (defined HEMCO_CESM) use hemco_interface, only: hemco_readnl @@ -169,6 +171,7 @@ subroutine read_namelist(nlfilename, single_column, scmlat, scmlon) call rad_data_readnl(nlfilename) call modal_aer_opt_readnl(nlfilename) call chem_readnl(nlfilename) + call lightning_readnl(nlfilename) call prescribed_volcaero_readnl(nlfilename) call prescribed_strataero_readnl(nlfilename) call solar_data_readnl(nlfilename) @@ -200,6 +203,7 @@ subroutine read_namelist(nlfilename, single_column, scmlat, scmlon) call dyn_readnl(nlfilename) call ionosphere_readnl(nlfilename) call qneg_readnl(nlfilename) + call cam_budget_readnl(nlfilename) call phys_grid_ctem_readnl(nlfilename) #if (defined HEMCO_CESM) call hemco_readnl(nlfilename) diff --git a/src/cpl/nuopc/atm_comp_nuopc.F90 b/src/cpl/nuopc/atm_comp_nuopc.F90 index a85accd837..8b2ba903d0 100644 --- a/src/cpl/nuopc/atm_comp_nuopc.F90 +++ b/src/cpl/nuopc/atm_comp_nuopc.F90 @@ -4,60 +4,79 @@ module atm_comp_nuopc ! This is the NUOPC cap for CAM !---------------------------------------------------------------------------- - use ESMF - use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize - use NUOPC , only : NUOPC_CompFilterPhaseMap, NUOPC_IsUpdated, NUOPC_IsAtTime - use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise - use NUOPC , only : NUOPC_SetAttribute, NUOPC_CompAttributeGet, NUOPC_CompAttributeSet - use NUOPC_Model , only : model_routine_SS => SetServices - use NUOPC_Model , only : SetVM - use NUOPC_Model , only : model_label_Advance => label_Advance - use NUOPC_Model , only : model_label_DataInitialize => label_DataInitialize - use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock - use NUOPC_Model , only : model_label_Finalize => label_Finalize - use NUOPC_Model , only : NUOPC_ModelGet - use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs - use shr_sys_mod , only : shr_sys_abort - use shr_log_mod , only : shr_log_getlogunit, shr_log_setlogunit - use shr_cal_mod , only : shr_cal_noleap, shr_cal_gregorian, shr_cal_ymd2date - use shr_const_mod , only : shr_const_pi - use shr_orb_mod , only : shr_orb_decl, shr_orb_params, SHR_ORB_UNDEF_REAL, SHR_ORB_UNDEF_INT - use cam_instance , only : cam_instance_init, inst_suffix, inst_index - use cam_comp , only : cam_init, cam_run1, cam_run2, cam_run3, cam_run4, cam_final - use camsrfexch , only : cam_out_t, cam_in_t - use radiation , only : nextsw_cday - use cam_logfile , only : iulog - use spmd_utils , only : spmdinit, masterproc, iam, mpicom - use time_manager , only : get_curr_calday, advance_timestep, get_curr_date, get_nstep, get_step_size - use atm_import_export , only : read_surface_fields_namelists, advertise_fields, realize_fields - use atm_import_export , only : import_fields, export_fields - use nuopc_shr_methods , only : chkerr, state_setscalar, state_getscalar, state_diagnose, alarmInit - use nuopc_shr_methods , only : set_component_logging, get_component_instance, log_clock_advance - use perf_mod , only : t_startf, t_stopf - use ppgrid , only : pcols, begchunk, endchunk - use dyn_grid , only : get_horiz_grid_dim_d - use phys_grid , only : get_ncols_p, get_gcol_p, get_rlon_all_p, get_rlat_all_p - use phys_grid , only : ngcols=>num_global_phys_cols - use cam_control_mod , only : cam_ctrl_set_orbit - use cam_pio_utils , only : cam_pio_createfile, cam_pio_openfile, cam_pio_closefile, pio_subsystem - use cam_initfiles , only : cam_initfiles_get_caseid, cam_initfiles_get_restdir - use cam_history_support , only : fillvalue - use filenames , only : interpret_filename_spec - use pio , only : file_desc_t, io_desc_t, var_desc_t, pio_double, pio_def_dim, PIO_MAX_NAME - use pio , only : pio_closefile, pio_put_att, pio_enddef, pio_nowrite - use pio , only : pio_inq_dimid, pio_inq_varid, pio_inquire_dimension, pio_def_var - use pio , only : pio_initdecomp, pio_freedecomp - use pio , only : pio_read_darray, pio_write_darray - use pio , only : pio_noerr, pio_bcast_error, pio_internal_error, pio_seterrorhandling - use pio , only : pio_def_var, pio_get_var, pio_put_var, PIO_INT - use ioFileMod -!$use omp_lib , only : omp_set_num_threads + use ESMF , only : operator(<=), operator(>), operator(==), operator(+) + use ESMF , only : ESMF_MethodRemove + use ESMF , only : ESMF_GridComp, ESMF_GridCompGet, ESMF_State, ESMF_StateGet + use ESMF , only : ESMF_Grid, ESMF_GridCreateNoPeriDimUfrm, ESMF_Field, ESMF_FieldGet + use ESMF , only : ESMF_DistGrid, ESMF_DistGridCreate + use ESMF , only : ESMF_Mesh, ESMF_MeshCreate, ESMF_MeshGet, ESMF_FILEFORMAT_ESMFMESH + use ESMF , only : ESMF_Clock, ESMF_ClockGet, ESMF_ClockSet, ESMF_ClockGetNextTime, ESMF_ClockAdvance + use ESMF , only : ESMF_Time, ESMF_TimeGet + use ESMF , only : ESMF_Alarm, ESMF_ClockGetAlarm, ESMF_AlarmRingerOff, ESMF_AlarmIsRinging + use ESMF , only : ESMF_ClockGetAlarmList, ESMF_ALARMLIST_ALL, ESMF_AlarmSet + use ESMF , only : ESMF_TimeInterval, ESMF_TimeIntervalGet + use ESMF , only : ESMF_CalKind_Flag, ESMF_MAXSTR, ESMF_KIND_I8 + use ESMF , only : ESMF_CALKIND_NOLEAP, ESMF_CALKIND_GREGORIAN + use ESMF , only : ESMF_GridCompSetEntryPoint + use ESMF , only : ESMF_VM, ESMF_VMGetCurrent, ESMF_VMGet + use ESMF , only : ESMF_LOGMSG_INFO, ESMF_LOGERR_PASSTHRU + use ESMF , only : ESMF_LogWrite, ESMF_LogSetError, ESMF_LogFoundError + use ESMF , only : ESMF_SUCCESS, ESMF_METHOD_INITIALIZE, ESMF_FAILURE, ESMF_RC_NOT_VALID + use ESMF , only : ESMF_STAGGERLOC_CENTER, ESMF_STAGGERLOC_CORNER + use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize + use NUOPC , only : NUOPC_CompFilterPhaseMap, NUOPC_IsUpdated, NUOPC_IsAtTime + use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise + use NUOPC , only : NUOPC_SetAttribute, NUOPC_CompAttributeGet, NUOPC_CompAttributeSet + use NUOPC_Model , only : model_routine_SS => SetServices + use NUOPC_Model , only : SetVM + use NUOPC_Model , only : model_label_Advance => label_Advance + use NUOPC_Model , only : model_label_DataInitialize => label_DataInitialize + use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock + use NUOPC_Model , only : model_label_Finalize => label_Finalize + use NUOPC_Model , only : NUOPC_ModelGet + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_log_mod , only : shr_log_getlogunit, shr_log_setlogunit + use shr_cal_mod , only : shr_cal_noleap, shr_cal_gregorian, shr_cal_ymd2date + use shr_const_mod , only : shr_const_pi + use shr_orb_mod , only : shr_orb_decl, shr_orb_params, SHR_ORB_UNDEF_REAL, SHR_ORB_UNDEF_INT + use cam_instance , only : cam_instance_init, inst_suffix, inst_index + use cam_comp , only : cam_init, cam_run1, cam_run2, cam_run3, cam_run4, cam_final + use camsrfexch , only : cam_out_t, cam_in_t + use radiation , only : nextsw_cday + use cam_logfile , only : iulog + use spmd_utils , only : spmdinit, masterproc, iam, mpicom + use time_manager , only : get_curr_calday, advance_timestep, get_curr_date, get_nstep, get_step_size + use atm_import_export , only : read_surface_fields_namelists, advertise_fields, realize_fields + use atm_import_export , only : import_fields, export_fields + use nuopc_shr_methods , only : chkerr, state_setscalar, state_getscalar, state_diagnose, alarmInit + use nuopc_shr_methods , only : set_component_logging, get_component_instance, log_clock_advance + use perf_mod , only : t_startf, t_stopf + use ppgrid , only : pcols, begchunk, endchunk + use dyn_grid , only : get_horiz_grid_dim_d + use phys_grid , only : get_ncols_p, get_gcol_p, get_rlon_all_p, get_rlat_all_p + use phys_grid , only : ngcols=>num_global_phys_cols + use cam_control_mod , only : cam_ctrl_set_orbit + use cam_pio_utils , only : cam_pio_createfile, cam_pio_openfile, cam_pio_closefile, pio_subsystem + use cam_initfiles , only : cam_initfiles_get_caseid, cam_initfiles_get_restdir + use cam_history_support , only : fillvalue + use filenames , only : interpret_filename_spec + use pio , only : file_desc_t, io_desc_t, var_desc_t, pio_double, pio_def_dim, PIO_MAX_NAME + use pio , only : pio_closefile, pio_put_att, pio_enddef, pio_nowrite + use pio , only : pio_inq_dimid, pio_inq_varid, pio_inquire_dimension, pio_def_var + use pio , only : pio_initdecomp, pio_freedecomp + use pio , only : pio_read_darray, pio_write_darray + use pio , only : pio_noerr, pio_bcast_error, pio_internal_error, pio_seterrorhandling + use pio , only : pio_def_var, pio_get_var, pio_put_var, PIO_INT + use ioFileMod + !$use omp_lib , only : omp_set_num_threads implicit none private ! except public :: SetServices public :: SetVM + !-------------------------------------------------------------------------- ! Private interfaces !-------------------------------------------------------------------------- @@ -109,6 +128,10 @@ module atm_comp_nuopc character(len=*) , parameter :: orb_fixed_parameters = 'fixed_parameters' real(R8) , parameter :: grid_tol = 1.e-2_r8 ! tolerance for calculated lat/lon vs read in + + type(ESMF_Mesh) :: model_mesh ! model_mesh + type(ESMF_Clock) :: model_clock ! model_clock + !=============================================================================== contains !=============================================================================== @@ -319,7 +342,6 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) type(ESMF_TimeInterval) :: timeStep type(ESMF_CalKind_Flag) :: esmf_caltype ! esmf calendar type type(ESMF_DistGrid) :: distGrid - type(ESMF_Mesh) :: mesh integer :: spatialDim integer :: numOwnedElements real(R8), pointer :: ownedElemCoords(:) @@ -626,7 +648,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) if (single_column) then - call cam_set_mesh_for_single_column(scol_lon, scol_lat, mesh, rc) + call cam_set_mesh_for_single_column(scol_lon, scol_lat, model_mesh, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return allocate(dof(1)) dof(1) = 1 @@ -657,7 +679,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) call NUOPC_CompAttributeGet(gcomp, name='mesh_atm', value=cvalue, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - mesh = ESMF_MeshCreate(filename=trim(cvalue), fileformat=ESMF_FILEFORMAT_ESMFMESH, & + model_mesh = ESMF_MeshCreate(filename=trim(cvalue), fileformat=ESMF_FILEFORMAT_ESMFMESH, & elementDistgrid=Distgrid, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (masterproc) then @@ -665,7 +687,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) end if ! obtain mesh lats and lons - call ESMF_MeshGet(mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) + call ESMF_MeshGet(model_mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (numOwnedElements /= lsize) then write(tempc1,'(i10)') numOwnedElements @@ -677,7 +699,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) end if allocate(ownedElemCoords(spatialDim*numOwnedElements)) allocate(lonMesh(lsize), latMesh(lsize)) - call ESMF_MeshGet(mesh, ownedElemCoords=ownedElemCoords) + call ESMF_MeshGet(model_mesh, ownedElemCoords=ownedElemCoords) if (ChkErr(rc,__LINE__,u_FILE_u)) return do n = 1,lsize lonMesh(n) = ownedElemCoords(2*n-1) @@ -702,7 +724,8 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! error check differences between internally generated lons and those read in do n = 1,lsize - if (abs(lonMesh(n) - lon(n)) > grid_tol .and. abs(lonMesh(n) - lon(n)) /= 360._r8) then + if (abs(lonMesh(n) - lon(n)) > grid_tol .and. .not. & + abs(abs(lonMesh(n) - lon(n))- 360._r8) < grid_tol) then write(6,100)n,lon(n),lonMesh(n), abs(lonMesh(n)-lon(n)) 100 format('ERROR: CAM n, lonmesh(n), lon(n), diff_lon = ',i6,2(f21.13,3x),d21.5) call shr_sys_abort() @@ -722,11 +745,14 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) end if ! end of if single_column ! realize the actively coupled fields - call realize_fields(gcomp, mesh, flds_scalar_name, flds_scalar_num, single_column, rc) + call realize_fields(gcomp, model_mesh, flds_scalar_name, flds_scalar_num, single_column, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! Create model_clock as a module variable - needed for generating streams + model_clock = clock + ! Create cam export array and set the state scalars - call export_fields( gcomp, cam_out, rc=rc ) + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc=rc ) if (ChkErr(rc,__LINE__,u_FILE_u)) return call get_horiz_grid_dim_d(hdim1_d, hdim2_d) @@ -881,7 +907,7 @@ subroutine DataInitialize(gcomp, rc) call import_fields( gcomp, cam_in, rc=rc ) if (ChkErr(rc,__LINE__,u_FILE_u)) return call cam_run1 ( cam_in, cam_out ) - call export_fields( gcomp, cam_out, rc=rc ) + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc=rc ) if (ChkErr(rc,__LINE__,u_FILE_u)) return else call cam_read_srfrest( gcomp, clock, rc=rc ) @@ -889,7 +915,7 @@ subroutine DataInitialize(gcomp, rc) call import_fields( gcomp, cam_in, restart_init=.true., rc=rc ) if (ChkErr(rc,__LINE__,u_FILE_u)) return call cam_run1 ( cam_in, cam_out ) - call export_fields( gcomp, cam_out, rc=rc ) + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc=rc ) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if @@ -1136,7 +1162,7 @@ subroutine ModelAdvance(gcomp, rc) if (mediator_present) then ! Set export fields call t_startf ('CAM_export') - call export_fields( gcomp, cam_out, rc ) + call export_fields( gcomp, model_mesh, model_clock, cam_out, rc ) if (ChkErr(rc,__LINE__,u_FILE_u)) return call t_stopf ('CAM_export') @@ -1503,7 +1529,7 @@ subroutine cam_orbital_update(clock, logunit, mastertask, eccen, obliqr, lambm0 if(.not. (logprint .and. mastertask)) then logprint = .false. endif - + eccen = orb_eccen call shr_orb_params(orb_year, eccen, orb_obliq, orb_mvelp, obliqr, lambm0, mvelpp, logprint) diff --git a/src/cpl/nuopc/atm_import_export.F90 b/src/cpl/nuopc/atm_import_export.F90 index bdce379f69..baadd00865 100644 --- a/src/cpl/nuopc/atm_import_export.F90 +++ b/src/cpl/nuopc/atm_import_export.F90 @@ -3,6 +3,7 @@ module atm_import_export use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise, NUOPC_IsConnected use NUOPC_Model , only : NUOPC_ModelGet use ESMF , only : ESMF_GridComp, ESMF_State, ESMF_Mesh, ESMF_StateGet, ESMF_Field + use ESMF , only : ESMF_Clock use ESMF , only : ESMF_KIND_R8, ESMF_SUCCESS, ESMF_MAXSTR, ESMF_LOGMSG_INFO use ESMF , only : ESMF_LogWrite, ESMF_LOGMSG_ERROR, ESMF_LogFoundError use ESMF , only : ESMF_STATEITEM_NOTFOUND, ESMF_StateItem_Flag @@ -23,6 +24,8 @@ module atm_import_export use srf_field_check , only : set_active_Faoo_fco2_ocn use srf_field_check , only : set_active_Faxa_nhx use srf_field_check , only : set_active_Faxa_noy + use srf_field_check , only : active_Faxa_nhx, active_Faxa_noy + use atm_stream_ndep , only : stream_ndep_init, stream_ndep_interp, stream_ndep_is_initialized implicit none private ! except @@ -57,7 +60,8 @@ module atm_import_export integer :: drydep_nflds = -huge(1) ! number of dry deposition velocity fields lnd-> atm integer :: megan_nflds = -huge(1) ! number of MEGAN voc fields from lnd-> atm integer :: emis_nflds = -huge(1) ! number of fire emission fields from lnd-> atm - integer, public :: ndep_nflds = -huge(1) ! number of nitrogen deposition fields from atm->lnd/ocn + integer, public :: ndep_nflds = -huge(1) ! number of nitrogen deposition fields from atm->lnd/ocn + logical :: atm_provides_lightning = .false. ! cld to grnd lightning flash freq (min-1) character(*),parameter :: F01 = "('(cam_import_export) ',a,i8,2x,i8,2x,d21.14)" character(*),parameter :: F02 = "('(cam_import_export) ',a,i8,2x,i8,2x,i8,2x,d21.14)" character(*),parameter :: u_FILE_u = __FILE__ @@ -76,6 +80,7 @@ subroutine read_surface_fields_namelists() use shr_fire_emis_mod , only : shr_fire_emis_readnl use shr_carma_mod , only : shr_carma_readnl use shr_ndep_mod , only : shr_ndep_readnl + use shr_lightning_coupling_mod, only : shr_lightning_coupling_readnl character(len=*), parameter :: nl_file_name = 'drv_flds_in' @@ -85,9 +90,13 @@ subroutine read_surface_fields_namelists() call shr_megan_readnl(nl_file_name, megan_nflds) call shr_fire_emis_readnl(nl_file_name, emis_nflds) call shr_carma_readnl(nl_file_name, carma_fields) + call shr_lightning_coupling_readnl(nl_file_name, atm_provides_lightning) end subroutine read_surface_fields_namelists + !----------------------------------------------------------- + ! advertise fields + !----------------------------------------------------------- subroutine advertise_fields(gcomp, flds_scalar_name, rc) ! input/output variables @@ -100,7 +109,6 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) type(ESMF_State) :: exportState character(ESMF_MAXSTR) :: stdname character(ESMF_MAXSTR) :: cvalue - character(len=2) :: nec_str integer :: n, num logical :: flds_co2a ! use case logical :: flds_co2b ! use case @@ -186,11 +194,21 @@ subroutine advertise_fields(gcomp, flds_scalar_name, rc) call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_co2diag' ) end if - ! from atm - nitrogen deposition if (ndep_nflds > 0) then - call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=ndep_nflds) + ! The following is when CAM/WACCM computes ndep call set_active_Faxa_nhx(.true.) call set_active_Faxa_noy(.true.) + else + ! The following is used for reading in stream data + call set_active_Faxa_nhx(.false.) + call set_active_Faxa_noy(.false.) + end if + ! Assume that 2 fields are always sent as part of Faxa_ndep + call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Faxa_ndep', ungridded_lbound=1, ungridded_ubound=2) + + ! lightning flash freq + if (atm_provides_lightning) then + call fldlist_add(fldsFrAtm_num, fldsFrAtm, 'Sa_lightning') end if ! Now advertise above export fields @@ -859,7 +877,7 @@ end subroutine import_fields !=============================================================================== - subroutine export_fields( gcomp, cam_out, rc) + subroutine export_fields( gcomp, model_mesh, model_clock, cam_out, rc) ! ----------------------------------------------------- ! Set field pointers in export set @@ -877,16 +895,20 @@ subroutine export_fields( gcomp, cam_out, rc) !------------------------------- ! input/output variables - type(ESMF_GridComp) :: gcomp - type(cam_out_t) , intent(in) :: cam_out(begchunk:endchunk) - integer , intent(out) :: rc + type(ESMF_GridComp) :: gcomp + type(ESMF_Mesh) , intent(in) :: model_mesh + type(ESMF_Clock), intent(in) :: model_clock + type(cam_out_t) , intent(inout) :: cam_out(begchunk:endchunk) + integer , intent(out) :: rc ! local variables type(ESMF_State) :: exportState + type(ESMF_Clock) :: clock integer :: i,m,c,n,g ! indices integer :: ncols ! Number of columns integer :: nstep logical :: exists + real(r8) :: scale_ndep ! 2d pointers real(r8), pointer :: fldptr_ndep(:,:) real(r8), pointer :: fldptr_bcph(:,:) , fldptr_ocph(:,:) @@ -904,6 +926,7 @@ subroutine export_fields( gcomp, cam_out, rc) real(r8), pointer :: fldptr_ptem(:) , fldptr_pslv(:) real(r8), pointer :: fldptr_co2prog(:) , fldptr_co2diag(:) real(r8), pointer :: fldptr_ozone(:) + real(r8), pointer :: fldptr_lght(:) character(len=*), parameter :: subname='(atm_import_export:export_fields)' !--------------------------------------------------------------------------- @@ -1033,44 +1056,70 @@ subroutine export_fields( gcomp, cam_out, rc) end do end if - call state_getfldptr(exportState, 'Sa_co2prog', fldptr=fldptr_co2prog, exists=exists, rc=rc) + call state_getfldptr(exportState, 'Sa_lightning', fldptr=fldptr_lght, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then g = 1 do c = begchunk,endchunk do i = 1,get_ncols_p(c) - fldptr_co2prog(g) = cam_out(c)%co2prog(i) ! atm prognostic co2 + fldptr_lght(g) = cam_out(c)%lightning_flash_freq(i) ! cloud-to-ground lightning flash frequency (/min) g = g + 1 end do end do end if - call state_getfldptr(exportState, 'Sa_co2diag', fldptr=fldptr_co2diag, exists=exists, rc=rc) + call state_getfldptr(exportState, 'Sa_co2prog', fldptr=fldptr_co2prog, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then g = 1 do c = begchunk,endchunk do i = 1,get_ncols_p(c) - fldptr_co2diag(g) = cam_out(c)%co2diag(i) ! atm diagnostic co2 + fldptr_co2prog(g) = cam_out(c)%co2prog(i) ! atm prognostic co2 g = g + 1 end do end do end if - call state_getfldptr(exportState, 'Faxa_ndep', fldptr2d=fldptr_ndep, exists=exists, rc=rc) + call state_getfldptr(exportState, 'Sa_co2diag', fldptr=fldptr_co2diag, exists=exists, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (exists) then - ! (1) => nhx, (2) => noy g = 1 do c = begchunk,endchunk do i = 1,get_ncols_p(c) - fldptr_ndep(1,g) = cam_out(c)%nhx_nitrogen_flx(i) * mod2med_areacor(g) - fldptr_ndep(2,g) = cam_out(c)%noy_nitrogen_flx(i) * mod2med_areacor(g) + fldptr_co2diag(g) = cam_out(c)%co2diag(i) ! atm diagnostic co2 g = g + 1 end do end do end if + ! If ndep fields are not computed in cam and must be obtained from the ndep input stream + call state_getfldptr(exportState, 'Faxa_ndep', fldptr2d=fldptr_ndep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (.not. active_Faxa_nhx .and. .not. active_Faxa_noy) then + if (.not. stream_ndep_is_initialized) then + call stream_ndep_init(model_mesh, model_clock, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + stream_ndep_is_initialized = .true. + end if + call stream_ndep_interp(cam_out, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! NDEP read from forcing is expected to be in units of gN/m2/sec - but the mediator + ! expects units of kgN/m2/sec + scale_ndep = .001_r8 + else + ! If waccm computes ndep, then its in units of kgN/m2/s - and the mediator expects + ! units of kgN/m2/sec, so the following conversion needs to happen + scale_ndep = 1._r8 + end if + g = 1 + do c = begchunk,endchunk + do i = 1,get_ncols_p(c) + fldptr_ndep(1,g) = cam_out(c)%nhx_nitrogen_flx(i) * scale_ndep * mod2med_areacor(g) + fldptr_ndep(2,g) = cam_out(c)%noy_nitrogen_flx(i) * scale_ndep * mod2med_areacor(g) + g = g + 1 + end do + end do + end subroutine export_fields !=============================================================================== diff --git a/src/cpl/nuopc/atm_stream_ndep.F90 b/src/cpl/nuopc/atm_stream_ndep.F90 new file mode 100644 index 0000000000..394808a529 --- /dev/null +++ b/src/cpl/nuopc/atm_stream_ndep.F90 @@ -0,0 +1,256 @@ +module atm_stream_ndep + + !----------------------------------------------------------------------- + ! Contains methods for reading in nitrogen deposition data file + ! Also includes functions for dynamic ndep file handling and + ! interpolation. + !----------------------------------------------------------------------- + ! + use ESMF , only : ESMF_Clock, ESMF_Mesh + use ESMF , only : ESMF_SUCCESS, ESMF_LOGERR_PASSTHRU, ESMF_END_ABORT + use ESMF , only : ESMF_Finalize, ESMF_LogFoundError + use nuopc_shr_methods , only : chkerr + use dshr_strdata_mod , only : shr_strdata_type + use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_cl, CS => shr_kind_cs + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmd_utils , only : mpicom, masterproc, iam + use spmd_utils , only : mpi_character, mpi_integer + use cam_logfile , only : iulog + use cam_abortutils , only : endrun + + implicit none + private + + public :: stream_ndep_init ! position datasets for dynamic ndep + public :: stream_ndep_interp ! interpolates between two years of ndep file data + + private :: stream_ndep_check_units ! Check the units and make sure they can be used + + type(shr_strdata_type) :: sdat_ndep ! input data stream + logical, public :: stream_ndep_is_initialized = .false. + character(len=CS) :: stream_varlist_ndep(2) + type(ESMF_Clock) :: model_clock + + character(len=*), parameter :: sourcefile = & + __FILE__ + +!============================================================================== +contains +!============================================================================== + + subroutine stream_ndep_init(model_mesh, model_clock, rc) + ! + ! Initialize data stream information. + + ! Uses: + use cam_instance , only: inst_suffix + use shr_nl_mod , only: shr_nl_find_group_name + use dshr_strdata_mod , only: shr_strdata_init_from_inline + + ! input/output variables + type(ESMF_CLock), intent(in) :: model_clock + type(ESMF_Mesh) , intent(in) :: model_mesh + integer , intent(out) :: rc + + ! local variables + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + character(len=CL) :: stream_ndep_data_filename + character(len=CL) :: stream_ndep_mesh_filename + character(len=CL) :: filein ! atm namelist file + integer :: stream_ndep_year_first ! first year in stream to use + integer :: stream_ndep_year_last ! last year in stream to use + integer :: stream_ndep_year_align ! align stream_year_firstndep with + integer :: ierr + character(*), parameter :: subName = "('stream_ndep_init')" + !----------------------------------------------------------------------- + + namelist /ndep_stream_nl/ & + stream_ndep_data_filename, & + stream_ndep_mesh_filename, & + stream_ndep_year_first, & + stream_ndep_year_last, & + stream_ndep_year_align + + rc = ESMF_SUCCESS + + ! Default values for namelist + stream_ndep_data_filename = ' ' + stream_ndep_mesh_filename = ' ' + stream_ndep_year_first = 1 ! first year in stream to use + stream_ndep_year_last = 1 ! last year in stream to use + stream_ndep_year_align = 1 ! align stream_ndep_year_first with this model year + + ! For now variable list in stream data file is hard-wired + stream_varlist_ndep = (/'NDEP_NHx_month', 'NDEP_NOy_month'/) + + ! Read ndep_stream namelist + if (masterproc) then + filein = "atm_in" // trim(inst_suffix) + open( newunit=nu_nml, file=trim(filein), status='old', iostat=nml_error ) + if (nml_error /= 0) then + call endrun(subName//': ERROR opening '//trim(filein)//errMsg(sourcefile, __LINE__)) + end if + call shr_nl_find_group_name(nu_nml, 'ndep_stream_nl', status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=ndep_stream_nl, iostat=nml_error) + if (nml_error /= 0) then + call endrun(' ERROR reading ndep_stream_nl namelist'//errMsg(sourcefile, __LINE__)) + end if + else + call endrun(' ERROR finding ndep_stream_nl namelist'//errMsg(sourcefile, __LINE__)) + end if + close(nu_nml) + endif + call mpi_bcast(stream_ndep_mesh_filename, len(stream_ndep_mesh_filename), mpi_character, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_mesh_filename") + call mpi_bcast(stream_ndep_data_filename, len(stream_ndep_data_filename), mpi_character, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_data_filename") + call mpi_bcast(stream_ndep_year_first, 1, mpi_integer, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_year_first") + call mpi_bcast(stream_ndep_year_last, 1, mpi_integer, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_year_last") + call mpi_bcast(stream_ndep_year_align, 1, mpi_integer, 0, mpicom, ierr) + if (ierr /= 0) call endrun(trim(subname)//": FATAL: mpi_bcast: stream_ndep_year_align") + + if (masterproc) then + write(iulog,'(a)' ) ' ' + write(iulog,'(a,i8)') 'stream ndep settings:' + write(iulog,'(a,a)' ) ' stream_ndep_data_filename = ',trim(stream_ndep_data_filename) + write(iulog,'(a,a)' ) ' stream_ndep_mesh_filename = ',trim(stream_ndep_mesh_filename) + write(iulog,'(a,a,a)') ' stream_varlist_ndep = ',trim(stream_varlist_ndep(1)), trim(stream_varlist_ndep(2)) + write(iulog,'(a,i8)') ' stream_ndep_year_first = ',stream_ndep_year_first + write(iulog,'(a,i8)') ' stream_ndep_year_last = ',stream_ndep_year_last + write(iulog,'(a,i8)') ' stream_ndep_year_align = ',stream_ndep_year_align + write(iulog,'(a)' ) ' ' + endif + + ! Read in units + call stream_ndep_check_units(stream_ndep_data_filename) + + ! Initialize the cdeps data type sdat_ndep + call shr_strdata_init_from_inline(sdat_ndep, & + my_task = iam, & + logunit = iulog, & + compname = 'ATM', & + model_clock = model_clock, & + model_mesh = model_mesh, & + stream_meshfile = trim(stream_ndep_mesh_filename), & + stream_filenames = (/trim(stream_ndep_data_filename)/), & + stream_yearFirst = stream_ndep_year_first, & + stream_yearLast = stream_ndep_year_last, & + stream_yearAlign = stream_ndep_year_align, & + stream_fldlistFile = stream_varlist_ndep, & + stream_fldListModel = stream_varlist_ndep, & + stream_lev_dimname = 'null', & + stream_mapalgo = 'bilinear', & + stream_offset = 0, & + stream_taxmode = 'cycle', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = 'linear', & + stream_name = 'Nitrogen deposition data ', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + end subroutine stream_ndep_init + + !================================================================ + subroutine stream_ndep_check_units( stream_fldFileName_ndep) + + !-------------------------------------------------------- + ! Check that units are correct on the file and if need any conversion + !-------------------------------------------------------- + + use cam_pio_utils , only : cam_pio_createfile, cam_pio_openfile, cam_pio_closefile, pio_subsystem + use pio , only : file_desc_t, io_desc_t, var_desc_t, pio_double, pio_def_dim + use pio , only : pio_bcast_error, pio_seterrorhandling, pio_inq_varid, pio_get_att + use pio , only : PIO_NOERR, PIO_NOWRITE + + ! Arguments + character(len=*), intent(in) :: stream_fldFileName_ndep ! ndep filename + ! + ! Local variables + type(file_desc_t) :: File ! NetCDF filehandle for ndep file + type(var_desc_t) :: vardesc ! variable descriptor + integer :: ierr ! error status + integer :: err_handling ! temporary + character(len=CS) :: ndepunits! ndep units + !----------------------------------------------------------------------- + + call cam_pio_openfile( File, trim(stream_fldFileName_ndep), PIO_NOWRITE) + call pio_seterrorhandling(File, PIO_BCAST_ERROR, err_handling) + ierr = pio_inq_varid(File, stream_varlist_ndep(1), vardesc) + if (ierr /= PIO_NOERR) then + call endrun(' ERROR finding variable: '//trim(stream_varlist_ndep(1))//" in file: "// & + trim(stream_fldFileName_ndep)//errMsg(sourcefile, __LINE__)) + else + ierr = PIO_get_att(File, vardesc, "units", ndepunits) + end if + call pio_seterrorhandling(File, err_handling) + call cam_pio_closefile(File) + + ! Now check to make sure they are correct + if (.not. trim(ndepunits) == "g(N)/m2/s" )then + call endrun(' ERROR in units for nitrogen deposition equal to: '//trim(ndepunits)//" not units expected"// & + errMsg(sourcefile, __LINE__)) + end if + + end subroutine stream_ndep_check_units + + !================================================================ + subroutine stream_ndep_interp(cam_out, rc) + + use dshr_methods_mod , only : dshr_fldbun_getfldptr + use dshr_strdata_mod , only : shr_strdata_advance + use camsrfexch , only : cam_out_t + use ppgrid , only : begchunk, endchunk + use time_manager , only : get_curr_date + use phys_grid , only : get_ncols_p + + ! input/output variables + type(cam_out_t) , intent(inout) :: cam_out(begchunk:endchunk) + integer , intent(out) :: rc + + ! local variables + integer :: i,c,g + integer :: year ! year (0, ...) for nstep+1 + integer :: mon ! month (1, ..., 12) for nstep+1 + integer :: day ! day of month (1, ..., 31) for nstep+1 + integer :: sec ! seconds into current date for nstep+1 + integer :: mcdate ! Current model date (yyyymmdd) + real(r8), pointer :: dataptr1d_nhx(:) + real(r8), pointer :: dataptr1d_noy(:) + !----------------------------------------------------------------------- + + ! Advance sdat stream + call get_curr_date(year, mon, day, sec) + mcdate = year*10000 + mon*100 + day + call shr_strdata_advance(sdat_ndep, ymd=mcdate, tod=sec, logunit=iulog, istr='ndepdyn', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Get pointer for stream data that is time and spatially interpolated to model time and grid + call dshr_fldbun_getFldPtr(sdat_ndep%pstrm(1)%fldbun_model, stream_varlist_ndep(1), fldptr1=dataptr1d_nhx, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + call dshr_fldbun_getFldPtr(sdat_ndep%pstrm(1)%fldbun_model, stream_varlist_ndep(2), fldptr1=dataptr1d_noy, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + g = 1 + do c = begchunk,endchunk + do i = 1,get_ncols_p(c) + cam_out(c)%nhx_nitrogen_flx(i) = dataptr1d_nhx(g) + cam_out(c)%noy_nitrogen_flx(i) = dataptr1d_noy(g) + g = g + 1 + end do + end do + + end subroutine stream_ndep_interp + +end module atm_stream_ndep diff --git a/src/dynamics/eul/dp_coupling.F90 b/src/dynamics/eul/dp_coupling.F90 index 946c66b092..bc900e2d0e 100644 --- a/src/dynamics/eul/dp_coupling.F90 +++ b/src/dynamics/eul/dp_coupling.F90 @@ -269,7 +269,7 @@ subroutine d_p_coupling(ps, t3, u3, v3, q3, & ! Compute initial geopotential heights call geopotential_t (phys_state(lchnk)%lnpint, phys_state(lchnk)%lnpmid , phys_state(lchnk)%pint , & phys_state(lchnk)%pmid , phys_state(lchnk)%pdel , phys_state(lchnk)%rpdel , & - phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,1), rairv(:,:,lchnk), gravit, zvirv, & + phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,:), rairv(:,:,lchnk), gravit, zvirv, & phys_state(lchnk)%zi , phys_state(lchnk)%zm , ncol ) ! Compute initial dry static energy, include surface geopotential diff --git a/src/dynamics/eul/dycore_budget.F90 b/src/dynamics/eul/dycore_budget.F90 new file mode 100644 index 0000000000..7531d69ac7 --- /dev/null +++ b/src/dynamics/eul/dycore_budget.F90 @@ -0,0 +1,27 @@ +module dycore_budget +implicit none + +public :: print_budget + +!========================================================================================= +contains +!========================================================================================= + +subroutine print_budget(hstwr) + + use spmd_utils, only: masterproc + use cam_abortutils, only: endrun + use cam_budget, only: thermo_budget_history,thermo_budget_histfile_num + + ! arguments + logical, intent(in) :: hstwr(:) + character(len=*), parameter :: subname = 'dycore_budget:print_budgets:' + + !-------------------------------------------------------------------------------------- + + if (masterproc .and. thermo_budget_history .and. hstwr(thermo_budget_histfile_num)) then + call endrun(subname//' is not implemented for the EUL dycore') + end if +end subroutine print_budget + +end module dycore_budget diff --git a/src/dynamics/fv/dp_coupling.F90 b/src/dynamics/fv/dp_coupling.F90 index 4f109bf2ee..0b2aa31d55 100644 --- a/src/dynamics/fv/dp_coupling.F90 +++ b/src/dynamics/fv/dp_coupling.F90 @@ -77,7 +77,7 @@ subroutine d_p_coupling(grid, phys_state, phys_tend, pbuf2d, dyn_out) use ctem, only: ctem_diags, do_circulation_diags use diag_module, only: fv_diag_am_calc use gravity_waves_sources, only: gws_src_fnct - use cam_thermo, only: cam_thermo_update + use cam_thermo, only: cam_thermo_dry_air_update use shr_const_mod, only: shr_const_rwv use dyn_comp, only: frontgf_idx, frontga_idx, uzm_idx use qbo, only: qbo_use_forcing @@ -85,7 +85,7 @@ subroutine d_p_coupling(grid, phys_state, phys_tend, pbuf2d, dyn_out) use zonal_mean, only: zonal_mean_3D use d2a3dikj_mod, only: d2a3dikj use qneg_module, only: qneg3 - + use air_composition,only: dry_air_species_num !----------------------------------------------------------------------- implicit none !----------------------------------------------------------------------- @@ -572,7 +572,7 @@ subroutine d_p_coupling(grid, phys_state, phys_tend, pbuf2d, dyn_out) end do end do - if ( waccmx_is('ionosphere') .or. waccmx_is('neutral') ) then + if (dry_air_species_num>0) then !------------------------------------------------------------ ! Apply limiters to mixing ratios of major species !------------------------------------------------------------ @@ -581,7 +581,7 @@ subroutine d_p_coupling(grid, phys_state, phys_tend, pbuf2d, dyn_out) ! Call cam_thermo_update to compute cpairv, rairv, mbarv, and cappav as constituent dependent variables ! and compute molecular viscosity(kmvis) and conductivity(kmcnd) !----------------------------------------------------------------------------- - call cam_thermo_update(phys_state(lchnk)%q, phys_state(lchnk)%t, lchnk, ncol) + call cam_thermo_dry_air_update(phys_state(lchnk)%q, phys_state(lchnk)%t, lchnk, ncol) endif !------------------------------------------------------------------------ @@ -596,7 +596,7 @@ subroutine d_p_coupling(grid, phys_state, phys_tend, pbuf2d, dyn_out) ! Compute initial geopotential heights call geopotential_t (phys_state(lchnk)%lnpint, phys_state(lchnk)%lnpmid , phys_state(lchnk)%pint , & phys_state(lchnk)%pmid , phys_state(lchnk)%pdel , phys_state(lchnk)%rpdel , & - phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,1), rairv(:,:,lchnk), gravit, zvirv, & + phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,:), rairv(:,:,lchnk), gravit, zvirv, & phys_state(lchnk)%zi , phys_state(lchnk)%zm , ncol ) ! Compute initial dry static energy, include surface geopotential diff --git a/src/dynamics/fv/dycore_budget.F90 b/src/dynamics/fv/dycore_budget.F90 new file mode 100644 index 0000000000..a672fef9cc --- /dev/null +++ b/src/dynamics/fv/dycore_budget.F90 @@ -0,0 +1,27 @@ +module dycore_budget +implicit none + +public :: print_budget + +!========================================================================================= +contains +!========================================================================================= + +subroutine print_budget(hstwr) + + use spmd_utils, only: masterproc + use cam_abortutils, only: endrun + use cam_budget, only: thermo_budget_histfile_num, thermo_budget_history + + ! arguments + logical, intent(in) :: hstwr(:) + character(len=*), parameter :: subname = 'dycore_budget:print_budgets:' + + !-------------------------------------------------------------------------------------- + + if (masterproc .and. thermo_budget_history .and. hstwr(thermo_budget_histfile_num)) then + call endrun(subname//' is not implemented for the FV dycore') + end if +end subroutine print_budget + +end module dycore_budget diff --git a/src/dynamics/fv/metdata.F90 b/src/dynamics/fv/metdata.F90 index 5f49143562..06957af5ef 100644 --- a/src/dynamics/fv/metdata.F90 +++ b/src/dynamics/fv/metdata.F90 @@ -660,7 +660,9 @@ subroutine get_met_srf2( cam_in ) ! Nudging land and forcing ocean. if (met_srf_land_scale) then - met_rlx_sfc(:ncol) = (1._r8 - cam_in(c)%landfrac(:ncol)) * met_rlx_sfc(:ncol) + cam_in(c)%landfrac(:ncol) * met_rlx(pver) + met_rlx_sfc(:ncol) = (1._r8 - cam_in(c)%landfrac(:ncol)) * & + met_rlx_sfc(:ncol) + & + cam_in(c)%landfrac(:ncol) * met_rlx(pver) else where(cam_in(c)%landfrac(:ncol) == 1._r8) met_rlx_sfc(:ncol) = 0._r8 end if @@ -725,9 +727,9 @@ subroutine get_met_srf2( cam_in ) end if if (met_srf_refs) then - cam_in(c)%qref(:ncol) = (1._r8-met_rlx_sfc(:ncol)) * cam_in(c)%qref(:ncol) + met_rlx_sfc(:ncol) * met_qref(:ncol,c) - cam_in(c)%tref(:ncol) = (1._r8-met_rlx_sfc(:ncol)) * cam_in(c)%tref(:ncol) + met_rlx_sfc(:ncol) * met_tref(:ncol,c) - cam_in(c)%u10(:ncol) = (1._r8-met_rlx_sfc(:ncol)) * cam_in(c)%u10(:ncol) + met_rlx_sfc(:ncol) * met_u10(:ncol,c) + cam_in(c)%qref(:ncol) = (1._r8-met_rlx_sfc(:ncol)) * cam_in(c)%qref(:ncol) + met_rlx_sfc(:ncol) * met_qref(:ncol,c) + cam_in(c)%tref(:ncol) = (1._r8-met_rlx_sfc(:ncol)) * cam_in(c)%tref(:ncol) + met_rlx_sfc(:ncol) * met_tref(:ncol,c) + cam_in(c)%u10(:ncol) = (1._r8-met_rlx_sfc(:ncol)) * cam_in(c)%u10(:ncol) + met_rlx_sfc(:ncol) * met_u10(:ncol,c) end if if (met_srf_sst) then @@ -902,6 +904,8 @@ subroutine get_dyn_flds( state, tend, dt ) use ppgrid, only: pcols, pver, begchunk, endchunk use phys_grid, only: get_ncols_p use cam_history, only: outfld + use air_composition,only: thermodynamic_active_species_liq_num, thermodynamic_active_species_ice_num + use air_composition,only: thermodynamic_active_species_liq_idx,thermodynamic_active_species_ice_idx implicit none @@ -912,7 +916,10 @@ subroutine get_dyn_flds( state, tend, dt ) integer :: lats(pcols) ! array of latitude indices integer :: lons(pcols) ! array of longitude indices integer :: c, ncol, i,j,k - real(r8):: qini(pcols,pver) ! initial specific humidity + integer :: m_cnst,m + real(r8):: qini(pcols,pver) ! initial specific humidity + real(r8):: totliqini(pcols,pver) ! initial total liquid + real(r8):: toticeini(pcols,pver) ! initial total ice real(r8) :: tmp(pcols,pver) @@ -920,14 +927,26 @@ subroutine get_dyn_flds( state, tend, dt ) do c = begchunk, endchunk ncol = get_ncols_p(c) + ! + ! update water variables + ! + qini(:ncol,:pver) = state(c)%q(:ncol,:pver,1) + totliqini = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_liq_num + m = thermodynamic_active_species_liq_idx(m_cnst) + totliqini(:ncol,:pver) = totliqini(:ncol,:pver)+state(c)%q(:ncol,:pver,m) + end do + toticeini = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_ice_num + m = thermodynamic_active_species_ice_idx(m_cnst) + toticeini(:ncol,:pver) = toticeini(:ncol,:pver)+state(c)%q(:ncol,:pver,m) + end do + do k=1,pver do i=1,ncol if (met_nudge_temp) then state(c)%t(i,k) = (1._r8-met_rlx(k))*state(c)%t(i,k) + met_rlx(k)*met_t(i,k,c) end if - - qini(i,k) = state(c)%q(i,k,1) - ! at this point tracer mixing ratios have already been ! converted from dry to moist state(c)%q(i,k,1) = alpha*state(c)%q(i,k,1) + (D1_0-alpha)*met_q(i,k,c) @@ -940,7 +959,7 @@ subroutine get_dyn_flds( state, tend, dt ) ! now adjust mass of each layer now that water vapor has changed if (( .not. online_test ) .and. (alpha .ne. D1_0 )) then - call physics_dme_adjust(state(c), tend(c), qini, dt) + call physics_dme_adjust(state(c), tend(c), qini, totliqini, toticeini, dt) endif end do diff --git a/src/dynamics/fv3/dp_coupling.F90 b/src/dynamics/fv3/dp_coupling.F90 index 2eb69c448e..3b7fcca69b 100644 --- a/src/dynamics/fv3/dp_coupling.F90 +++ b/src/dynamics/fv3/dp_coupling.F90 @@ -733,7 +733,7 @@ subroutine derived_phys_dry(phys_state, phys_tend, pbuf2d) ! Compute initial geopotential heights - based on full pressure call geopotential_t (phys_state(lchnk)%lnpint, phys_state(lchnk)%lnpmid , phys_state(lchnk)%pint , & phys_state(lchnk)%pmid , phys_state(lchnk)%pdel , phys_state(lchnk)%rpdel , & - phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,1), rairv(:,:,lchnk), gravit, zvirv , & + phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,:), rairv(:,:,lchnk), gravit, zvirv , & phys_state(lchnk)%zi , phys_state(lchnk)%zm , ncol ) ! Compute initial dry static energy, include surface geopotential diff --git a/src/dynamics/fv3/dycore_budget.F90 b/src/dynamics/fv3/dycore_budget.F90 new file mode 100644 index 0000000000..0645edb251 --- /dev/null +++ b/src/dynamics/fv3/dycore_budget.F90 @@ -0,0 +1,27 @@ +module dycore_budget + +implicit none + +public :: print_budget + +!========================================================================================= +contains +!========================================================================================= + +subroutine print_budget(hstwr) + + use spmd_utils, only: masterproc + use cam_abortutils, only: endrun + use cam_budget, only: thermo_budget_histfile_num, thermo_budget_history + + ! arguments + logical, intent(in) :: hstwr(:) + character(len=*), parameter :: subname = 'dycore_budget:print_budgets:' + + !-------------------------------------------------------------------------------------- + + if (masterproc .and. thermo_budget_history .and. hstwr(thermo_budget_histfile_num)) then + call endrun(subname//' is not implemented for the FV3 dycore') + end if +end subroutine print_budget +end module dycore_budget diff --git a/src/dynamics/mpas/dp_coupling.F90 b/src/dynamics/mpas/dp_coupling.F90 index 2037a820cb..792a7d54b0 100644 --- a/src/dynamics/mpas/dp_coupling.F90 +++ b/src/dynamics/mpas/dp_coupling.F90 @@ -47,6 +47,7 @@ subroutine d_p_coupling(phys_state, phys_tend, pbuf2d, dyn_out) ! dry air mass. use cam_history, only : hist_fld_active use mpas_constants, only : Rv_over_Rd => rvord + use cam_budget, only : thermo_budget_history ! arguments type(physics_state), intent(inout) :: phys_state(begchunk:endchunk) @@ -70,8 +71,6 @@ subroutine d_p_coupling(phys_state, phys_tend, pbuf2d, dyn_out) real(r8), pointer :: w(:,:) real(r8), pointer :: theta_m(:,:) real(r8), pointer :: tracers(:,:,:) - - integer :: lchnk, icol, icol_p, k, kk ! indices over chunks, columns, physics columns and layers integer :: i, m, ncols, blockid integer :: block_index @@ -90,10 +89,7 @@ subroutine d_p_coupling(phys_state, phys_tend, pbuf2d, dyn_out) character(len=*), parameter :: subname = 'd_p_coupling' !---------------------------------------------------------------------------- - compute_energy_diags=& - (hist_fld_active('SE_dBF').or.hist_fld_active('SE_dAP').or.hist_fld_active('SE_dAM').or.& - hist_fld_active('KE_dBF').or.hist_fld_active('KE_dAP').or.hist_fld_active('KE_dAM').or.& - hist_fld_active('WV_dBF').or.hist_fld_active('WV_dAP').or.hist_fld_active('WV_dAM')) + compute_energy_diags=thermo_budget_history nCellsSolve = dyn_out % nCellsSolve index_qv = dyn_out % index_qv @@ -110,7 +106,7 @@ subroutine d_p_coupling(phys_state, phys_tend, pbuf2d, dyn_out) tracers => dyn_out % tracers if (compute_energy_diags) then - call tot_energy(nCellsSolve, plev,size(tracers, 1), index_qv, zz(:,1:nCellsSolve), zint(:,1:nCellsSolve), & + call tot_energy_dyn(nCellsSolve, plev,size(tracers, 1), index_qv, zz(:,1:nCellsSolve), zint(:,1:nCellsSolve), & rho_zz(:,1:nCellsSolve), theta_m(:,1:nCellsSolve), tracers(:,:,1:nCellsSolve),& ux(:,1:nCellsSolve),uy(:,1:nCellsSolve),'dBF') end if @@ -127,7 +123,7 @@ subroutine d_p_coupling(phys_state, phys_tend, pbuf2d, dyn_out) if( ierr /= 0 ) call endrun(subname//':failed to allocate pintdry array') call hydrostatic_pressure( & - nCellsSolve, plev, zz, zint, rho_zz, theta_m, tracers(index_qv,:,:),& + nCellsSolve, plev, size(tracers, 1), index_qv, zz, zint, rho_zz, theta_m, exner, tracers,& pmiddry, pintdry, pmid) call t_startf('dpcopy') @@ -324,7 +320,6 @@ end subroutine p_d_coupling !========================================================================================= subroutine derived_phys(phys_state, phys_tend, pbuf2d) - ! Compute fields in the physics state object which are diagnosed from the ! MPAS prognostic fields. @@ -332,11 +327,12 @@ subroutine derived_phys(phys_state, phys_tend, pbuf2d) use check_energy, only: check_energy_timestep_init use shr_vmath_mod, only: shr_vmath_log use phys_control, only: waccmx_is - use cam_thermo, only: cam_thermo_update - use air_composition, only: rairv + use cam_thermo, only: cam_thermo_dry_air_update, cam_thermo_water_update + use air_composition, only: rairv, dry_air_species_num use qneg_module, only: qneg3 use shr_const_mod, only: shr_const_rwv use constituents, only: qmin + use dyn_tests_utils, only: vcoord=>vc_height ! Arguments type(physics_state), intent(inout) :: phys_state(begchunk:endchunk) type(physics_tend ), intent(inout) :: phys_tend(begchunk:endchunk) @@ -344,7 +340,7 @@ subroutine derived_phys(phys_state, phys_tend, pbuf2d) ! Local variables - integer :: i, k, lchnk, m, ncol + integer :: i, k, lchnk, m, ncol, m_cnst real(r8) :: factor(pcols,pver) real(r8) :: zvirv(pcols,pver) @@ -391,7 +387,12 @@ subroutine derived_phys(phys_state, phys_tend, pbuf2d) do k = 1, pver ! To be consistent with total energy formula in physic's check_energy module only ! include water vapor in moist pdel. - factor(:ncol,k) = 1._r8 + phys_state(lchnk)%q(:ncol,k,1) + factor(:ncol,k) = 1.0_r8 + do m_cnst=1,thermodynamic_active_species_num + m = thermodynamic_active_species_idx(m_cnst) + ! at this point all q's are dry + factor(:ncol,k) = factor(:ncol,k)+phys_state(lchnk)%q(:ncol,k,m) + end do phys_state(lchnk)%pdel(:ncol,k) = phys_state(lchnk)%pdeldry(:ncol,k)*factor(:ncol,k) phys_state(lchnk)%rpdel(:ncol,k) = 1._r8 / phys_state(lchnk)%pdel(:ncol,k) end do @@ -418,18 +419,10 @@ subroutine derived_phys(phys_state, phys_tend, pbuf2d) phys_state(lchnk)%exner(:ncol,k) = (pref / phys_state(lchnk)%pmid(:ncol,k))**cappa end do - ! Tracers from MPAS are in dry mixing ratio units. CAM's physics package expects constituents - ! which have been declared to be type 'wet' when they are registered to be represented by mixing - ! ratios based on moist air mass (dry air + water vapor). Do appropriate conversion here. - factor(:ncol,:) = 1._r8/factor(:ncol,:) - do m = 1,pcnst - if (cnst_type(m) == 'wet') then - phys_state(lchnk)%q(:ncol,:,m) = factor(:ncol,:)*phys_state(lchnk)%q(:ncol,:,m) - end if - end do - if ( waccmx_is('ionosphere') .or. waccmx_is('neutral') ) then + + if (dry_air_species_num>0) then !------------------------------------------------------------ ! Apply limiters to mixing ratios of major species !------------------------------------------------------------ @@ -440,11 +433,25 @@ subroutine derived_phys(phys_state, phys_tend, pbuf2d) ! Compute molecular viscosity(kmvis) and conductivity(kmcnd). ! Fill local zvirv variable; calculated for WACCM-X. !----------------------------------------------------------------------------- - call cam_thermo_update(phys_state(lchnk)%q, phys_state(lchnk)%t, lchnk, ncol) + call cam_thermo_dry_air_update(phys_state(lchnk)%q, phys_state(lchnk)%t, lchnk, ncol) zvirv(:,:) = shr_const_rwv / rairv(:,:,lchnk) -1._r8 else zvirv(:,:) = zvir endif + ! + ! update cp_dycore in module air_composition. + ! (note: at this point q is dry) + ! + call cam_thermo_water_update(phys_state(lchnk)%q(1:ncol,:,:), lchnk, ncol, vcoord) + ! Tracers from MPAS are in dry mixing ratio units. CAM's physics package expects constituents + ! which have been declared to be type 'wet' when they are registered to be represented by mixing + ! ratios based on moist air mass (dry air + water vapor). Do appropriate conversion here. + factor(:ncol,:) = 1._r8/factor(:ncol,:) + do m = 1,pcnst + if (cnst_type(m) == 'wet') then + phys_state(lchnk)%q(:ncol,:,m) = factor(:ncol,:)*phys_state(lchnk)%q(:ncol,:,m) + end if + end do ! Compute geopotential height above surface - based on full pressure ! Note that phys_state%zi(:,plev+1) = 0 whereas zint in MPAS is surface height @@ -452,7 +459,7 @@ subroutine derived_phys(phys_state, phys_tend, pbuf2d) call geopotential_t( & phys_state(lchnk)%lnpint, phys_state(lchnk)%lnpmid, phys_state(lchnk)%pint, & phys_state(lchnk)%pmid, phys_state(lchnk)%pdel, phys_state(lchnk)%rpdel, & - phys_state(lchnk)%t, phys_state(lchnk)%q(:,:,1), rairv(:,:,lchnk), gravit, zvirv, & + phys_state(lchnk)%t, phys_state(lchnk)%q(:,:,:), rairv(:,:,lchnk), gravit, zvirv, & phys_state(lchnk)%zi, phys_state(lchnk)%zm, ncol) ! Compute initial dry static energy, include surface geopotential @@ -484,7 +491,7 @@ subroutine derived_tend(nCellsSolve, nCells, t_tend, u_tend, v_tend, q_tend, dyn use cam_mpas_subdriver, only : cam_mpas_cell_to_edge_winds, cam_mpas_update_halo use mpas_constants, only : Rv_over_Rd => rvord use time_manager, only : get_step_size - + use air_composition, only: get_R ! Arguments integer, intent(in) :: nCellsSolve integer, intent(in) :: nCells @@ -525,10 +532,13 @@ subroutine derived_tend(nCellsSolve, nCells, t_tend, u_tend, v_tend, q_tend, dyn real(r8), pointer :: uy(:,:) real(r8) :: theta_m_new(pver,nCellsSolve) !modified potential temperature after various physics updates real(r8) :: rtheta_param(pver,nCellsSolve)!tendency from temperature change only (for diagnostics) - real(r8) :: qk (thermodynamic_active_species_num,pver,nCellsSolve) !water species before physics (diagnostics) + real(r8) :: Rold(nCellsSolve,pver) + real(r8) :: Rnew(nCellsSolve,pver) + real(r8) :: qk (thermodynamic_active_species_num,pver,nCellsSolve) !water species before physics (diagnostics) + real(r8) :: qktmp (nCellsSolve,pver,thermodynamic_active_species_num) + integer :: idx_thermo (thermodynamic_active_species_num) real(r8) :: qwv(pver,nCellsSolve) !water vapor before physics real(r8) :: facnew, facold - real(r8), allocatable :: tracers_old(:,:,:) integer :: iCell,k @@ -585,38 +595,76 @@ subroutine derived_tend(nCellsSolve, nCells, t_tend, u_tend, v_tend, q_tend, dyn zint => dyn_in % zint ux => dyn_in % ux uy => dyn_in % uy + + if (compute_energy_diags) then + ! + ! Rnew and Rold are only needed for diagnostics purposes + ! + do m=1,thermodynamic_active_species_num + idx_thermo(m) = m + idx_dycore = thermodynamic_active_species_idx_dycore(m) + do iCell = 1, nCellsSolve + do k = 1, pver + qktmp(iCell,k,m) = tracers(idx_dycore,k,iCell) + end do + end do + end do + call get_R(qktmp,idx_thermo,Rnew) + Rnew = Rnew*cv/Rgas + + do m=1,thermodynamic_active_species_num + idx_dycore = thermodynamic_active_species_idx_dycore(m) + do iCell = 1, nCellsSolve + do k = 1, pver + qktmp(iCell,k,m) = tracers(idx_dycore,k,iCell)-dtime*q_tend(m,k,iCell) + end do + end do + end do + call get_R(qktmp,idx_thermo,Rold) + Rold=Rold*cv/Rgas + else + Rnew = 0.0_r8 + Rold = 1.0_r8 + end if ! ! Compute q not updated by physics ! qwv = tracers(index_qv,:,1:nCellsSolve)-dtime*q_tend(index_qv_phys,:,1:nCellsSolve) - + ! + ! for energy diagnostics compute state with physics tendency (no water change) first + ! and then add water changes (parameterizations + dme_adjust) + ! do iCell = 1, nCellsSolve do k = 1, pver rhodk = zz(k,iCell) * rho_zz(k,iCell) facold = 1.0_r8 + Rv_over_Rd *qwv(k,iCell) thetak = theta_m(k,iCell)/facold - exnerk = (rgas*rhodk*theta_m(k,iCell)/p0)**(rgas/cv) - tknew = exnerk*thetak+(cp/cv)*dtime*t_tend(k,icell) - - - thetaknew = (tknew**(cv/cp))*((rgas*rhodk*facold)/p0)**(-rgas/cp) + ! + ! for compute_energy_diags only + ! + tknew = exnerk*thetak+(cp/Rold(iCell,k))*(Rnew(iCell,k)/cp)*dtime*t_tend(k,icell)!for diags only + thetaknew = (tknew**(cv/cp))*((rgas*rhodk*facold)/p0)**(-rgas/cp) !for diags only ! ! calculate theta_m tendency due to parameterizations (but no water adjustment) + ! (for diagnostics only) ! - rtheta_param(k,iCell) = (thetaknew-thetak)/dtime - rtheta_param(k,iCell) = rtheta_param(k,iCell)*(1.0_r8 + Rv_over_Rd *qwv(k,iCell)) !convert to thetam - rtheta_param(k,iCell) = rtheta_param(k,iCell)*rho_zz(k,iCell) + rtheta_param(k,iCell) = (thetaknew-thetak)/dtime !for diags only + rtheta_param(k,iCell) = rtheta_param(k,iCell)*(1.0_r8 + Rv_over_Rd *qwv(k,iCell)) !for diags only + !convert to thetam + rtheta_param(k,iCell) = rtheta_param(k,iCell)*rho_zz(k,iCell) !for diags only ! ! include water change in theta_m ! facnew = 1.0_r8 + Rv_over_Rd *tracers(index_qv,k,iCell) + tknew = exnerk*thetak+dtime*t_tend(k,icell) thetaknew = (tknew**(cv/cp))*((rgas*rhodk*facnew)/p0)**(-rgas/cp) rtheta_tend(k,iCell) = (thetaknew*facnew-thetak*facold)/dtime rtheta_tend(k,iCell) = rtheta_tend(k,iCell) * rho_zz(k,iCell) end do end do + if (compute_energy_diags) then ! ! compute energy based on parameterization increment (excl. water change) @@ -631,7 +679,7 @@ subroutine derived_tend(nCellsSolve, nCells, t_tend, u_tend, v_tend, q_tend, dyn tracers(idx_dycore,:,1:nCellsSolve)= qk(m,:,: )-dtime*q_tend(m,:,1:nCellsSolve) end do - call tot_energy( & + call tot_energy_dyn( & nCellsSolve, plev, size(tracers, 1), index_qv, zz(:,1:nCellsSolve), zint(:,1:nCellsSolve), rho_zz(:,1:nCellsSolve), & theta_m_new, tracers(:,:,1:nCellsSolve), & ux(:,1:nCellsSolve)+dtime*u_tend(:,1:nCellsSolve)/rho_zz(:,1:nCellsSolve), & @@ -645,12 +693,17 @@ subroutine derived_tend(nCellsSolve, nCells, t_tend, u_tend, v_tend, q_tend, dyn ! compute energy incl. water change ! theta_m_new = theta_m(:,1:nCellsSolve)+dtime*rtheta_tend(:,1:nCellsSolve)/rho_zz(:,1:nCellsSolve) - call tot_energy( & + call tot_energy_dyn( & nCellsSolve, plev, size(tracers, 1), index_qv, zz(:,1:nCellsSolve), zint(:,1:nCellsSolve), & rho_zz(:,1:nCellsSolve), theta_m_new, tracers(:,:,1:nCellsSolve), & ux(:,1:nCellsSolve)+dtime*u_tend(:,1:nCellsSolve)/rho_zz(:,1:nCellsSolve), & uy(:,1:nCellsSolve)+dtime*v_tend(:,1:nCellsSolve)/rho_zz(:,1:nCellsSolve),'dAM') end if + ! + ! compute energy based on parameterization increment (excl. water change) + ! + theta_m_new = theta_m(:,1:nCellsSolve)+dtime*rtheta_param(:,1:nCellsSolve)/rho_zz(:,1:nCellsSolve) + ! ! Update halo for rtheta_m tendency ! @@ -665,8 +718,8 @@ subroutine derived_tend(nCellsSolve, nCells, t_tend, u_tend, v_tend, q_tend, dyn end subroutine derived_tend !========================================================================================= -subroutine hydrostatic_pressure(nCells, nVertLevels, zz, zgrid, rho_zz, theta_m, q, pmiddry, pintdry,pmid) - +subroutine hydrostatic_pressure(nCells, nVertLevels, qsize, index_qv, zz, zgrid, rho_zz, theta_m, & + exner, q, pmiddry, pintdry,pmid) ! Compute dry hydrostatic pressure at layer interfaces and midpoints ! ! Given arrays of zz, zgrid, rho_zz, and theta_m from the MPAS-A prognostic @@ -680,71 +733,89 @@ subroutine hydrostatic_pressure(nCells, nVertLevels, zz, zgrid, rho_zz, theta_m, ! Arguments integer, intent(in) :: nCells integer, intent(in) :: nVertLevels - real(r8), dimension(nVertLevels, nCells), intent(in) :: zz ! d(zeta)/dz [-] - real(r8), dimension(nVertLevels+1, nCells), intent(in) :: zgrid ! geometric heights of layer interfaces [m] - real(r8), dimension(nVertLevels, nCells), intent(in) :: rho_zz ! dry density / zz [kg m^-3] - real(r8), dimension(nVertLevels, nCells), intent(in) :: theta_m ! modified potential temperature - real(r8), dimension(nVertLevels, nCells), intent(in) :: q ! water vapor dry mixing ratio - real(r8), dimension(nVertLevels, nCells), intent(out):: pmiddry ! layer midpoint dry hydrostatic pressure [Pa] - real(r8), dimension(nVertLevels+1, nCells), intent(out):: pintdry ! layer interface dry hydrostatic pressure [Pa] - real(r8), dimension(nVertLevels, nCells), intent(out):: pmid ! layer midpoint hydrostatic pressure [Pa] + integer, intent(in) :: qsize + integer, intent(in) :: index_qv + real(r8), dimension(nVertLevels, nCells), intent(in) :: zz ! d(zeta)/dz [-] + real(r8), dimension(nVertLevels+1, nCells), intent(in) :: zgrid ! geometric heights of layer interfaces [m] + real(r8), dimension(nVertLevels, nCells), intent(in) :: rho_zz ! dry density / zz [kg m^-3] + real(r8), dimension(nVertLevels, nCells), intent(in) :: theta_m ! modified potential temperature + real(r8), dimension(nVertLevels, nCells), intent(in) :: exner ! Exner function + real(r8), dimension(qsize,nVertLevels, nCells), intent(in) :: q ! water vapor dry mixing ratio + real(r8), dimension(nVertLevels, nCells), intent(out):: pmiddry ! layer midpoint dry hydrostatic pressure [Pa] + real(r8), dimension(nVertLevels+1, nCells), intent(out):: pintdry ! layer interface dry hydrostatic pressure [Pa] + real(r8), dimension(nVertLevels, nCells), intent(out):: pmid ! layer midpoint hydrostatic pressure [Pa] ! Local variables - integer :: iCell, k - real(r8), dimension(nVertLevels) :: dz ! Geometric layer thickness in column - real(r8), dimension(nVertLevels+1) :: pint ! hydrostatic pressure at interface - real(r8) :: pi, t - real(r8) :: pk,rhok,rhodryk,theta,thetavk,kap1,kap2 - + integer :: iCell, k, idx + real(r8), dimension(nVertLevels) :: dz ! Geometric layer thickness in column + real(r8), dimension(nVertLevels) :: dp,dpdry ! Pressure thickness + real(r8), dimension(nVertLevels+1,nCells) :: pint ! hydrostatic pressure at interface + real(r8) :: pi, t, sum_water + real(r8) :: pk,rhok,rhodryk,theta,thetavk,kap1,kap2,tvk,tk ! ! For each column, integrate downward from model top to compute dry hydrostatic pressure at layer ! midpoints and interfaces. The pressure averaged to layer midpoints should be consistent with ! the ideal gas law using the rho_zz and theta values prognosed by MPAS at layer midpoints. ! - kap1 = p0**(-rgas/cp) ! pre-compute constants - kap2 = cp/cv ! pre-compute constants do iCell = 1, nCells - dz(:) = zgrid(2:nVertLevels+1,iCell) - zgrid(1:nVertLevels,iCell) + do k = nVertLevels, 1, -1 + rhodryk = zz(k,iCell)* rho_zz(k,iCell) !full CAM physics density + rhok = 1.0_r8 + do idx=1,thermodynamic_active_species_num + rhok = rhok+q(thermodynamic_active_species_idx_dycore(idx),k,iCell) + end do + rhok = rhok*rhodryk + dp(k) = gravit*dz(k)*rhok + dpdry(k) = gravit*dz(k)*rhodryk + end do k = nVertLevels - rhok = (1.0_r8+q(k,iCell))*zz(k,iCell) * rho_zz(k,iCell) !full CAM physics density - thetavk = theta_m(k,iCell)/ (1.0_r8 + q(k,iCell)) !convert modified theta to virtual theta - pk = (rhok*rgas*thetavk*kap1)**kap2 !mid-level top pressure + sum_water = 1.0_r8 + do idx=1,thermodynamic_active_species_num + sum_water = sum_water+q(thermodynamic_active_species_idx_dycore(idx),k,iCell) + end do + rhok = sum_water*zz(k,iCell) * rho_zz(k,iCell) + thetavk = theta_m(k,iCell)/sum_water + tvk = thetavk*exner(k,iCell) + pk = dp(k)*rgas*tvk/(gravit*dz(k)) ! ! model top pressure consistently diagnosed using the assumption that the mid level ! is at height z(nVertLevels-1)+0.5*dz - ! + ! pintdry(nVertLevels+1,iCell) = pk-0.5_r8*dz(nVertLevels)*rhok*gravity !hydrostatic - pint (nVertLevels+1) = pintdry(nVertLevels+1,iCell) + pint (nVertLevels+1,iCell) = pintdry(nVertLevels+1,iCell) do k = nVertLevels, 1, -1 ! ! compute hydrostatic dry interface pressure so that (pintdry(k+1)-pintdry(k))/g is pseudo density ! - rhodryk = zz(k,iCell) * rho_zz(k,iCell) - rhok = (1.0_r8+q(k,iCell))*rhodryk - pintdry(k,iCell) = pintdry(k+1,iCell) + gravity * rhodryk * dz(k) - pint (k) = pint (k+1) + gravity * rhok * dz(k) - end do - - do k = nVertLevels, 1, -1 - !hydrostatic mid-level pressure - MPAS full pressure is (rhok*rgas*thetavk*kap1)**kap2 - pmid (k,iCell) = 0.5_r8*(pint(k+1)+pint(k)) - !hydrostatic dry mid-level dry pressure - - !MPAS non-hydrostatic dry pressure is pmiddry(k,iCell) = (rhodryk*rgas*theta*kap1)**kap2 - pmiddry(k,iCell) = 0.5_r8*(pintdry(k+1,iCell)+pintdry(k,iCell)) + sum_water = 1.0_r8 + do idx=1,thermodynamic_active_species_num + sum_water = sum_water+q(thermodynamic_active_species_idx_dycore(idx),k,iCell) + end do + thetavk = theta_m(k,iCell)/sum_water!convert modified theta to virtual theta + tvk = thetavk*exner(k,iCell) + tk = tvk*sum_water/(1.0_r8+Rv_over_Rd*q(index_qv,k,iCell)) + pint (k,iCell) = pint (k+1,iCell)+dp(k) + pintdry(k,iCell) = pintdry(k+1,iCell)+dpdry(k) + pmid(k,iCell) = dp(k) *rgas*tvk/(gravit*dz(k)) + pmiddry(k,iCell) = dpdry(k)*rgas*tk /(gravit*dz(k)) end do end do end subroutine hydrostatic_pressure - -subroutine tot_energy(nCells, nVertLevels, qsize, index_qv, zz, zgrid, rho_zz, theta_m, q, ux,uy,outfld_name_suffix) +subroutine tot_energy_dyn(nCells, nVertLevels, qsize, index_qv, zz, zgrid, rho_zz, theta_m, q, ux,uy,outfld_name_suffix) use physconst, only: rair, cpair, gravit,cappa!=R/cp (dry air) use mpas_constants, only: p0,cv,rv,rgas,cp use cam_history, only: outfld, hist_fld_active use mpas_constants, only: Rv_over_Rd => rvord use air_composition, only: thermodynamic_active_species_ice_idx_dycore,thermodynamic_active_species_liq_idx_dycore use air_composition, only: thermodynamic_active_species_ice_num,thermodynamic_active_species_liq_num + use air_composition, only: dry_air_species_num, thermodynamic_active_species_R + use cam_thermo, only: wvidx,wlidx,wiidx,seidx,poidx,keidx,teidx,thermo_budget_num_vars + use cam_thermo, only: get_hydrostatic_energy,thermo_budget_vars + use dyn_tests_utils, only: vcoord=>vc_height + use cam_history_support, only: max_fieldname_len ! Arguments integer, intent(in) :: nCells integer, intent(in) :: nVertLevels @@ -760,83 +831,75 @@ subroutine tot_energy(nCells, nVertLevels, qsize, index_qv, zz, zgrid, rho_zz, t character*(*), intent(in) :: outfld_name_suffix ! suffix for "outfld" names ! Local variables - integer :: iCell, k, idx - real(r8) :: rho_dz,zcell,temperature,theta,pk,ptop,exner - real(r8), dimension(nVertLevels, nCells) :: rhod, dz - real(r8), dimension(nCells) :: kinetic_energy,potential_energy,internal_energy,water_vapor,water_liq,water_ice + integer :: iCell, k, idx, idx_tmp + integer :: i + real(r8) :: rho_dz,theta,pk,ptop,exner,dz,rhod + real(r8), dimension(nCells,nVertLevels) :: temperature, pdeldry, cp_or_cv, zcell, u, v + real(r8), dimension(nCells) :: phis + real(r8), dimension(nCells,nVertLevels,qsize) :: tracers + real(r8), dimension(nCells) :: kinetic_energy,potential_energy,internal_energy,water_vapor real(r8), dimension(nCells) :: liq !total column integrated liquid real(r8), dimension(nCells) :: ice !total column integrated ice - - character(len=16) :: name_out1,name_out2,name_out3,name_out4,name_out5 - - name_out1 = 'SE_' //trim(outfld_name_suffix) - name_out2 = 'KE_' //trim(outfld_name_suffix) - name_out3 = 'WV_' //trim(outfld_name_suffix) - name_out4 = 'WL_' //trim(outfld_name_suffix) - name_out5 = 'WI_' //trim(outfld_name_suffix) - - if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2).or.hist_fld_active(name_out3).or.& - hist_fld_active(name_out4).or.hist_fld_active(name_out5)) then - - kinetic_energy = 0.0_r8 - potential_energy = 0.0_r8 - internal_energy = 0.0_r8 - water_vapor = 0.0_r8 - - do iCell = 1, nCells - do k = 1, nVertLevels - dz(k,iCell) = zgrid(k+1,iCell) - zgrid(k,iCell) - zcell = 0.5_r8*(zgrid(k,iCell)+zgrid(k+1,iCell)) - rhod(k,iCell) = zz(k,iCell) * rho_zz(k,iCell) - rho_dz = (1.0_r8+q(index_qv,k,iCell))*rhod(k,iCell)*dz(k,iCell) - theta = theta_m(k,iCell)/(1.0_r8 + Rv_over_Rd *q(index_qv,k,iCell))!convert theta_m to theta - - exner = (rgas*rhod(k,iCell)*theta_m(k,iCell)/p0)**(rgas/cv) - temperature = exner*theta - - water_vapor(iCell) = water_vapor(iCell) + rhod(k,iCell)*q(index_qv,k,iCell)*dz(k,iCell) - kinetic_energy(iCell) = kinetic_energy(iCell) + & - 0.5_r8*(ux(k,iCell)**2._r8+uy(k,iCell)**2._r8)*rho_dz - potential_energy(iCell) = potential_energy(iCell)+ rho_dz*gravit*zcell - internal_energy(iCell) = internal_energy(iCell) + rho_dz*cv*temperature - end do - internal_energy(iCell) = internal_energy(iCell) + potential_energy(iCell) !static energy - end do - call outfld(name_out1,internal_energy,ncells,1) - call outfld(name_out2,kinetic_energy ,ncells,1) - call outfld(name_out3,water_vapor ,ncells,1) - ! - ! vertical integral of total liquid water - ! - if (hist_fld_active(name_out4)) then - liq = 0._r8 - do idx = 1,thermodynamic_active_species_liq_num - do iCell = 1, nCells - do k = 1, nVertLevels - liq(iCell) = liq(iCell) + & - q(thermodynamic_active_species_liq_idx_dycore(idx),k,iCell)*rhod(k,iCell)*dz(k,iCell) - end do + real(r8) :: sum_species + + character(len=max_fieldname_len) :: name_out(thermo_budget_num_vars) + + + do i=1,thermo_budget_num_vars + name_out(i)=trim(thermo_budget_vars(i))//'_'//trim(outfld_name_suffix) + end do + + kinetic_energy = 0.0_r8 + potential_energy = 0.0_r8 + internal_energy = 0.0_r8 + water_vapor = 0.0_r8 + tracers = 0.0_r8 + + do iCell = 1, nCells + do k = 1, nVertLevels + dz = zgrid(k+1,iCell) - zgrid(k,iCell) + zcell(iCell,k) = 0.5_r8*(zgrid(k,iCell)+zgrid(k+1,iCell))-zgrid(1,iCell) + rhod = zz(k,iCell) * rho_zz(k,iCell) + theta = theta_m(k,iCell)/(1.0_r8 + Rv_over_Rd *q(index_qv,k,iCell))!convert theta_m to theta + exner = (rgas*rhod*theta_m(k,iCell)/p0)**(rgas/cv) + + temperature(iCell,k) = exner*theta + pdeldry(iCell,k) = gravit*rhod*dz + ! + ! internal energy coefficient for MPAS + ! (equation 92 in Eldred et al. 2023; https://rmets.onlinelibrary.wiley.com/doi/epdf/10.1002/qj.4353) + ! + cp_or_cv(iCell,k) = rair + sum_species = 1.0_r8 + do idx=dry_air_species_num + 1,thermodynamic_active_species_num + idx_tmp = thermodynamic_active_species_idx_dycore(idx) + cp_or_cv(iCell,k) = cp_or_cv(iCell,k)+thermodynamic_active_species_R(idx)*q(idx_tmp,k,iCell) + sum_species = sum_species+q(idx_tmp,k,iCell) end do - end do - call outfld(name_out4,liq,ncells,1) - end if - ! - ! vertical integral of total frozen (ice) water - ! - if (hist_fld_active(name_out5)) then - ice = 0._r8 - do idx = 1,thermodynamic_active_species_ice_num - do iCell = 1, nCells - do k = 1, nVertLevels - ice(iCell) = ice(iCell) + & - q(thermodynamic_active_species_ice_idx_dycore(idx),k,iCell)*rhod(k,iCell)*dz(k,iCell) - end do + cp_or_cv(iCell,k) = cv*cp_or_cv(iCell,k)/(sum_species*rair) + u(iCell,k) = ux(k,iCell) + v(iCell,k) = uy(k,iCell) + phis(iCell) = zgrid(1,iCell)*gravit + do idx=1,thermodynamic_active_species_num + idx_tmp = thermodynamic_active_species_idx_dycore(idx) + tracers(iCell,k,idx_tmp) = q(idx_tmp,k,iCell) end do - end do - call outfld(name_out5,ice,ncells,1) - end if - end if - end subroutine tot_energy + end do + enddo + call get_hydrostatic_energy(tracers, .false., pdeldry, cp_or_cv, u, v, temperature, & + vcoord=vcoord, phis = phis, z_mid=zcell, dycore_idx=.true., & + se=internal_energy, po=potential_energy, ke=kinetic_energy, & + wv=water_vapor , liq=liq , ice=ice) + + call outfld(name_out(seidx),internal_energy ,ncells,1) + call outfld(name_out(poidx),potential_energy,ncells,1) + call outfld(name_out(keidx),kinetic_energy ,ncells,1) + call outfld(name_out(wvidx),water_vapor ,ncells,1) + call outfld(name_out(wlidx),liq ,ncells,1) + call outfld(name_out(wiidx),ice ,ncells,1) + call outfld(name_out(teidx),potential_energy+internal_energy+kinetic_energy,ncells,1) + +end subroutine tot_energy_dyn end module dp_coupling diff --git a/src/dynamics/mpas/dycore_budget.F90 b/src/dynamics/mpas/dycore_budget.F90 new file mode 100644 index 0000000000..18dd0e1375 --- /dev/null +++ b/src/dynamics/mpas/dycore_budget.F90 @@ -0,0 +1,407 @@ +module dycore_budget +use shr_kind_mod, only: r8=>shr_kind_r8 +implicit none + +public :: print_budget +real(r8), parameter :: eps = 1.0E-9_r8 +real(r8), parameter :: eps_mass = 1.0E-12_r8 +real(r8), save :: previous_dEdt_dry_mass_adjust = 0.0_r8 +real(r8), save :: previous_dEdt_phys_dyn_coupl_err_Agrid = 0.0_r8 +!========================================================================================= +contains +!========================================================================================= + +subroutine print_budget(hstwr) + + use cam_budget, only: cam_budget_get_global, thermo_budget_histfile_num, thermo_budget_history + use spmd_utils, only: masterproc + use cam_logfile, only: iulog + use cam_abortutils, only: endrun + use cam_thermo, only: thermo_budget_vars_descriptor, thermo_budget_num_vars, thermo_budget_vars_massv + use cam_thermo, only: teidx, seidx, keidx, poidx + + ! arguments + logical, intent(in) :: hstwr(:) + + ! Local variables + character(len=*), parameter :: subname = 'dycore_budget:print_budgets:' + ! + ! physics energy tendencies + ! + integer :: idx(4) + real(r8) :: dEdt_param_physE(4) ! dE/dt CAM physics using physics E formula (phAP-phBP) + real(r8) :: dEdt_param_dynE(4) ! dE/dt CAM physics using dycore E (dyAP-dyBP) + + real(r8) :: dEdt_efix_physE(4) ! dE/dt energy fixer using physics E formula (phBP-phBF) + real(r8) :: dEdt_efix_dynE(4) ! dE/dt energy fixer using dycore E formula (dyBP-dyBF) + + real(r8) :: dEdt_dme_adjust_physE(4) ! dE/dt dry mass adjustment using physics E formula (phAM-phAP) + real(r8) :: dEdt_dme_adjust_dynE(4) ! dE/dt dry mass adjustment using dycore E (dyAM-dyAP) + + real(r8) :: dEdt_param_efix_physE(4) ! dE/dt CAM physics + energy fixer using physics E formula (phAP-phBF) + real(r8) :: dEdt_param_efix_dynE(4) ! dE/dt CAM physics + energy fixer using dycore E formula (dyAP-dyBF) + + real(r8) :: dEdt_phys_total_dynE(4) ! dE/dt physics total using dycore E (dyAM-dyBF) + ! physics total = parameterizations + efix + dry-mass adjustment + ! + ! dycore specific energy tendencies + ! + real(r8) :: dEdt_phys_total_in_dyn(4) ! dEdt of physics total in dynamical core + ! physics total = parameterizations + efix + dry-mass adjustment + real(r8) :: dEdt_param_efix_in_dyn(4) ! dEdt CAM physics + energy fixer in dynamical core + real(r8) :: dEdt_dme_adjust_in_dyn(4) ! dEdt of dme adjust in dynamical core + real(r8) :: dEdt_dycore_and_pdc_estimated_from_efix ! dEdt dycore and PDC errors (estimated in physics) + ! + ! mass budgets physics + ! + real(r8) :: dMdt_efix ! mass tendency energy fixer + real(r8) :: dMdt_parameterizations ! mass tendency physics paramterizations + real(r8) :: dMdt_dme_adjust ! mass tendency dry-mass adjustment + real(r8) :: dMdt_phys_total ! mass tendency physics total (energy fixer + parameterizations + dry-mass adjustment) + ! + ! mass budgets dynamics + ! + real(r8) :: dMdt_phys_total_in_dyn ! mass tendency physics total in dycore + real(r8) :: dMdt_PDC ! mass tendency physics-dynamics coupling + ! + ! physics-dynamics coupling variables + ! + real(r8) :: E_dBF(4) ! E of dynamics state at the end of dycore integration (on dycore deomposition) + real(r8) :: E_dyBF(4) ! E of physics state using dycore E + + + real(r8) :: diff, tmp ! dummy variables + integer :: m_cnst, i + character(LEN=*), parameter :: fmt = "(a40,a15,a1,F6.2,a1,F6.2,a1,E10.2,a5)" + character(LEN=*), parameter :: fmtf = "(a48,F8.4,a6)" + character(LEN=*), parameter :: fmtm = "(a48,E8.2,a9)" + character(LEN=15) :: str(4) + character(LEN=5) :: pf ! pass or fail identifier + !-------------------------------------------------------------------------------------- + + if (masterproc .and. thermo_budget_history .and. hstwr(thermo_budget_histfile_num)) then + idx(1) = teidx !total energy index + idx(2) = seidx !enthaly index + idx(3) = keidx !kinetic energy index + idx(4) = poidx !surface potential energy index + str(1) = "(total )" + str(2) = "(internal )" + str(3) = "(kinetic )" + str(4) = "(potential )" + do i=1,4 + ! + ! CAM physics energy tendencies + ! + call cam_budget_get_global('phAP-phBP',idx(i),dEdt_param_physE(i)) + call cam_budget_get_global('phBP-phBF',idx(i),dEdt_efix_physE(i)) + call cam_budget_get_global('phAM-phAP',idx(i),dEdt_dme_adjust_physE(i)) + call cam_budget_get_global('phAP-phBF',idx(i),dEdt_param_efix_physE(i)) + ! + ! CAM physics energy tendencies using dycore energy formula scaling + ! temperature tendencies for consistency with CAM physics + ! + call cam_budget_get_global('dyAP-dyBP',idx(i),dEdt_param_dynE(i)) + call cam_budget_get_global('dyBP-dyBF',idx(i),dEdt_efix_dynE(i)) + call cam_budget_get_global('dyAM-dyAP',idx(i),dEdt_dme_adjust_dynE(i)) + call cam_budget_get_global('dyAP-dyBF',idx(i),dEdt_param_efix_dynE(i)) + call cam_budget_get_global('dyAM-dyBF',idx(i),dEdt_phys_total_dynE(i)) + call cam_budget_get_global('dyBF' ,idx(i),E_dyBF(i))!state beginning physics + ! + ! CAM physics energy tendencies in dynamical core + ! + call cam_budget_get_global('dAP-dBF',teidx,dEdt_param_efix_in_dyn(i)) + call cam_budget_get_global('dAM-dAP',teidx,dEdt_dme_adjust_in_dyn(i)) + call cam_budget_get_global('dAM-dBF',teidx,dEdt_param_efix_in_dyn(i)) + + call cam_budget_get_global('dAM-dBF',idx(i),dEdt_phys_total_in_dyn(i)) + call cam_budget_get_global('dBF' ,idx(i),E_dBF(i)) !state passed to physics + end do + write(iulog,*)" " + write(iulog,*)"======================================================================" + write(iulog,*)"Total energy diagnostics introduced in Lauritzen and Williamson (2019)" + write(iulog,*)"(DOI:10.1029/2018MS001549)" + write(iulog,*)"======================================================================" + write(iulog,*)" " + write(iulog,*)"Globally and vertically integrated total energy (E) diagnostics are" + write(iulog,*)"computed at various points in the physics and dynamics loops to compute" + write(iulog,*)"energy tendencies (dE/dt) and check for consistency (e.g., is E of" + write(iulog,*)"state passed to physics computed using dycore state variables the same" + write(iulog,*)"E of the state in the beginning of physics computed using the physics" + write(iulog,*)"representation of the state)" + write(iulog,*)" " + write(iulog,*)"Energy stages in physics:" + write(iulog,*)"-------------------------" + write(iulog,*)" " + write(iulog,*)" xxBF: state passed to parameterizations, before energy fixer" + write(iulog,*)" xxBP: after energy fixer, before parameterizations" + write(iulog,*)" xxAP: after last phys_update in parameterizations and state " + write(iulog,*)" saved for energy fixer" + write(iulog,*)" xxAM: after dry mass adjustment" + write(iulog,*)" history files saved off here" + write(iulog,*)" " + write(iulog,*)"where xx='ph','dy' " + write(iulog,*)" " + write(iulog,*)"Suffix ph is CAM physics total energy" + write(iulog,*)"(eq. 111 in Lauritzen et al. 2022; 10.1029/2022MS003117)" + write(iulog,*)" " + write(iulog,*)"Suffix dy is dycore energy computed in CAM physics using" + write(iulog,*)"CAM physics state variables" + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"Energy stages in dynamics" + write(iulog,*)"-------------------------" + write(iulog,*)" " + write(iulog,*)" dBF: dynamics state before physics (d_p_coupling)" + write(iulog,*)" dAP: dynamics state with T,u,V increment but not incl water changes" + write(iulog,*)" dAM: dynamics state with full physics increment (incl. water)" + write(iulog,*)" " + write(iulog,*)"Note that these energies are computed using the dynamical core" + write(iulog,*)"state variables which may be different from the physics prognostic" + write(iulog,*)"variables." + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"FYI : norm. diff = absolute normalized difference" + write(iulog,*)"FYI2: diff = difference (not normalized)" + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"Consistency check 0:" + write(iulog,*)"--------------------" + write(iulog,*)" " + write(iulog,*)"For energetic consistency we require that dE/dt [W/m^2] from energy " + write(iulog,*)"fixer and all parameterizations computed using physics E and" + write(iulog,*)"dycore in physics E are the same! Checking:" + write(iulog,*)" " + write(iulog,*) " xx=ph xx=dy norm. diff." + write(iulog,*) " ----- ----- -----------" + do i=1,4 + diff = abs_diff(dEdt_efix_physE(i),dEdt_efix_dynE(i),pf=pf) + write(iulog,fmt)"dE/dt energy fixer (xxBP-xxBF) ",str(i)," ",dEdt_efix_physE(i), " ",dEdt_efix_dynE(i)," ",diff,pf + diff = abs_diff(dEdt_param_physE(i),dEdt_param_dynE(i),pf=pf) + write(iulog,fmt)"dE/dt all parameterizations (xxAP-xxBP) ",str(i)," ",dEdt_param_physE(i)," ",dEdt_param_dynE(i)," ",diff,pf + write(iulog,*) " " + if (diff>eps) then + write(iulog,*)"FAIL" + call endrun(subname//"dE/dt's in physics inconsistent") + end if + end do + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"dE/dt from dry-mass adjustment will differ if dynamics and physics use" + write(iulog,*)"different energy definitions! Checking:" + write(iulog,*)" " + write(iulog,*) " xx=ph xx=dy diff" + write(iulog,*) " ----- ----- ----" + do i=1,4 + diff = dEdt_dme_adjust_physE(i)-dEdt_dme_adjust_dynE(i) + write(iulog,fmt)"dE/dt dry mass adjustment (xxAM-xxAP) ",str(i)," ",dEdt_dme_adjust_physE(i), & + " ",dEdt_dme_adjust_dynE(i)," ",diff + end do + write(iulog,*)" " + write(iulog,*)"Compare to dry mass adjustment in dynamics (xx=d,dy):" + write(iulog,*) " xx=d xx=dy norm. diff" + write(iulog,*) " ----- ----- ----------" + do i=1,4 + diff = abs_diff(dEdt_dme_adjust_in_dyn(i),dEdt_dme_adjust_dynE(i),pf=pf) + write(iulog,fmt)"dE/dt dry mass adjustment (xxAM-xxAP) ",str(i)," ",dEdt_dme_adjust_in_dyn(i),& + " ",dEdt_dme_adjust_dynE(i)," ",diff,pf + end do + write(iulog,*)" " + write(iulog,*)" " + ! + ! these diagnostics only make sense time-step to time-step + ! + write(iulog,*)" " + write(iulog,*)"Some energy budget observations:" + write(iulog,*)"--------------------------------" + write(iulog,*)" " + write(iulog,*)" Note that total energy fixer fixes:" + write(iulog,*)" " + write(iulog,*)" -dE/dt energy fixer(t=n) = dE/dt dry mass adjustment (t=n-1) +" + write(iulog,*)" dE/dt adiabatic dycore (t=n-1) +" + write(iulog,*)" dE/dt physics-dynamics coupling errors (t=n-1)" + write(iulog,*)" " + write(iulog,*)" (equation 23 in Lauritzen and Williamson (2019))" + write(iulog,*)" " + write(iulog,*)" Technically this equation is only valid with instantaneous time-step to" + write(iulog,*)" time-step output" + write(iulog,*) " " + write(iulog,*) " dE/dt energy fixer(t=n) = ",dEdt_efix_dynE(1) + write(iulog,*) " dE/dt dry mass adjustment (t=n-1) = ",previous_dEdt_dry_mass_adjust + write(iulog,*) " dE/dt adiabatic dycore (t=n-1) = unknown" + write(iulog,*) " dE/dt PDC errors (A-grid) (t=n-1) = ",previous_dEdt_phys_dyn_coupl_err_Agrid + write(iulog,*) " dE/dt PDC errors (other ) (t=n-1) = unknown" + + dEdt_dycore_and_pdc_estimated_from_efix = -dEdt_efix_dynE(1) - & + previous_dEdt_phys_dyn_coupl_err_Agrid - & + previous_dEdt_dry_mass_adjust + write(iulog,*) " " + write(iulog,*) "Hence the dycore E dissipation and physics-dynamics coupling errors" + write(iulog,*) "associated with mapping wind tendencies to C-grid and dribbling " + write(iulog,*) "tendencies in the dycore (PDC other), estimated from energy fixer " + write(iulog,'(A39,F6.2,A6)') "based on previous time-step values is ",dEdt_dycore_and_pdc_estimated_from_efix," W/M^2" + write(iulog,*) " " + write(iulog,*) " " + write(iulog,*) "-------------------------------------------------------------------" + write(iulog,*) " Consistency check 1: state passed to physics same as end dynamics?" + write(iulog,*) "-------------------------------------------------------------------" + write(iulog,*) " " + write(iulog,*) "Is globally integrated total energy of state at the end of dynamics (dBF)" + write(iulog,*) "and beginning of physics (using dynamics in physics energy; dyBF) the same?" + write(iulog,*) "" + + if (abs(E_dyBF(1))>eps) then + diff = abs_diff(E_dBF(1),E_dyBF(1)) + if (abs(diff)eps) then + do i=1,4 + write(iulog,*) str(i),":" + write(iulog,*) "======" + diff = abs_diff(dEdt_phys_total_dynE(i),dEdt_phys_total_in_dyn(i),pf=pf) + write(iulog,*) "dE/dt physics-dynamics coupling errors (diff) ",diff + write(iulog,*) "dE/dt physics total in dynamics (dAM-dBF) ",dEdt_phys_total_in_dyn(i) + write(iulog,*) "dE/dt physics total in physics (pAM-pBF) ",dEdt_phys_total_dynE(i) + write(iulog,*) " " + write(iulog,*) " physics total = parameterizations + efix + dry-mass adjustment" + write(iulog,*) " " + end do + end if + write(iulog,*)" " + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)" MPAS dycore energy tendencies" + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)" " + write(iulog,*)" Energy diagnostics have not been implemented in the MPAS" + write(iulog,*)" dynamical core so a detailed budget is not available." + write(iulog,*)" " + write(iulog,*)" dE/dt adiabatic dynamical core must therefore be estimated" + write(iulog,*)" from" + write(iulog,*)" " + write(iulog,*)" dE/dt adiabatic dycore (t=n-1) = " + write(iulog,*)" -dE/dt dry mass adjustment (t=n-1) +" + write(iulog,*)" -dE/dt energy fixer(t=n)" + write(iulog,*)" -dE/dt physics-dynamics coupling errors (t=n-1)" + write(iulog,*)" " + dEdt_dycore_and_pdc_estimated_from_efix = -dEdt_efix_dynE(1)-previous_dEdt_dry_mass_adjust + write(iulog,'(A34,F6.2,A6)') " = ",dEdt_dycore_and_pdc_estimated_from_efix," W/M^2" + write(iulog,*)" " + write(iulog,*)" assuming no physics-dynamics coupling errors, that is," + write(iulog,*)" dE/dt physics-dynamics coupling errors (t=n-1) = 0" + write(iulog,*)" " + write(iulog,*)" For MPAS the physics-dynamics coupling errors include:" + write(iulog,*)" - `dribbling' temperature and wind tendencies during the" + write(iulog,*)" dynamical core time-integration" + write(iulog,*)" - mapping wind tendencies from A to C grid" + write(iulog,*)" " + + write(iulog,*)" " + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)"Tracer mass budgets" + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)" " + write(iulog,*)"Below the physics-dynamics coupling error is computed as " + write(iulog,*)"dMASS/dt physics tendency in dycore (dBD-dAF) minus" + write(iulog,*)"dMASS/dt total physics (pAM-pBF)" + write(iulog,*)" " + write(iulog,*)" " + do m_cnst=1,thermo_budget_num_vars + if (thermo_budget_vars_massv(m_cnst)) then + write(iulog,*)thermo_budget_vars_descriptor(m_cnst) + write(iulog,*)"------------------------------" + call cam_budget_get_global('phBP-phBF',m_cnst,dMdt_efix) + call cam_budget_get_global('phAM-phAP',m_cnst,dMdt_dme_adjust) + call cam_budget_get_global('phAP-phBP',m_cnst,dMdt_parameterizations) + call cam_budget_get_global('phAM-phBF',m_cnst,dMdt_phys_total) + ! + ! total energy fixer should not affect mass - checking + ! + if (abs(dMdt_efix)>eps_mass) then + write(iulog,*) "dMASS/dt energy fixer (pBP-pBF) ",dMdt_efix," Pa/m^2/s" + write(iulog,*) "ERROR: Mass not conserved in energy fixer. ABORT" + call endrun(subname//"Mass not conserved in energy fixer. See atm.log") + endif + ! + ! dry-mass adjustmnt should not affect mass - checking + ! + if (abs(dMdt_dme_adjust)>eps_mass) then + write(iulog,*)"dMASS/dt dry mass adjustment (pAM-pAP) ",dMdt_dme_adjust," Pa/m^2/s" + write(iulog,*) "ERROR: Mass not conserved in dry mass adjustment. ABORT" + call endrun(subname//"Mass not conserved in dry mass adjustment. See atm.log") + end if + ! + ! all of the mass-tendency should come from parameterization - checking + ! + if (abs(dMdt_parameterizations-dMdt_phys_total)>eps_mass) then + write(iulog,*) "Error: dMASS/dt parameterizations (pAP-pBP) /= dMASS/dt physics total (pAM-pBF)" + write(iulog,*) "dMASS/dt parameterizations (pAP-pBP) ",dMdt_parameterizations," Pa/m^2/s" + write(iulog,*) "dMASS/dt physics total (pAM-pBF) ",dMdt_phys_total," Pa/m^2/s" + call endrun(subname//"mass change not only due to parameterizations. See atm.log") + end if + write(iulog,*)" " + ! + ! check if mass change in physics is the same as dynamical core + ! + call cam_budget_get_global('dAM-dBF',m_cnst,dMdt_phys_total_in_dyn) + dMdt_PDC = dMdt_phys_total-dMdt_phys_total_in_dyn + write(iulog,fmtm)" Mass physics-dynamics coupling error ",dMdt_PDC," Pa/m^2/s" + write(iulog,*)" " + if (abs(dMdt_PDC)>eps_mass) then + write(iulog,fmtm)" dMASS/dt physics tendency in dycore (dAM-dBF) ",dMdt_phys_total_in_dyn," Pa/m^2/s" + write(iulog,fmtm)" dMASS/dt total physics ",dMdt_phys_total," Pa/m^2/s" + end if + end if + end do + ! + ! save dry-mass adjustment to avoid sampling error + ! + previous_dEdt_dry_mass_adjust = dEdt_dme_adjust_dynE(1) + end if + end subroutine print_budget + !========================================================================================= + function abs_diff(a,b,pf) + real(r8), intent(in) :: a,b + character(LEN=5), optional, intent(out):: pf + real(r8) :: abs_diff + if (abs(b)>eps) then + abs_diff = abs((b-a)/b) + else + abs_diff = abs(b-a) + end if + if (present(pf)) then + if (abs_diff>eps) then + pf = ' FAIL' + else + pf = ' PASS' + end if + end if + end function abs_diff +end module dycore_budget + diff --git a/src/dynamics/mpas/dyn_comp.F90 b/src/dynamics/mpas/dyn_comp.F90 index d4ff112434..7b27c4521e 100644 --- a/src/dynamics/mpas/dyn_comp.F90 +++ b/src/dynamics/mpas/dyn_comp.F90 @@ -22,7 +22,7 @@ module dyn_comp use inic_analytic, only: analytic_ic_active, dyn_set_inic_col use dyn_tests_utils, only: vcoord=>vc_height -use cam_history, only: addfld, add_default, horiz_only, register_vector_field, & +use cam_history, only: add_default, horiz_only, register_vector_field, & outfld, hist_fld_active use cam_history_support, only: max_fieldname_len use string_utils, only: date2yyyymmdd, sec2hms, int2str @@ -39,8 +39,9 @@ module dyn_comp use cam_abortutils, only: endrun use mpas_timekeeping, only : MPAS_TimeInterval_type - use cam_mpas_subdriver, only: cam_mpas_global_sum_real +use cam_budget, only: cam_budget_em_snapshot, cam_budget_em_register + implicit none private @@ -196,8 +197,6 @@ module dyn_comp real(r8), dimension(:), pointer :: fzm ! Interp weight from k layer midpoint to k layer ! interface [dimensionless] (nver) real(r8), dimension(:), pointer :: fzp ! Interp weight from k-1 layer midpoint to k - ! layer interface [dimensionless] (nver) - ! ! State that may be directly derived from dycore prognostic state ! @@ -316,6 +315,9 @@ subroutine dyn_init(dyn_in, dyn_out) use mpas_constants, only : mpas_constants_compute_derived use dyn_tests_utils, only : vc_dycore, vc_height, string_vc, vc_str_lgth use constituents, only : cnst_get_ind + use phys_control, only: phys_getopts + use cam_budget, only: thermo_budget_history + ! arguments: type(dyn_import_t), intent(inout) :: dyn_in type(dyn_export_t), intent(inout) :: dyn_out @@ -347,29 +349,21 @@ subroutine dyn_init(dyn_in, dyn_out) character(len=*), parameter :: subname = 'dyn_comp::dyn_init' ! variables for initializing energy and axial angular momentum diagnostics - integer, parameter :: num_stages = 3, num_vars = 5 - character (len = 3), dimension(num_stages) :: stage = (/"dBF","dAP","dAM"/) + integer, parameter :: num_stages = 6 + character (len = 8), dimension(num_stages) :: stage = (/"dBF ","dAP ","dAM ","BD_dparm","BD_DMEA ","BD_phys "/) character (len = 55),dimension(num_stages) :: stage_txt = (/& " dynamics state before physics (d_p_coupling) ",& " dynamics state with T,u,V increment but not q ",& - " dynamics state with full physics increment (incl.q)" & + " dynamics state with full physics increment (incl.q)",& + "dE/dt params+efix in dycore (dparam)(dAP-dBF) ",& + "dE/dt dry mass adjustment in dycore (dAM-dAP)",& + "dE/dt physics total in dycore (phys) (dAM-dBF)" & /) - character (len = 2) , dimension(num_vars) :: vars = (/"WV" ,"WL" ,"WI" ,"SE" ,"KE"/) - character (len = 45) , dimension(num_vars) :: vars_descriptor = (/& - "Total column water vapor ",& - "Total column cloud water ",& - "Total column cloud ice ",& - "Total column static energy ",& - "Total column kinetic energy "/) - character (len = 14), dimension(num_vars) :: & - vars_unit = (/& - "kg/m2 ","kg/m2 ","kg/m2 ","J/m2 ",& - "J/m2 "/) - integer :: istage, ivars, m character (len=108) :: str1, str2, str3 character (len=vc_str_lgth) :: vc_str + !------------------------------------------------------- vc_dycore = vc_height if (masterproc) then @@ -536,40 +530,54 @@ subroutine dyn_init(dyn_in, dyn_out) ! Set the interval over which the dycore should integrate during each call to dyn_run. call MPAS_set_timeInterval(integrationLength, S=nint(dtime), S_n=0, S_d=1) - do istage = 1, num_stages - do ivars=1, num_vars - write(str1,*) TRIM(ADJUSTL(vars(ivars))),"_",TRIM(ADJUSTL(stage(istage))) - write(str2,*) TRIM(ADJUSTL(vars_descriptor(ivars)))," ", & - TRIM(ADJUSTL(stage_txt(istage))) - write(str3,*) TRIM(ADJUSTL(vars_unit(ivars))) - call addfld (TRIM(ADJUSTL(str1)), horiz_only, 'A', TRIM(ADJUSTL(str3)),TRIM(ADJUSTL(str2)), gridname='mpas_cell') - end do - end do + ! + ! initialize history for MPAS energy budgets + + if (thermo_budget_history) then + ! Define energy/mass snapshots using stage structure + do istage = 1, num_stages + call cam_budget_em_snapshot(TRIM(ADJUSTL(stage(istage))), 'dyn', longname=TRIM(ADJUSTL(stage_txt(istage)))) + end do + ! + ! initialize MPAS energy budgets + ! add budgets that are derived from stages + ! + call cam_budget_em_register('dEdt_param_efix_in_dyn','dAP','dBF',pkgtype='dyn',optype='dif', & + longname="dE/dt parameterizations+efix in dycore (dparam)(dAP-dBF)") + call cam_budget_em_register('dEdt_dme_adjust_in_dyn','dAM','dAP',pkgtype='dyn',optype='dif', & + longname="dE/dt dry mass adjustment in dycore (dAM-dAP)") + call cam_budget_em_register('dEdt_phys_total_in_dyn','dAM','dBF',pkgtype='dyn',optype='dif', & + longname="dE/dt physics total in dycore (phys) (dAM-dBF)") + end if + ! ! initialize CAM thermodynamic infrastructure ! do m=1,thermodynamic_active_species_num - thermodynamic_active_species_idx_dycore(m) = dyn_in % mpas_from_cam_cnst(thermodynamic_active_species_idx(m)) - if (masterproc) then - write(iulog,*) subname//": m,thermodynamic_active_species_idx_dycore: ",m,thermodynamic_active_species_idx_dycore(m) - end if + thermodynamic_active_species_idx_dycore(m) = dyn_out % cam_from_mpas_cnst(thermodynamic_active_species_idx(m)) + if (masterproc) then + write(iulog,'(a,2I4)') subname//": m,thermodynamic_active_species_idx_dycore: ", & + m,thermodynamic_active_species_idx_dycore(m) + end if end do do m=1,thermodynamic_active_species_liq_num - thermodynamic_active_species_liq_idx_dycore(m) = dyn_in % mpas_from_cam_cnst(thermodynamic_active_species_liq_idx(m)) - if (masterproc) then - write(iulog,*) subname//": m,thermodynamic_active_species_idx_liq_dycore: ",m,thermodynamic_active_species_liq_idx_dycore(m) - end if + thermodynamic_active_species_liq_idx_dycore(m) = dyn_out % cam_from_mpas_cnst(thermodynamic_active_species_liq_idx(m)) + if (masterproc) then + write(iulog,'(a,2I4)') subname//": m,thermodynamic_active_species_idx_liq_dycore: ", & + m,thermodynamic_active_species_liq_idx_dycore(m) + end if end do do m=1,thermodynamic_active_species_ice_num - thermodynamic_active_species_ice_idx_dycore(m) = dyn_in % mpas_from_cam_cnst(thermodynamic_active_species_ice_idx(m)) - if (masterproc) then - write(iulog,*) subname//": m,thermodynamic_active_species_idx_ice_dycore: ",m,thermodynamic_active_species_ice_idx_dycore(m) - end if + thermodynamic_active_species_ice_idx_dycore(m) = dyn_out % cam_from_mpas_cnst(thermodynamic_active_species_ice_idx(m)) + if (masterproc) then + write(iulog,'(a,2I4)') subname//": m,thermodynamic_active_species_idx_ice_dycore: ", & + m,thermodynamic_active_species_ice_idx_dycore(m) + end if end do - -end subroutine dyn_init - + + end subroutine dyn_init + !========================================================================================= subroutine dyn_run(dyn_in, dyn_out) @@ -588,6 +596,7 @@ subroutine dyn_run(dyn_in, dyn_out) ! Local variables type(mpas_pool_type), pointer :: state_pool character(len=*), parameter :: subname = 'dyn_comp:dyn_run' + real(r8) :: dtime !---------------------------------------------------------------------------- @@ -609,11 +618,10 @@ subroutine dyn_run(dyn_in, dyn_out) end subroutine dyn_run -!========================================================================================= subroutine dyn_final(dyn_in, dyn_out) - use cam_mpas_subdriver, only : cam_mpas_finalize + use cam_mpas_subdriver, only : cam_mpas_finalize ! Deallocates the dynamics import and export states, and finalizes ! the MPAS dycore. @@ -775,7 +783,7 @@ subroutine read_inidat(dyn_in) real(r8), pointer :: uReconstructZ(:,:) integer :: mpas_idx, cam_idx, ierr - character(len=16) :: trac_name + character(len=32) :: trac_name character(len=*), parameter :: subname = 'dyn_comp:read_inidat' !-------------------------------------------------------------------------------------- diff --git a/src/dynamics/mpas/dyn_grid.F90 b/src/dynamics/mpas/dyn_grid.F90 index c8efc66123..104524a3c9 100644 --- a/src/dynamics/mpas/dyn_grid.F90 +++ b/src/dynamics/mpas/dyn_grid.F90 @@ -530,6 +530,7 @@ subroutine define_cam_grids() use cam_grid_support, only: horiz_coord_t, horiz_coord_create, iMap use cam_grid_support, only: cam_grid_register, cam_grid_attribute_register + use shr_const_mod, only: PI => SHR_CONST_PI ! Local variables integer :: i, j @@ -545,6 +546,7 @@ subroutine define_cam_grids() real(r8), dimension(:), pointer :: latCell ! cell center latitude (radians) real(r8), dimension(:), pointer :: lonCell ! cell center longitude (radians) real(r8), dimension(:), pointer :: areaCell ! cell areas in m^2 + real(r8), dimension(:), pointer :: areaWeight! normalized cell areas weights integer, dimension(:), pointer :: indexToEdgeID ! global indices of edge nodes real(r8), dimension(:), pointer :: latEdge ! edge node latitude (radians) @@ -555,6 +557,13 @@ subroutine define_cam_grids() real(r8), dimension(:), pointer :: lonVertex ! vertex node longitude (radians) integer :: ierr character(len=*), parameter :: subname = 'dyn_grid::define_cam_grids' + integer :: hdim1_d ! Global Longitudes or global grid size (nCells_g) + integer :: hdim2_d ! Latitudes or 1 for unstructured grids + integer :: num_levels ! Number of levels + integer :: index_model_top_layer + integer :: index_surface_layer + logical :: unstructured + type (physics_column_t), allocatable :: dyn_cols(:) !---------------------------------------------------------------------------- call mpas_pool_get_subpool(domain_ptr % blocklist % structs, 'mesh', meshPool) @@ -578,6 +587,11 @@ subroutine define_cam_grids() lon_coord => horiz_coord_create('lonCell', 'nCells', nCells_g, 'longitude', & 'degrees_east', 1, nCellsSolve, lonCell(1:nCellsSolve)*rad2deg, map=gidx) + allocate(areaWeight(nCellsSolve), stat=ierr) + if( ierr /= 0 ) call endrun(subname//':failed to allocate area_weight :'//int2str(__LINE__)) + call get_dyn_grid_info(hdim1_d, hdim2_d, num_levels, index_model_top_layer, index_surface_layer, unstructured, dyn_cols) + + ! Map for cell centers grid allocate(grid_map(3, nCellsSolve), stat=ierr) if( ierr /= 0 ) call endrun(subname//':failed to allocate grid_map array at line:'//int2str(__LINE__)) @@ -586,11 +600,19 @@ subroutine define_cam_grids() grid_map(1, i) = i grid_map(2, i) = 1 grid_map(3, i) = gidx(i) + areaWeight(i) = dyn_cols(i)%weight/(4.0_r8*PI) end do ! cell center grid for I/O using MPAS names call cam_grid_register('mpas_cell', dyn_decomp, lat_coord, lon_coord, & grid_map, block_indexed=.false., unstruct=.true.) + call cam_grid_attribute_register('mpas_cell', 'area_cell', 'mpas cell areas', & + 'nCells', areaCell, map=gidx) + call cam_grid_attribute_register('mpas_cell', 'area_weight_mpas', 'mpas area weight', & + 'nCells', areaWeight, map=gidx) + + nullify(areaWeight) ! areaWeight belongs to grid now + nullify(areaCell) ! areaCell belongs to grid now ! create new coordinates and grid using CAM names lat_coord => horiz_coord_create('lat', 'ncol', nCells_g, 'latitude', & @@ -603,6 +625,8 @@ subroutine define_cam_grids() ! gidx can be deallocated. Values are copied into the coordinate and attribute objects. deallocate(gidx) + deallocate(dyn_cols) + ! grid_map memory cannot be deallocated. The cam_filemap_t object just points ! to it. Pointer can be disassociated. nullify(grid_map) ! Map belongs to grid now diff --git a/src/dynamics/se/advect_tend.F90 b/src/dynamics/se/advect_tend.F90 index 856e3408a2..44ea0ff6f7 100644 --- a/src/dynamics/se/advect_tend.F90 +++ b/src/dynamics/se/advect_tend.F90 @@ -25,7 +25,7 @@ subroutine compute_adv_tends_xyz(elem,fvm,nets,nete,qn0,n0) use cam_history, only: outfld, hist_fld_active use time_manager, only: get_step_size use constituents, only: tottnam,pcnst - use dimensions_mod, only: nc,np,nlev,ntrac + use dimensions_mod, only: nc,np,nlev,use_cslam use element_mod, only: element_t use fvm_control_volume_mod, only: fvm_struct implicit none @@ -38,7 +38,7 @@ subroutine compute_adv_tends_xyz(elem,fvm,nets,nete,qn0,n0) logical :: init real(r8), allocatable, dimension(:,:) :: ftmp - if (ntrac>0) then + if (use_cslam) then nx=nc else nx=np @@ -52,7 +52,7 @@ subroutine compute_adv_tends_xyz(elem,fvm,nets,nete,qn0,n0) adv_tendxyz(:,:,:,:,:) = 0._r8 endif - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete do ic=1,pcnst adv_tendxyz(:,:,:,ic,ie) = fvm(ie)%c(1:nc,1:nc,:,ic) - adv_tendxyz(:,:,:,ic,ie) diff --git a/src/dynamics/se/dp_coupling.F90 b/src/dynamics/se/dp_coupling.F90 index 03132e8ccf..7dae784315 100644 --- a/src/dynamics/se/dp_coupling.F90 +++ b/src/dynamics/se/dp_coupling.F90 @@ -57,7 +57,7 @@ subroutine d_p_coupling(phys_state, phys_tend, pbuf2d, dyn_out) use time_mod, only: timelevel_qdp use control_mod, only: qsplit use test_fvm_mapping, only: test_mapping_overwrite_dyn_state, test_mapping_output_phys_state - + use prim_advance_mod, only: tot_energy_dyn ! arguments type(dyn_export_t), intent(inout) :: dyn_out ! dynamics export type(physics_buffer_desc), pointer :: pbuf2d(:,:) @@ -128,6 +128,8 @@ subroutine d_p_coupling(phys_state, phys_tend, pbuf2d, dyn_out) allocate(q_tmp(nphys_pts,pver,pcnst,nelemd)) allocate(omega_tmp(nphys_pts,pver,nelemd)) + call tot_energy_dyn(elem,dyn_out%fvm, 1, nelemd,tl_f , tl_qdp_np0,'dBF') + if (use_gw_front .or. use_gw_front_igw) then allocate(frontgf(nphys_pts,pver,nelemd), stat=ierr) if (ierr /= 0) call endrun("dp_coupling: Allocate of frontgf failed.") @@ -377,9 +379,7 @@ subroutine p_d_coupling(phys_state, phys_tend, dyn_in, tl_f, tl_qdp) end do end do end do - call thermodynamic_consistency( & - phys_state(lchnk), phys_tend(lchnk), ncols, pver, lchnk) - end do + end do call t_startf('pd_copy') !$omp parallel do num_threads(max_num_threads) private (col_ind, lchnk, icol, ie, blk_ind, ilyr, m) @@ -539,8 +539,10 @@ subroutine derived_phys_dry(phys_state, phys_tend, pbuf2d) use constituents, only: qmin use physconst, only: gravit, zvir - use cam_thermo, only: cam_thermo_update - use air_composition, only: cpairv, rairv, cappav + use cam_thermo, only: cam_thermo_dry_air_update, cam_thermo_water_update + use air_composition, only: thermodynamic_active_species_num + use air_composition, only: thermodynamic_active_species_idx + use air_composition, only: cpairv, rairv, cappav, dry_air_species_num use shr_const_mod, only: shr_const_rwv use phys_control, only: waccmx_is use geopotential, only: geopotential_t @@ -548,7 +550,7 @@ subroutine derived_phys_dry(phys_state, phys_tend, pbuf2d) use hycoef, only: hyai, ps0 use shr_vmath_mod, only: shr_vmath_log use qneg_module, only: qneg3 - + use dyn_tests_utils, only: vc_dry_pressure ! arguments type(physics_state), intent(inout), dimension(begchunk:endchunk) :: phys_state type(physics_tend ), intent(inout), dimension(begchunk:endchunk) :: phys_tend @@ -560,7 +562,7 @@ subroutine derived_phys_dry(phys_state, phys_tend, pbuf2d) real(r8) :: zvirv(pcols,pver) ! Local zvir array pointer real(r8) :: factor_array(pcols,nlev) - integer :: m, i, k, ncol + integer :: m, i, k, ncol, m_cnst type(physics_buffer_desc), pointer :: pbuf_chnk(:) !---------------------------------------------------------------------------- @@ -602,13 +604,15 @@ subroutine derived_phys_dry(phys_state, phys_tend, pbuf2d) end do ! wet pressure variables (should be removed from physics!) - - do k=1,nlev - do i=1,ncol - ! to be consistent with total energy formula in physic's check_energy module only - ! include water vapor in in moist dp - factor_array(i,k) = 1+phys_state(lchnk)%q(i,k,1) - end do + factor_array(:,:) = 1.0_r8 + do m_cnst=1,thermodynamic_active_species_num + m = thermodynamic_active_species_idx(m_cnst) + do k=1,nlev + do i=1,ncol + ! at this point all q's are dry + factor_array(i,k) = factor_array(i,k)+phys_state(lchnk)%q(i,k,m) + end do + end do end do do k=1,nlev @@ -640,49 +644,51 @@ subroutine derived_phys_dry(phys_state, phys_tend, pbuf2d) end do end do - ! all tracers (including moisture) are in dry mixing ratio units - ! physics expect water variables moist - factor_array(1:ncol,1:nlev) = 1/factor_array(1:ncol,1:nlev) - - do m = 1,pcnst - if (cnst_type(m) == 'wet') then - do k = 1, nlev - do i = 1, ncol - phys_state(lchnk)%q(i,k,m) = factor_array(i,k)*phys_state(lchnk)%q(i,k,m) - end do - end do - end if - end do - - if ( waccmx_is('ionosphere') .or. waccmx_is('neutral') ) then - !------------------------------------------------------------ - ! Apply limiters to mixing ratios of major species - !------------------------------------------------------------ + !------------------------------------------------------------ + ! Apply limiters to mixing ratios of major species (waccmx) + !------------------------------------------------------------ + if (dry_air_species_num>0) then call physics_cnst_limit( phys_state(lchnk) ) !----------------------------------------------------------------------------- - ! Call cam_thermo_update to compute cpairv, rairv, mbarv, and cappav as + ! Call cam_thermo_dry_air_update to compute cpairv, rairv, mbarv, and cappav as ! constituent dependent variables. ! Compute molecular viscosity(kmvis) and conductivity(kmcnd). ! Fill local zvirv variable; calculated for WACCM-X. !----------------------------------------------------------------------------- - call cam_thermo_update(phys_state(lchnk)%q, phys_state(lchnk)%t, lchnk, ncol,& - to_moist_factor=phys_state(lchnk)%pdeldry(:ncol,:)/phys_state(lchnk)%pdel(:ncol,:) ) + call cam_thermo_dry_air_update(phys_state(lchnk)%q, phys_state(lchnk)%t, lchnk, ncol) zvirv(:,:) = shr_const_rwv / rairv(:,:,lchnk) -1._r8 else zvirv(:,:) = zvir - endif - + end if + ! + ! update cp_dycore in module air_composition. + ! (note: at this point q is dry) + ! + call cam_thermo_water_update(phys_state(lchnk)%q(1:ncol,:,:), lchnk, ncol, vc_dry_pressure) do k = 1, nlev do i = 1, ncol phys_state(lchnk)%exner(i,k) = (phys_state(lchnk)%pint(i,pver+1) & / phys_state(lchnk)%pmid(i,k))**cappav(i,k,lchnk) end do end do + ! + ! CAM physics: water tracers are moist; the rest dry + ! + factor_array(1:ncol,1:nlev) = 1._r8/factor_array(1:ncol,1:nlev) + do m = 1,pcnst + if (cnst_type(m) == 'wet') then + do k = 1, nlev + do i = 1, ncol + phys_state(lchnk)%q(i,k,m) = factor_array(i,k)*phys_state(lchnk)%q(i,k,m) + end do + end do + end if + end do ! Compute initial geopotential heights - based on full pressure call geopotential_t (phys_state(lchnk)%lnpint, phys_state(lchnk)%lnpmid , phys_state(lchnk)%pint , & phys_state(lchnk)%pmid , phys_state(lchnk)%pdel , phys_state(lchnk)%rpdel , & - phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,1), rairv(:,:,lchnk), gravit, zvirv , & + phys_state(lchnk)%t , phys_state(lchnk)%q(:,:,:), rairv(:,:,lchnk), gravit, zvirv , & phys_state(lchnk)%zi , phys_state(lchnk)%zm , ncol ) ! Compute initial dry static energy, include surface geopotential @@ -705,40 +711,4 @@ subroutine derived_phys_dry(phys_state, phys_tend, pbuf2d) end do ! lchnk end subroutine derived_phys_dry - -!========================================================================================= - -subroutine thermodynamic_consistency(phys_state, phys_tend, ncols, pver, lchnk) - ! - ! Adjust the physics temperature tendency for thermal energy consistency with the - ! dynamics. - ! Note: mixing ratios are assumed to be dry. - ! - use dimensions_mod, only: lcp_moist - use air_composition, only: get_cp - use control_mod, only: phys_dyn_cp - use air_composition, only: cpairv - - type(physics_state), intent(in) :: phys_state - type(physics_tend ), intent(inout) :: phys_tend - integer, intent(in) :: ncols, pver, lchnk - - real(r8):: inv_cp(ncols,pver) - !---------------------------------------------------------------------------- - - if (lcp_moist.and.phys_dyn_cp==1) then - ! - ! scale temperature tendency so that thermal energy increment from physics - ! matches SE (not taking into account dme adjust) - ! - ! note that if lcp_moist=.false. then there is thermal energy increment - ! consistency (not taking into account dme adjust) - ! - call get_cp(phys_state%q(1:ncols,1:pver,:), .true., inv_cp) - phys_tend%dtdt(1:ncols,1:pver) = phys_tend%dtdt(1:ncols,1:pver) * cpairv(1:ncols,1:pver,lchnk) * inv_cp - end if -end subroutine thermodynamic_consistency - -!========================================================================================= - end module dp_coupling diff --git a/src/dynamics/se/dycore/control_mod.F90 b/src/dynamics/se/dycore/control_mod.F90 index 0ecc2079d5..4c1127c45b 100644 --- a/src/dynamics/se/dycore/control_mod.F90 +++ b/src/dynamics/se/dycore/control_mod.F90 @@ -23,9 +23,6 @@ module control_mod ! every rsplit tracer timesteps logical, public :: variable_nsplit=.false. - integer, public :: phys_dyn_cp = 1 !=0; no thermal energy scaling of T increment - !=1; scale increment for cp consistency between dynamics and physics - logical, public :: refined_mesh integer, public :: vert_remap_q_alg = 10 diff --git a/src/dynamics/se/dycore/dimensions_mod.F90 b/src/dynamics/se/dycore/dimensions_mod.F90 index 8a41ea30c3..eb1564600c 100644 --- a/src/dynamics/se/dycore/dimensions_mod.F90 +++ b/src/dynamics/se/dycore/dimensions_mod.F90 @@ -15,7 +15,6 @@ module dimensions_mod #else integer, parameter :: ntrac_d = 0 ! No fvm tracers if CSLAM is off #endif - ! ! The variables below hold indices of water vapor and condensate loading tracers as well as ! associated heat capacities (initialized in dyn_init): @@ -31,20 +30,14 @@ module dimensions_mod ! character(len=16), allocatable, public :: cnst_name_gll(:) ! constituent names for SE tracers character(len=128), allocatable, public :: cnst_longname_gll(:) ! long name of SE tracers - ! - !moist cp in energy conversion term - ! - ! .false.: force dycore to use cpd (cp dry) instead of moist cp - ! .true. : use moist cp in dycore - ! - logical , public :: lcp_moist = .true. - + integer, parameter, public :: np = NP integer, parameter, public :: nc = 3 !cslam resolution integer , public :: fv_nphys !physics-grid resolution - the "MAX" is so that the code compiles with NC=0 - integer :: ntrac = 0 !ntrac is set in dyn_comp - integer :: qsize = 0 !qsize is set in dyn_comp + integer :: ntrac = 0 !ntrac is set in dyn_comp + logical, public :: use_cslam = .false. !logical for CSLAM + integer :: qsize = 0 !qsize is set in dyn_comp ! ! fvm dimensions: logical, public :: lprint!for debugging diff --git a/src/dynamics/se/dycore/fvm_mod.F90 b/src/dynamics/se/dycore/fvm_mod.F90 index 93aa41a008..c55358a063 100644 --- a/src/dynamics/se/dycore/fvm_mod.F90 +++ b/src/dynamics/se/dycore/fvm_mod.F90 @@ -290,14 +290,14 @@ subroutine fvm_init1(par,elem) use control_mod, only: rsplit use dimensions_mod, only: qsize, qsize_d use dimensions_mod, only: fvm_supercycling, fvm_supercycling_jet - use dimensions_mod, only: nc,nhe, nhc, nlev,ntrac, ntrac_d,ns, nhr + use dimensions_mod, only: nc,nhe, nhc, nlev,ntrac, ntrac_d,ns, nhr, use_cslam use dimensions_mod, only: large_Courant_incr use dimensions_mod, only: kmin_jet,kmax_jet type (parallel_t) :: par type (element_t),intent(inout) :: elem(:) ! - if (ntrac>0) then + if (use_cslam) then if (par%masterproc) then write(iulog,*) " " write(iulog,*) "|-----------------------------------------|" @@ -305,7 +305,7 @@ subroutine fvm_init1(par,elem) write(iulog,*) "|-----------------------------------------|" write(iulog,*) " " end if - if (ntrac>0) then + if (use_cslam) then if (par%masterproc) then write(iulog,*) "Running consistent SE-CSLAM, Lauritzen et al. (2017, MWR)." write(iulog,*) "CSLAM = Conservative Semi-LAgrangian Multi-tracer scheme" @@ -517,8 +517,8 @@ end subroutine fvm_init2 subroutine fvm_init3(elem,fvm,hybrid,nets,nete,irecons) use control_mod , only: neast, nwest, seast, swest use fvm_analytic_mod, only: compute_reconstruct_matrix - use dimensions_mod , only: fv_nphys - use dimensions_mod, only: nlev, nc, nhe, nlev, ntrac, ntrac_d,nhc + use dimensions_mod , only: fv_nphys, use_cslam + use dimensions_mod, only: nlev, nc, nhe, nlev, nhc use coordinate_systems_mod, only: cartesian2D_t,cartesian3D_t use coordinate_systems_mod, only: cubedsphere2cart, cart2cubedsphere implicit none @@ -536,7 +536,7 @@ subroutine fvm_init3(elem,fvm,hybrid,nets,nete,irecons) type (cartesian2D_t) :: gnom type(cartesian3D_t) :: tmpcart3d - if (ntrac>0.and.nc.ne.fv_nphys) then + if (use_cslam.and.nc.ne.fv_nphys) then ! ! fill the fvm halo for mapping in d_p_coupling if ! physics grid resolution is different than fvm resolution @@ -728,7 +728,6 @@ subroutine fvm_pg_init(elem, fvm, hybrid, nets, nete,irecons) use control_mod, only : neast, nwest, seast, swest use coordinate_systems_mod, only : cubedsphere2cart, cart2cubedsphere use dimensions_mod, only: fv_nphys, nhe_phys,nhc_phys - use dimensions_mod, only: ntrac_d use cube_mod ,only: dmap use control_mod ,only: cubed_sphere_map use fvm_analytic_mod, only: compute_reconstruct_matrix diff --git a/src/dynamics/se/dycore/global_norms_mod.F90 b/src/dynamics/se/dycore/global_norms_mod.F90 index de295da01a..843fd88bc7 100644 --- a/src/dynamics/se/dycore/global_norms_mod.F90 +++ b/src/dynamics/se/dycore/global_norms_mod.F90 @@ -24,26 +24,27 @@ module global_norms_mod private :: global_maximum type (EdgeBuffer_t), private :: edgebuf + interface global_integral + module procedure global_integral_elem + module procedure global_integral_fvm + end interface global_integral + contains - subroutine global_integrals(elem, h,hybrid,npts,num_flds,nets,nete,I_sphere) + subroutine global_integrals(elem,fld,hybrid,npts,num_flds,nets,nete,I_sphere) use hybrid_mod, only: hybrid_t use element_mod, only: element_t - use dimensions_mod, only: np, nelemd + use dimensions_mod, only: np use physconst, only: pi use parallel_mod, only: global_shared_buf, global_shared_sum type(element_t) , intent(in) :: elem(:) integer , intent(in) :: npts,nets,nete,num_flds - real (kind=r8), intent(in) :: h(npts,npts,num_flds,nets:nete) + real (kind=r8), intent(in) :: fld(npts,npts,num_flds,nets:nete) type (hybrid_t) , intent(in) :: hybrid real (kind=r8) :: I_sphere(num_flds) - - real (kind=r8) :: I_priv - real (kind=r8) :: I_shared - common /gblintcom/I_shared ! ! Local variables ! @@ -57,13 +58,12 @@ subroutine global_integrals(elem, h,hybrid,npts,num_flds,nets,nete,I_sphere) ! J_tmp = 0.0_r8 -!JMD print *,'global_integral: before loop' do ie=nets,nete do q=1,num_flds do j=1,np do i=1,np da = elem(ie)%mp(i,j)*elem(ie)%metdet(i,j) - J_tmp(ie,q) = J_tmp(ie,q) + da*h(i,j,q,ie) + J_tmp(ie,q) = J_tmp(ie,q) + da*fld(i,j,q,ie) end do end do end do @@ -71,28 +71,21 @@ subroutine global_integrals(elem, h,hybrid,npts,num_flds,nets,nete,I_sphere) do ie=nets,nete global_shared_buf(ie,1:num_flds) = J_tmp(ie,:) enddo - !JMD print *,'global_integral: before wrap_repro_sum' call wrap_repro_sum(nvars=num_flds, comm=hybrid%par%comm) - !JMD print *,'global_integral: after wrap_repro_sum' I_sphere(:) =global_shared_sum(1:num_flds) /(4.0_r8*PI) end subroutine global_integrals - subroutine global_integrals_general(h,hybrid,npts,da,num_flds,nets,nete,I_sphere) + subroutine global_integrals_general(fld,hybrid,npts,da,num_flds,nets,nete,I_sphere) use hybrid_mod, only: hybrid_t - use dimensions_mod, only: nc, nelemd use physconst, only: pi use parallel_mod, only: global_shared_buf, global_shared_sum integer, intent(in) :: npts,nets,nete,num_flds - real (kind=r8), intent(in) :: h(npts,npts,num_flds,nets:nete) + real (kind=r8), intent(in) :: fld(npts,npts,num_flds,nets:nete) type (hybrid_t), intent(in) :: hybrid real (kind=r8), intent(in) :: da(npts,npts,nets:nete) real (kind=r8) :: I_sphere(num_flds) - - real (kind=r8) :: I_priv - real (kind=r8) :: I_shared - common /gblintcom/I_shared ! ! Local variables ! @@ -105,12 +98,11 @@ subroutine global_integrals_general(h,hybrid,npts,da,num_flds,nets,nete,I_sphere ! J_tmp = 0.0_r8 -!JMD print *,'global_integral: before loop' do ie=nets,nete do q=1,num_flds do j=1,npts do i=1,npts - J_tmp(ie,q) = J_tmp(ie,q) + da(i,j,ie)*h(i,j,q,ie) + J_tmp(ie,q) = J_tmp(ie,q) + da(i,j,ie)*fld(i,j,q,ie) end do end do end do @@ -118,9 +110,7 @@ subroutine global_integrals_general(h,hybrid,npts,da,num_flds,nets,nete,I_sphere do ie=nets,nete global_shared_buf(ie,1:num_flds) = J_tmp(ie,:) enddo - !JMD print *,'global_integral: before wrap_repro_sum' call wrap_repro_sum(nvars=num_flds, comm=hybrid%par%comm) - !JMD print *,'global_integral: after wrap_repro_sum' I_sphere(:) =global_shared_sum(1:num_flds) /(4.0_r8*PI) end subroutine global_integrals_general @@ -133,24 +123,20 @@ end subroutine global_integrals_general ! ! ================================ ! -------------------------- - function global_integral(elem, h,hybrid,npts,nets,nete) result(I_sphere) + function global_integral_elem(elem,fld,hybrid,npts,nets,nete) result(I_sphere) use hybrid_mod, only: hybrid_t use element_mod, only: element_t - use dimensions_mod, only: np, nelemd + use dimensions_mod, only: np use physconst, only: pi use parallel_mod, only: global_shared_buf, global_shared_sum type(element_t) , intent(in) :: elem(:) integer , intent(in) :: npts,nets,nete - real (kind=r8), intent(in) :: h(npts,npts,nets:nete) + real (kind=r8), intent(in) :: fld(npts,npts,nets:nete) type (hybrid_t) , intent(in) :: hybrid real (kind=r8) :: I_sphere - real (kind=r8) :: I_priv - real (kind=r8) :: I_shared - common /gblintcom/I_shared - ! Local variables integer :: ie,j,i @@ -159,31 +145,69 @@ function global_integral(elem, h,hybrid,npts,nets,nete) result(I_sphere) real (kind=r8) :: da real (kind=r8) :: J_tmp(nets:nete) ! -! This algorythm is independent of thread count and task count. +! This algorithm is independent of thread count and task count. ! This is a requirement of consistancy checking in cam. ! J_tmp = 0.0_r8 -!JMD print *,'global_integral: before loop' do ie=nets,nete do j=1,np do i=1,np da = elem(ie)%mp(i,j)*elem(ie)%metdet(i,j) - J_tmp(ie) = J_tmp(ie) + da*h(i,j,ie) + J_tmp(ie) = J_tmp(ie) + da*fld(i,j,ie) end do end do end do do ie=nets,nete global_shared_buf(ie,1) = J_tmp(ie) enddo -!JMD print *,'global_integral: before wrap_repro_sum' call wrap_repro_sum(nvars=1, comm=hybrid%par%comm) -!JMD print *,'global_integral: after wrap_repro_sum' I_tmp = global_shared_sum(1) -!JMD print *,'global_integral: after global_shared_sum' I_sphere = I_tmp(1)/(4.0_r8*PI) - end function global_integral + end function global_integral_elem + + function global_integral_fvm(fvm,fld,hybrid,npts,nets,nete) result(I_sphere) + use hybrid_mod, only: hybrid_t + use fvm_control_volume_mod, only: fvm_struct + use physconst, only: pi + use parallel_mod, only: global_shared_buf, global_shared_sum + + type (fvm_struct) , intent(in) :: fvm(:) + integer , intent(in) :: npts,nets,nete + real (kind=r8), intent(in) :: fld(npts,npts,nets:nete) + type (hybrid_t) , intent(in) :: hybrid + + real (kind=r8) :: I_sphere + + ! Local variables + + integer :: ie,j,i + real(kind=r8) :: I_tmp(1) + + real (kind=r8) :: da + real (kind=r8) :: J_tmp(nets:nete) +! +! This algorithm is independent of thread count and task count. +! This is a requirement of consistancy checking in cam. +! + J_tmp = 0.0_r8 + do ie=nets,nete + do j=1,npts + do i=1,npts + da = fvm(ie)%area_sphere(i,j) + J_tmp(ie) = J_tmp(ie) + da*fld(i,j,ie) + end do + end do + end do + do ie=nets,nete + global_shared_buf(ie,1) = J_tmp(ie) + enddo + call wrap_repro_sum(nvars=1, comm=hybrid%par%comm) + I_tmp = global_shared_sum(1) + I_sphere = I_tmp(1)/(4.0_r8*PI) + + end function global_integral_fvm !------------------------------------------------------------------------------------ @@ -205,23 +229,22 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& ! worse viscosity CFL (given by dtnu) is not violated by reducing ! viscosity coefficient in regions where CFL is violated ! - use hybrid_mod, only: hybrid_t, PrintHybrid + use hybrid_mod, only: hybrid_t use element_mod, only: element_t - use dimensions_mod, only: np,ne,nelem,nelemd,nc,nhe,qsize,ntrac,nlev,large_Courant_incr + use dimensions_mod, only: np,ne,nelem,nc,nhe,use_cslam,nlev,large_Courant_incr use dimensions_mod, only: nu_scale_top,nu_div_lev,nu_lev,nu_t_lev use quadrature_mod, only: gausslobatto, quadrature_t use reduction_mod, only: ParallelMin,ParallelMax use physconst, only: ra, rearth, pi - use control_mod, only: nu, nu_div, nu_q, nu_p, nu_t, nu_top, fine_ne, rk_stage_user, max_hypervis_courant + use control_mod, only: nu, nu_div, nu_q, nu_p, nu_t, nu_top, fine_ne, max_hypervis_courant use control_mod, only: tstep_type, hypervis_power, hypervis_scaling use control_mod, only: sponge_del4_nu_div_fac, sponge_del4_nu_fac, sponge_del4_lev use cam_abortutils, only: endrun use parallel_mod, only: global_shared_buf, global_shared_sum use edge_mod, only: initedgebuffer, FreeEdgeBuffer, edgeVpack, edgeVunpack use bndry_mod, only: bndry_exchange - use time_mod, only: tstep use mesh_mod, only: MeshUseMeshFile use dimensions_mod, only: ksponge_end, kmvis_ref, kmcnd_ref,rho_ref use physconst, only: cpair @@ -241,14 +264,14 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& real (kind=r8) :: max_min_dx,min_min_dx,min_max_dx,max_unif_dx ! used for normalizing scalar HV real (kind=r8) :: max_normDinv, min_normDinv ! used for CFL real (kind=r8) :: min_area, max_area,max_ratio !min/max element area - real (kind=r8) :: avg_area, avg_min_dx + real (kind=r8) :: avg_area, avg_min_dx,tot_area,tot_area_rad real (kind=r8) :: min_hypervis, max_hypervis, avg_hypervis, stable_hv real (kind=r8) :: normDinv_hypervis real (kind=r8) :: x, y, noreast, nw, se, sw real (kind=r8), dimension(np,np,nets:nete) :: zeta real (kind=r8) :: lambda_max, lambda_vis, min_gw, lambda,umax, ugw - real (kind=r8) :: scale1,scale2,scale3, max_laplace,z(nlev) - integer :: ie,corner, i, j, rowind, colind, k + real (kind=r8) :: scale1, max_laplace,z(nlev) + integer :: ie, i, j, rowind, colind, k type (quadrature_t) :: gp character(LEN=256) :: rk_str @@ -257,7 +280,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& real (kind=r8) :: dt_max_hypervis, dt_max_hypervis_tracer, dt_max_laplacian_top real(kind=r8) :: I_sphere, nu_max, nu_div_max - real(kind=r8) :: h(np,np,nets:nete) + real(kind=r8) :: fld(np,np,nets:nete) logical :: top_000_032km, top_032_042km, top_042_090km, top_090_140km, top_140_600km ! model top location ranges logical :: nu_set,div_set,lev_set @@ -312,9 +335,9 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& ! !****************************************************************************************** ! - h(:,:,nets:nete)=1.0_r8 + fld(:,:,nets:nete)=1.0_r8 ! Calculate surface area by integrating 1.0_r8 over sphere and dividing by 4*PI (Should be 1) - I_sphere = global_integral(elem, h(:,:,nets:nete),hybrid,np,nets,nete) + I_sphere = global_integral(elem, fld(:,:,nets:nete),hybrid,np,nets,nete) min_normDinv = 1E99_r8 max_normDinv = 0 @@ -341,6 +364,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& enddo call wrap_repro_sum(nvars=2, comm=hybrid%par%comm) avg_area = global_shared_sum(1)/dble(nelem) + tot_area_rad = global_shared_sum(1) avg_min_dx = global_shared_sum(2)/dble(nelem) min_area = ParallelMin(min_area,hybrid) @@ -351,16 +375,19 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& max_min_dx = ParallelMax(max_min_dx,hybrid) min_max_dx = ParallelMin(min_max_dx,hybrid) max_ratio = ParallelMax(max_ratio,hybrid) - ! Physical units for area - min_area = min_area*rearth*rearth/1000000._r8 - max_area = max_area*rearth*rearth/1000000._r8 - avg_area = avg_area*rearth*rearth/1000000._r8 + ! Physical units for area (unit sphere to Earth sphere) + min_area = min_area*rearth*rearth/1000000._r8 !m2 (rearth is in units of km) + max_area = max_area*rearth*rearth/1000000._r8 !m2 (rearth is in units of km) + avg_area = avg_area*rearth*rearth/1000000._r8 !m2 (rearth is in units of km) + tot_area = tot_area_rad*rearth*rearth/1000000._r8!m2 (rearth is in units of km) if (hybrid%masterthread) then write(iulog,* )"" write(iulog,* )"Running Global Integral Diagnostic..." write(iulog,*)"Area of unit sphere is",I_sphere write(iulog,*)"Should be 1.0 to round off..." write(iulog,'(a,f9.3)') 'Element area: max/min',(max_area/min_area) + write(iulog,'(a,E23.15)') 'Total Grid area: ',(tot_area) + write(iulog,'(a,E23.15)') 'Total Grid area rad^2: ',(tot_area_rad) if (.not.MeshUseMeshFile) then write(iulog,'(a,f6.3,f8.2)') "Average equatorial node spacing (deg, km) = ", & dble(90)/dble(ne*(np-1)), PI*rearth/(2000.0_r8*dble(ne*(np-1))) @@ -716,7 +743,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& dt_max_adv = S_rk/(umax*max_normDinv*lambda_max*ra) dt_max_gw = S_rk/(ugw*max_normDinv*lambda_max*ra) dt_max_tracer_se = S_rk_tracer*min_gw/(umax*max_normDinv*ra) - if (ntrac>0) then + if (use_cslam) then if (large_Courant_incr) then dt_max_tracer_fvm = dble(nhe)*(4.0_r8*pi*Rearth/dble(4.0_r8*ne*nc))/umax else @@ -753,7 +780,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& dt_tracer_visco_actual,'s' if (dt_tracer_visco_actual>dt_max_hypervis_tracer) write(iulog,*) 'WARNING: dt_tracer_hypervis theoretically unstable' - if (ntrac>0) then + if (use_cslam) then write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_fvm (time-stepping tracers ; q ) < ',dt_max_tracer_fvm,& 's ',dt_tracer_fvm_actual if (dt_tracer_fvm_actual>dt_max_tracer_fvm) write(iulog,*) 'WARNING: dt_tracer_fvm theortically unstable' @@ -792,13 +819,13 @@ end subroutine print_cfl ! ! ================================ - function global_maximum(h,hybrid,npts,nets,nete) result(Max_sphere) + function global_maximum(fld,hybrid,npts,nets,nete) result(Max_sphere) use hybrid_mod, only : hybrid_t use reduction_mod, only : red_max, pmax_mt integer , intent(in) :: npts,nets,nete - real (kind=r8), intent(in) :: h(npts,npts,nets:nete) + real (kind=r8), intent(in) :: fld(npts,npts,nets:nete) type (hybrid_t) , intent(in) :: hybrid real (kind=r8) :: Max_sphere @@ -807,7 +834,7 @@ function global_maximum(h,hybrid,npts,nets,nete) result(Max_sphere) real (kind=r8) :: redp(1) - Max_sphere = MAXVAL(h(:,:,nets:nete)) + Max_sphere = MAXVAL(fld(:,:,nets:nete)) redp(1) = Max_sphere call pmax_mt(red_max,redp,1,hybrid) @@ -822,39 +849,39 @@ end function global_maximum ! for a scalar quantity ! =========================================================== - function l1_snorm(elem, h,ht,hybrid,npts,nets,nete) result(l1) + function l1_snorm(elem,fld,fld_exact,hybrid,npts,nets,nete) result(l1) use element_mod, only : element_t use hybrid_mod, only : hybrid_t type(element_t) , intent(in) :: elem(:) integer , intent(in) :: npts,nets,nete - real (kind=r8), intent(in) :: h(npts,npts,nets:nete) ! computed soln - real (kind=r8), intent(in) :: ht(npts,npts,nets:nete) ! true soln + real (kind=r8), intent(in) :: fld(npts,npts,nets:nete) ! computed soln + real (kind=r8), intent(in) :: fld_exact(npts,npts,nets:nete) ! true soln type (hybrid_t) , intent(in) :: hybrid real (kind=r8) :: l1 ! Local variables - real (kind=r8) :: dhabs(npts,npts,nets:nete) - real (kind=r8) :: htabs(npts,npts,nets:nete) - real (kind=r8) :: dhabs_int - real (kind=r8) :: htabs_int + real (kind=r8) :: dfld_abs(npts,npts,nets:nete) + real (kind=r8) :: fld_exact_abs(npts,npts,nets:nete) + real (kind=r8) :: dfld_abs_int + real (kind=r8) :: fld_exact_abs_int integer i,j,ie do ie=nets,nete do j=1,npts do i=1,npts - dhabs(i,j,ie) = ABS(h(i,j,ie)-ht(i,j,ie)) - htabs(i,j,ie) = ABS(ht(i,j,ie)) + dfld_abs(i,j,ie) = ABS(fld(i,j,ie)-fld_exact(i,j,ie)) + fld_exact_abs(i,j,ie) = ABS(fld_exact(i,j,ie)) end do end do end do - dhabs_int = global_integral(elem, dhabs(:,:,nets:nete),hybrid,npts,nets,nete) - htabs_int = global_integral(elem, htabs(:,:,nets:nete),hybrid,npts,nets,nete) + dfld_abs_int = global_integral(elem, dfld_abs(:,:,nets:nete),hybrid,npts,nets,nete) + fld_exact_abs_int = global_integral(elem, fld_exact_abs(:,:,nets:nete),hybrid,npts,nets,nete) - l1 = dhabs_int/htabs_int + l1 = dfld_abs_int/fld_exact_abs_int end function l1_snorm @@ -930,38 +957,38 @@ end function l1_vnorm ! ! =========================================================== - function l2_snorm(elem, h,ht,hybrid,npts,nets,nete) result(l2) + function l2_snorm(elem,fld,fld_exact,hybrid,npts,nets,nete) result(l2) use element_mod, only : element_t use hybrid_mod, only : hybrid_t type(element_t), intent(in) :: elem(:) integer , intent(in) :: npts,nets,nete - real (kind=r8), intent(in) :: h(npts,npts,nets:nete) ! computed soln - real (kind=r8), intent(in) :: ht(npts,npts,nets:nete) ! true soln + real (kind=r8), intent(in) :: fld(npts,npts,nets:nete) ! computed soln + real (kind=r8), intent(in) :: fld_exact(npts,npts,nets:nete) ! true soln type (hybrid_t) , intent(in) :: hybrid real (kind=r8) :: l2 ! Local variables real (kind=r8) :: dh2(npts,npts,nets:nete) - real (kind=r8) :: ht2(npts,npts,nets:nete) + real (kind=r8) :: fld_exact2(npts,npts,nets:nete) real (kind=r8) :: dh2_int - real (kind=r8) :: ht2_int + real (kind=r8) :: fld_exact2_int integer i,j,ie do ie=nets,nete do j=1,npts do i=1,npts - dh2(i,j,ie)=(h(i,j,ie)-ht(i,j,ie))**2 - ht2(i,j,ie)=ht(i,j,ie)**2 + dh2(i,j,ie)=(fld(i,j,ie)-fld_exact(i,j,ie))**2 + fld_exact2(i,j,ie)=fld_exact(i,j,ie)**2 end do end do end do dh2_int = global_integral(elem,dh2(:,:,nets:nete),hybrid,npts,nets,nete) - ht2_int = global_integral(elem,ht2(:,:,nets:nete),hybrid,npts,nets,nete) + fld_exact2_int = global_integral(elem,fld_exact2(:,:,nets:nete),hybrid,npts,nets,nete) - l2 = SQRT(dh2_int)/SQRT(ht2_int) + l2 = SQRT(dh2_int)/SQRT(fld_exact2_int) end function l2_snorm @@ -1036,35 +1063,35 @@ end function l2_vnorm ! ! =========================================================== - function linf_snorm(h,ht,hybrid,npts,nets,nete) result(linf) + function linf_snorm(fld,fld_exact,hybrid,npts,nets,nete) result(linf) use hybrid_mod, only : hybrid_t integer , intent(in) :: npts,nets,nete - real (kind=r8), intent(in) :: h(npts,npts,nets:nete) ! computed soln - real (kind=r8), intent(in) :: ht(npts,npts,nets:nete) ! true soln + real (kind=r8), intent(in) :: fld(npts,npts,nets:nete) ! computed soln + real (kind=r8), intent(in) :: fld_exact(npts,npts,nets:nete) ! true soln type (hybrid_t) , intent(in) :: hybrid real (kind=r8) :: linf ! Local variables - real (kind=r8) :: dhabs(npts,npts,nets:nete) - real (kind=r8) :: htabs(npts,npts,nets:nete) - real (kind=r8) :: dhabs_max - real (kind=r8) :: htabs_max + real (kind=r8) :: dfld_abs(npts,npts,nets:nete) + real (kind=r8) :: fld_exact_abs(npts,npts,nets:nete) + real (kind=r8) :: dfld_abs_max + real (kind=r8) :: fld_exact_abs_max integer i,j,ie do ie=nets,nete do j=1,npts do i=1,npts - dhabs(i,j,ie)=ABS(h(i,j,ie)-ht(i,j,ie)) - htabs(i,j,ie)=ABS(ht(i,j,ie)) + dfld_abs(i,j,ie)=ABS(fld(i,j,ie)-fld_exact(i,j,ie)) + fld_exact_abs(i,j,ie)=ABS(fld_exact(i,j,ie)) end do end do end do - dhabs_max = global_maximum(dhabs(:,:,nets:nete),hybrid,npts,nets,nete) - htabs_max = global_maximum(htabs(:,:,nets:nete),hybrid,npts,nets,nete) + dfld_abs_max = global_maximum(dfld_abs(:,:,nets:nete),hybrid,npts,nets,nete) + fld_exact_abs_max = global_maximum(fld_exact_abs(:,:,nets:nete),hybrid,npts,nets,nete) - linf = dhabs_max/htabs_max + linf = dfld_abs_max/fld_exact_abs_max end function linf_snorm diff --git a/src/dynamics/se/dycore/hybrid_mod.F90 b/src/dynamics/se/dycore/hybrid_mod.F90 index 19f1043a92..5e7b4208ca 100644 --- a/src/dynamics/se/dycore/hybrid_mod.F90 +++ b/src/dynamics/se/dycore/hybrid_mod.F90 @@ -7,7 +7,7 @@ module hybrid_mod use parallel_mod , only : parallel_t, copy_par use thread_mod , only : omp_set_num_threads, omp_get_thread_num use thread_mod , only : horz_num_threads, vert_num_threads, tracer_num_threads -use dimensions_mod, only : nlev, qsize, ntrac +use dimensions_mod, only : nlev, qsize, ntrac, use_cslam implicit none private @@ -241,7 +241,7 @@ subroutine init_loop_ranges(nelemd) work_pool_trac(ith+1,2) = end_index end do - if(ntrac>0 .and. ntrac0) then + if ((cubed_sphere_map /= 0) .AND. use_cslam) then if (par%masterproc) then write(iulog, *) subname, 'fvm transport and require equi-angle gnomonic cube sphere mapping.' write(iulog, *) ' Set cubed_sphere_map = 0 or comment it out all together. ' diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index 7f3ee98d68..c9f1ac194b 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -10,7 +10,7 @@ module prim_advance_mod private save - public :: prim_advance_exp, prim_advance_init, applyCAMforcing, calc_tot_energy_dynamics, compute_omega + public :: prim_advance_exp, prim_advance_init, applyCAMforcing, tot_energy_dyn, compute_omega type (EdgeBuffer_t) :: edge3,edgeOmega,edgeSponge real (kind=r8), allocatable :: ur_weights(:) @@ -54,16 +54,15 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net use hybvcoord_mod, only: hvcoord_t use hybrid_mod, only: hybrid_t use time_mod, only: TimeLevel_t, timelevel_qdp, tevolve - use dimensions_mod, only: lcp_moist use fvm_control_volume_mod, only: fvm_struct use cam_thermo, only: get_kappa_dry - use air_composition, only: thermodynamic_active_species_num, dry_air_species_num + use air_composition, only: thermodynamic_active_species_num use air_composition, only: thermodynamic_active_species_idx_dycore, get_cp - use physconst, only: cpair, rair + use physconst, only: cpair implicit none type (element_t), intent(inout), target :: elem(:) - type(fvm_struct) , intent(in) :: fvm(:) + type(fvm_struct) , intent(inout) :: fvm(:) type (derivative_t) , intent(in) :: deriv type (hvcoord_t) :: hvcoord type (hybrid_t) , intent(in) :: hybrid @@ -74,7 +73,6 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net ! Local real (kind=r8) :: dt_vis, eta_ave_w - real (kind=r8) :: dp(np,np) integer :: ie,nm1,n0,np1,k,qn0,m_cnst, nq real (kind=r8) :: inv_cp_full(np,np,nlev,nets:nete) real (kind=r8) :: qwater(np,np,nlev,thermodynamic_active_species_num,nets:nete) @@ -123,22 +121,16 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net ! ! make sure Q is updated ! - qwater(:,:,:,nq,ie) = elem(ie)%state%Qdp(:,:,:,m_cnst,qn0)/elem(ie)%state%dp3d(:,:,:,n0) + qwater(:,:,:,nq,ie) = elem(ie)%state%Qdp(:,:,:,m_cnst,qn0)/elem(ie)%state%dp3d(:,:,:,n0) end do end do ! - ! compute Cp and kappa=Rdry/cpdry here and not in RK-stages since Q stays constant => Cp and kappa also stays constant + ! compute Cp and kappa=Rdry/cpdry here and not in RK-stages since Q stays constant ! - if (lcp_moist) then - do ie=nets,nete - call get_cp(qwater(:,:,:,:,ie),& - .true., inv_cp_full(:,:,:,ie), active_species_idx_dycore=qidx) - end do - else - do ie=nets,nete - inv_cp_full(:,:,:,ie) = 1.0_r8/cpair - end do - end if + do ie=nets,nete + call get_cp(qwater(:,:,:,:,ie),.true.,& + inv_cp_full(:,:,:,ie), active_species_idx_dycore=qidx) + end do do ie=nets,nete call get_kappa_dry(qwater(:,:,:,:,ie), qidx, kappa(:,:,:,ie)) end do @@ -270,7 +262,7 @@ end subroutine prim_advance_exp subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsubstep) - use dimensions_mod, only: np, nc, nlev, qsize, ntrac + use dimensions_mod, only: np, nc, nlev, qsize, ntrac, use_cslam use element_mod, only: element_t use control_mod, only: ftype, ftype_conserve use fvm_control_volume_mod, only: fvm_struct @@ -290,7 +282,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu real (kind=r8), allocatable :: ftmp_fvm(:,:,:,:,:) !diagnostics - if (ntrac>0) allocate(ftmp_fvm(nc,nc,nlev,ntrac,nets:nete)) + if (use_cslam) allocate(ftmp_fvm(nc,nc,nlev,ntrac,nets:nete)) if (ftype==0) then ! @@ -322,7 +314,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu ! do state-update for tracers and "dribbling" forcing for u,v,T ! dt_local = dt_dribble - if (ntrac>0) then + if (use_cslam) then dt_local_tracer = dt_dribble dt_local_tracer_fvm = dt_phys if (nsubstep.ne.1) then @@ -371,7 +363,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu else ftmp(:,:,:,:,ie) = 0.0_r8 end if - if (ntrac>0.and.dt_local_tracer_fvm>0) then + if (use_cslam.and.dt_local_tracer_fvm>0) then ! ! Repeat for the fvm tracers: fc holds tendency (fc_new-fc_old)/dt_physics ! @@ -395,18 +387,16 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu end do end do else - if (ntrac>0) ftmp_fvm(:,:,:,:,ie) = 0.0_r8 + if (use_cslam) ftmp_fvm(:,:,:,:,ie) = 0.0_r8 end if - if (ftype_conserve==1) then call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,np1_qdp), MASS_MIXING_RATIO, & - thermodynamic_active_species_idx_dycore, elem(ie)%state%dp3d(:,:,:,np1), pdel) + thermodynamic_active_species_idx_dycore, elem(ie)%state%dp3d(:,:,:,np1), pdel) do k=1,nlev do j=1,np do i = 1,np pdel(i,j,k)=elem(ie)%derived%FDP(i,j,k)/pdel(i,j,k) - elem(ie)%state%T(i,j,k,np1) = elem(ie)%state%T(i,j,k,np1) + & dt_local*elem(ie)%derived%FT(i,j,k)*pdel(i,j,k) ! @@ -426,13 +416,13 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu dt_local*elem(ie)%derived%FM(:,:,:,:) end if end do - if (ntrac>0) then + if (use_cslam) then call output_qdp_var_dynamics(ftmp_fvm(:,:,:,:,:),nc,ntrac,nets,nete,'PDC') else call output_qdp_var_dynamics(ftmp(:,:,:,:,:),np,qsize,nets,nete,'PDC') end if - if (ftype==1.and.nsubstep==1) call calc_tot_energy_dynamics(elem,fvm,nets,nete,np1,np1_qdp,'p2d') - if (ntrac>0) deallocate(ftmp_fvm) + if (ftype==1.and.nsubstep==1) call tot_energy_dyn(elem,fvm,nets,nete,np1,np1_qdp,'p2d') + if (use_cslam) deallocate(ftmp_fvm) end subroutine applyCAMforcing @@ -446,11 +436,11 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, ! For correct scaling, dt2 should be the same 'dt2' used in the leapfrog advace ! ! - use physconst, only: gravit, cappa, cpair, tref, lapse_rate + use physconst, only: cappa, cpair use cam_thermo, only: get_molecular_diff_coef, get_rho_dry - use dimensions_mod, only: np, nlev, nc, ntrac, npsq, qsize, ksponge_end + use dimensions_mod, only: np, nlev, nc, use_cslam, npsq, qsize, ksponge_end use dimensions_mod, only: nu_scale_top,nu_lev,kmvis_ref,kmcnd_ref,rho_ref,km_sponge_factor - use dimensions_mod, only: kmvisi_ref,kmcndi_ref,nu_t_lev + use dimensions_mod, only: nu_t_lev use control_mod, only: nu, nu_t, hypervis_subcycle,hypervis_subcycle_sponge, nu_p, nu_top use control_mod, only: molecular_diff use hybrid_mod, only: hybrid_t!, get_loop_ranges @@ -468,7 +458,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, type (hybrid_t) , intent(in) :: hybrid type (element_t) , intent(inout), target :: elem(:) - type(fvm_struct) , intent(in) :: fvm(:) + type(fvm_struct) , intent(inout) :: fvm(:) type (EdgeBuffer_t), intent(inout):: edge3 type (derivative_t), intent(in ) :: deriv integer , intent(in) :: nets,nete, nt, qn0 @@ -489,16 +479,13 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, type (EdgeDescriptor_t) :: desc real (kind=r8), dimension(np,np) :: lap_t,lap_dp - real (kind=r8), dimension(np,np) :: tmp, tmp2 real (kind=r8), dimension(np,np,ksponge_end,nets:nete):: kmvis,kmcnd,rho_dry - real (kind=r8), dimension(np,np,ksponge_end+1):: kmvisi,kmcndi real (kind=r8), dimension(np,np,nlev) :: tmp_kmvis,tmp_kmcnd real (kind=r8), dimension(np,np,2) :: lap_v - real (kind=r8) :: v1,v2,v1new,v2new,dt,heating,T0,T1 + real (kind=r8) :: v1,v2,v1new,v2new,dt,heating real (kind=r8) :: laplace_fluxes(nc,nc,4) real (kind=r8) :: rhypervis_subcycle real (kind=r8) :: nu_ratio1, ptop, inv_rho - real (kind=r8), dimension(ksponge_end) :: dtemp,du,dv real (kind=r8) :: nu_temp, nu_dp, nu_velo if (nu_t == 0 .and. nu == 0 .and. nu_p==0 ) return; @@ -516,7 +503,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! do ic=1,hypervis_subcycle - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dBH') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dBH') rhypervis_subcycle=1.0_r8/real(hypervis_subcycle,kind=r8) call biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid,nt,nets,nete,kbeg,kend,hvcoord) @@ -554,7 +541,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, enddo enddo - if (ntrac>0) then + if (use_cslam) then !OMP_COLLAPSE_SIMD !DIR_VECTOR_ALIGNED do j=1,nc @@ -606,7 +593,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = kbeg - 1 + 2*nlev call edgeVunpack(edge3,vtens(:,:,2,kbeg:kend,ie),kblk,kptr,ie) - if (ntrac>0) then + if (use_cslam) then do k=kbeg,kend temp(:,:,k) = elem(ie)%state%dp3d(:,:,k,nt) / elem(ie)%spheremp ! STATE before DSS corners(0:np+1,0:np+1,k) = 0.0_r8 @@ -616,7 +603,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = kbeg - 1 + 3*nlev call edgeVunpack(edge3,elem(ie)%state%dp3d(:,:,kbeg:kend,nt),kblk,kptr,ie) - if (ntrac>0) then + if (use_cslam) then desc = elem(ie)%desc kptr = kbeg - 1 + 3*nlev @@ -676,10 +663,13 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, enddo end do - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dCH') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dCH') do ie=nets,nete !$omp parallel do num_threads(vert_num_threads), private(k,i,j,v1,v2,heating) - do k=kbeg,kend + do k=ksponge_end,nlev + ! + ! only do "frictional heating" away from sponge + ! !OMP_COLLAPSE_SIMD !DIR_VECTOR_ALIGNED do j=1,np @@ -696,7 +686,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, enddo enddo enddo - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dAH') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dAH') end do ! @@ -771,7 +761,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, ! Horizontal Laplacian diffusion ! dt=dt2/hypervis_subcycle_sponge - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dBS') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dBS') kblk = ksponge_end do ic=1,hypervis_subcycle_sponge rhypervis_subcycle=1.0_r8/real(hypervis_subcycle_sponge,kind=r8) @@ -828,7 +818,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, end do end if - if (ntrac>0.and.nu_dp>0) then + if (use_cslam.and.nu_dp>0) then ! ! mass flux for CSLAM due to sponge layer diffusion on dp ! @@ -876,7 +866,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = 2*ksponge_end call edgeVunpack(edgeSponge,vtens(:,:,2,1:ksponge_end,ie),kblk,kptr,ie) - if (ntrac>0.and.nu_dp>0.0_r8) then + if (use_cslam.and.nu_dp>0.0_r8) then do k=1,ksponge_end temp(:,:,k) = elem(ie)%state%dp3d(:,:,k,nt) / elem(ie)%spheremp ! STATE before DSS corners(0:np+1,0:np+1,k) = 0.0_r8 @@ -886,7 +876,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = 3*ksponge_end call edgeVunpack(edgeSponge,elem(ie)%state%dp3d(:,:,1:ksponge_end,nt),kblk,kptr,ie) - if (ntrac>0.and.nu_dp>0.0_r8) then + if (use_cslam.and.nu_dp>0.0_r8) then desc = elem(ie)%desc kptr = 3*ksponge_end @@ -926,38 +916,40 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, vtens(i,j,2,k,ie)=dt*vtens(i,j,2,k,ie)*elem(ie)%rspheremp(i,j) ttens(i,j,k,ie)=dt*ttens(i,j,k,ie)*elem(ie)%rspheremp(i,j) elem(ie)%state%dp3d(i,j,k,nt)=elem(ie)%state%dp3d(i,j,k,nt)*elem(ie)%rspheremp(i,j) + ! update v first (gives better results than updating v after heating) + elem(ie)%state%v(i,j,:,k,nt)=elem(ie)%state%v(i,j,:,k,nt) + vtens(i,j,:,k,ie) + elem(ie)%state%T(i,j, k,nt)=elem(ie)%state%T(i,j, k,nt) + ttens(i,j, k,ie) enddo enddo enddo - !$omp parallel do num_threads(vert_num_threads) private(k,i,j,v1,v2,v1new,v2new) - do k=1,ksponge_end - !OMP_COLLAPSE_SIMD - !DIR_VECTOR_ALIGNED - do j=1,np - do i=1,np - ! update v first (gives better results than updating v after heating) - elem(ie)%state%v(i,j,:,k,nt)=elem(ie)%state%v(i,j,:,k,nt) + & - vtens(i,j,:,k,ie) - elem(ie)%state%T(i,j,k,nt)=elem(ie)%state%T(i,j,k,nt) & - +ttens(i,j,k,ie) - - v1new=elem(ie)%state%v(i,j,1,k,nt) - v2new=elem(ie)%state%v(i,j,2,k,nt) - v1 =elem(ie)%state%v(i,j,1,k,nt)- vtens(i,j,1,k,ie) - v2 =elem(ie)%state%v(i,j,2,k,nt)- vtens(i,j,2,k,ie) - ! - ! frictional heating - ! - heating = 0.5_r8*(v1new*v1new+v2new*v2new-(v1*v1+v2*v2)) - elem(ie)%state%T(i,j,k,nt)=elem(ie)%state%T(i,j,k,nt) & - -heating*inv_cp_full(i,j,k,ie) + if (molecular_diff>0) then + ! + ! no frictional heating for artificial sponge + ! + !$omp parallel do num_threads(vert_num_threads) private(k,i,j,v1,v2,v1new,v2new) + do k=1,ksponge_end + !OMP_COLLAPSE_SIMD + !DIR_VECTOR_ALIGNED + do j=1,np + do i=1,np + v1new=elem(ie)%state%v(i,j,1,k,nt) + v2new=elem(ie)%state%v(i,j,2,k,nt) + v1 =elem(ie)%state%v(i,j,1,k,nt)- vtens(i,j,1,k,ie) + v2 =elem(ie)%state%v(i,j,2,k,nt)- vtens(i,j,2,k,ie) + ! + ! frictional heating + ! + heating = 0.5_r8*(v1new*v1new+v2new*v2new-(v1*v1+v2*v2)) + elem(ie)%state%T(i,j,k,nt)=elem(ie)%state%T(i,j,k,nt) & + -heating*inv_cp_full(i,j,k,ie) + enddo enddo enddo - enddo + end if end do end do call t_stopf('sponge_diff') - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dAS') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dAS') end subroutine advance_hypervis_dp @@ -983,7 +975,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& ! allows us to fuse these two loops for more cache reuse ! ! =================================== - use dimensions_mod, only: np, nc, nlev, ntrac, ksponge_end + use dimensions_mod, only: np, nc, nlev, use_cslam use hybrid_mod, only: hybrid_t use element_mod, only: element_t use derivative_mod, only: derivative_t, divergence_sphere, gradient_sphere, vorticity_sphere @@ -992,12 +984,10 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& use edgetype_mod, only: edgedescriptor_t use bndry_mod, only: bndry_exchange use hybvcoord_mod, only: hvcoord_t - use physconst, only: epsilo use cam_thermo, only: get_gz, get_virtual_temp use air_composition, only: thermodynamic_active_species_num, dry_air_species_num - use air_composition, only: thermodynamic_active_species_idx_dycore, get_cp_dry, get_R_dry - use physconst, only: tref,cpair,gravit,lapse_rate - use time_mod, only : tevolve + use air_composition, only: get_cp_dry, get_R_dry + use physconst, only: tref,cpair,rga,lapse_rate implicit none integer, intent(in) :: np1,nm1,n0,nets,nete @@ -1028,9 +1018,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& real (kind=r8), dimension(np,np) :: vgrad_T ! v.grad(T) real (kind=r8), dimension(np,np) :: Ephi ! kinetic energy + PHI term real (kind=r8), dimension(np,np,2,nlev) :: grad_p_full - real (kind=r8), dimension(np,np,2,nlev) :: grad_p_m_pmet! gradient(p - p_met) real (kind=r8), dimension(np,np,nlev) :: vort ! vorticity - real (kind=r8), dimension(np,np,nlev) :: p_dry ! pressure dry real (kind=r8), dimension(np,np,nlev) :: dp_dry ! delta pressure dry real (kind=r8), dimension(np,np,nlev) :: R_dry, cp_dry! real (kind=r8), dimension(np,np,nlev) :: p_full ! pressure @@ -1053,7 +1041,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& real (kind=r8) :: sum_water(np,np,nlev), density_inv(np,np) real (kind=r8) :: E,v1,v2,glnps1,glnps2 integer :: i,j,k,kptr,ie - real (kind=r8) :: u_m_umet, v_m_vmet, t_m_tmet, ptop + real (kind=r8) :: ptop !JMD call t_barrierf('sync_compute_and_apply_rhs', hybrid%par%comm) call t_adj_detailf(+1) @@ -1217,7 +1205,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& ! T1 = .0065*Tref*Cp/g ! = ~191 ! T0 = Tref-T1 ! = ~97 ! - T1 = lapse_rate*Tref*cpair/gravit + T1 = lapse_rate*Tref*cpair*rga T0 = Tref-T1 if (hvcoord%hybm(k)>0) then @@ -1274,7 +1262,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& enddo - if (ntrac>0.and.eta_ave_w.ne.0._r8) then + if (use_cslam.and.eta_ave_w.ne.0._r8) then !OMP_COLLAPSE_SIMD !DIR_VECTOR_ALIGNED do j=1,np @@ -1317,7 +1305,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& kptr=nlev call edgeVunpack(edge3, elem(ie)%state%v(:,:,:,:,np1), 2*nlev, kptr, ie) - if (ntrac>0.and.eta_ave_w.ne.0._r8) then + if (use_cslam.and.eta_ave_w.ne.0._r8) then do k=1,nlev stashdp3d(:,:,k) = elem(ie)%state%dp3d(:,:,k,np1)/elem(ie)%spheremp(:,:) end do @@ -1328,7 +1316,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& kptr=kptr+2*nlev call edgeVunpack(edge3, elem(ie)%state%dp3d(:,:,:,np1),nlev,kptr,ie) - if (ntrac>0.and.eta_ave_w.ne.0._r8) then + if (use_cslam.and.eta_ave_w.ne.0._r8) then desc = elem(ie)%desc call edgeDGVunpack(edge3, corners, nlev, kptr, ie) @@ -1447,35 +1435,50 @@ subroutine distribute_flux_at_corners(cflux, corners, getmapP) endif end subroutine distribute_flux_at_corners - subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suffix) - use dimensions_mod, only: npsq,nlev,np,lcp_moist,nc,ntrac,qsize - use physconst, only: gravit, cpair, rearth, omega + subroutine tot_energy_dyn(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suffix) + use dimensions_mod, only: npsq,nlev,np,nc,use_cslam,qsize + use physconst, only: rga, cpair, rearth, omega use element_mod, only: element_t - use cam_history, only: outfld, hist_fld_active + use cam_history, only: outfld + use cam_history_support, only: max_fieldname_len use constituents, only: cnst_get_ind use string_utils, only: strlist_get_ind use hycoef, only: hyai, ps0 use fvm_control_volume_mod, only: fvm_struct - use cam_thermo, only: get_dp, MASS_MIXING_RATIO + use cam_thermo, only: get_dp, MASS_MIXING_RATIO,wvidx,wlidx,wiidx,seidx,keidx,moidx,mridx,ttidx,teidx, & + poidx,thermo_budget_num_vars,thermo_budget_vars + use cam_thermo, only: get_hydrostatic_energy use air_composition, only: thermodynamic_active_species_idx_dycore, get_cp + use air_composition, only: thermodynamic_active_species_num, thermodynamic_active_species_idx_dycore + use air_composition, only: thermodynamic_active_species_liq_num,thermodynamic_active_species_liq_idx + use air_composition, only: thermodynamic_active_species_ice_num,thermodynamic_active_species_ice_idx use dimensions_mod, only: cnst_name_gll + use dyn_tests_utils, only: vcoord=>vc_dry_pressure + use cam_budget, only: thermo_budget_history !------------------------------Arguments-------------------------------- - type (element_t) , intent(in) :: elem(:) - type(fvm_struct) , intent(in) :: fvm(:) + type (element_t) , intent(inout) :: elem(:) + type(fvm_struct) , intent(inout) :: fvm(:) integer , intent(in) :: tl, tl_qdp,nets,nete character*(*) , intent(in) :: outfld_name_suffix ! suffix for "outfld" names !---------------------------Local storage------------------------------- - real(kind=r8) :: se(npsq) ! Dry Static energy (J/m2) - real(kind=r8) :: ke(npsq) ! kinetic energy (J/m2) + real(kind=r8) :: se(np,np) ! Enthalpy energy (J/m2) + real(kind=r8) :: ke(np,np) ! kinetic energy (J/m2) + real(kind=r8) :: po(np,np) ! PHIS term in energy equation (J/m2) + real(kind=r8) :: wv(np,np) ! water vapor + real(kind=r8) :: liq(np,np) ! liquid + real(kind=r8) :: ice(np,np) ! ice + real(kind=r8) :: q(np,nlev,qsize) + integer :: qidx(thermodynamic_active_species_num) real(kind=r8) :: cdp_fvm(nc,nc,nlev) - real(kind=r8) :: se_tmp - real(kind=r8) :: ke_tmp - real(kind=r8) :: ps(np,np) + real(kind=r8) :: cdp(np,np,nlev) + real(kind=r8) :: ptop(np,np) real(kind=r8) :: pdel(np,np,nlev) + real(kind=r8) :: cp(np,np,nlev) + ! ! global axial angular momentum (AAM) can be separated into one part (mr) associatedwith the relative motion ! of the atmosphere with respect to the planets surface (also known as wind AAM) and another part (mo) @@ -1485,25 +1488,19 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf real(kind=r8) :: mr(npsq) ! wind AAM real(kind=r8) :: mo(npsq) ! mass AAM real(kind=r8) :: mr_cnst, mo_cnst, cos_lat, mr_tmp, mo_tmp - real(kind=r8) :: cp(np,np,nlev) - integer :: ie,i,j,k + integer :: ie,i,j,k,m_cnst,nq,idx integer :: ixwv,ixcldice, ixcldliq, ixtt ! CLDICE, CLDLIQ and test tracer indices - character(len=16) :: name_out1,name_out2,name_out3,name_out4,name_out5,name_out6 + character(len=max_fieldname_len) :: name_out(thermo_budget_num_vars) !----------------------------------------------------------------------- - name_out1 = 'SE_' //trim(outfld_name_suffix) - name_out2 = 'KE_' //trim(outfld_name_suffix) - name_out3 = 'WV_' //trim(outfld_name_suffix) - name_out4 = 'WL_' //trim(outfld_name_suffix) - name_out5 = 'WI_' //trim(outfld_name_suffix) - name_out6 = 'TT_' //trim(outfld_name_suffix) - - if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2).or.hist_fld_active(name_out3).or.& - hist_fld_active(name_out4).or.hist_fld_active(name_out5).or.hist_fld_active(name_out6)) then + if (thermo_budget_history) then + do i=1,thermo_budget_num_vars + name_out(i)=trim(thermo_budget_vars(i))//'_'//trim(outfld_name_suffix) + end do - if (ntrac>0) then + if (use_cslam) then ixwv = 1 call cnst_get_ind('CLDLIQ' , ixcldliq, abort=.false.) call cnst_get_ind('CLDICE' , ixcldice, abort=.false.) @@ -1519,79 +1516,104 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf ! ! Compute frozen static energy in 3 parts: KE, SE, and energy associated with vapor and liquid ! + do nq=1,thermodynamic_active_species_num + qidx(nq) = nq + end do do ie=nets,nete - se = 0.0_r8 - ke = 0.0_r8 - call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,tl_qdp), MASS_MIXING_RATIO, thermodynamic_active_species_idx_dycore,& - elem(ie)%state%dp3d(:,:,:,tl), pdel, ps=ps, ptop=hyai(1)*ps0) call get_cp(elem(ie)%state%Qdp(:,:,:,1:qsize,tl_qdp),& - .false., cp, dp_dry=elem(ie)%state%dp3d(:,:,:,tl),& + .false., cp, factor=1.0_r8/elem(ie)%state%dp3d(:,:,:,tl),& active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - do k = 1, nlev - do j=1,np - do i = 1, np - ! - ! kinetic energy - ! - ke_tmp = 0.5_r8*(elem(ie)%state%v(i,j,1,k,tl)**2+ elem(ie)%state%v(i,j,2,k,tl)**2)*pdel(i,j,k)/gravit - if (lcp_moist) then - se_tmp = cp(i,j,k)*elem(ie)%state%T(i,j,k,tl)*pdel(i,j,k)/gravit - else - ! - ! using CAM physics definition of internal energy - ! - se_tmp = cpair*elem(ie)%state%T(i,j,k,tl)*pdel(i,j,k)/gravit - end if - se (i+(j-1)*np) = se (i+(j-1)*np) + se_tmp - ke (i+(j-1)*np) = ke (i+(j-1)*np) + ke_tmp - end do - end do - end do - + ptop = hyai(1)*ps0 do j=1,np - do i = 1, np - se(i+(j-1)*np) = se(i+(j-1)*np) + elem(ie)%state%phis(i,j)*ps(i,j)/gravit + !get mixing ratio of thermodynamic active species only + !(other tracers not used in get_hydrostatic_energy) + do nq=1,thermodynamic_active_species_num + m_cnst = thermodynamic_active_species_idx_dycore(nq) + q(:,:,m_cnst) = elem(ie)%state%Qdp(:,j,:,m_cnst,tl_qdp)/& + elem(ie)%state%dp3d(:,j,:,tl) end do + call get_hydrostatic_energy(q, & + .false., elem(ie)%state%dp3d(:,j,:,tl), cp(:,j,:), elem(ie)%state%v(:,j,1,:,tl), & + elem(ie)%state%v(:,j,2,:,tl), elem(ie)%state%T(:,j,:,tl), vcoord, ptop=ptop(:,j),& + phis=elem(ie)%state%phis(:,j), dycore_idx=.true., & + se=se(:,j), po=po(:,j), ke=ke(:,j), wv=wv(:,j), liq=liq(:,j), ice=ice(:,j)) end do ! ! Output energy diagnostics on GLL grid ! - call outfld(name_out1 ,se ,npsq,ie) - call outfld(name_out2 ,ke ,npsq,ie) + call outfld(name_out(poidx) ,po ,npsq,ie) + call outfld(name_out(seidx) ,se ,npsq,ie) + call outfld(name_out(keidx) ,ke ,npsq,ie) + call outfld(name_out(teidx) ,ke+se+po ,npsq,ie) ! ! mass variables are output on CSLAM grid if using CSLAM else GLL grid ! - if (ntrac>0) then - if (ixwv>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixwv)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out3,ie) - end if - if (ixcldliq>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixcldliq)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out4,ie) - end if - if (ixcldice>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixcldice)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out5,ie) - end if - if (ixtt>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixtt)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out6,ie) - end if + if (use_cslam) then + if (ixwv>0) then + cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixwv)*fvm(ie)%dp_fvm(1:nc,1:nc,:) + call util_function(cdp_fvm,nc,nlev,name_out(wvidx),ie) + end if + ! + ! sum over liquid water + ! + if (thermodynamic_active_species_liq_num>0) then + cdp_fvm = 0.0_r8 + do nq = 1,thermodynamic_active_species_liq_num + cdp_fvm = cdp_fvm + fvm(ie)%c(1:nc,1:nc,:,thermodynamic_active_species_liq_idx(nq))& + *fvm(ie)%dp_fvm(1:nc,1:nc,:) + end do + call util_function(cdp_fvm,nc,nlev,name_out(wlidx),ie) + end if + ! + ! sum over ice water + ! + if (thermodynamic_active_species_ice_num>0) then + cdp_fvm = 0.0_r8 + do nq = 1,thermodynamic_active_species_ice_num + cdp_fvm = cdp_fvm + fvm(ie)%c(1:nc,1:nc,:,thermodynamic_active_species_ice_idx(nq))& + *fvm(ie)%dp_fvm(1:nc,1:nc,:) + end do + call util_function(cdp_fvm,nc,nlev,name_out(wiidx),ie) + end if + if (ixtt>0) then + cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixtt)*fvm(ie)%dp_fvm(1:nc,1:nc,:) + call util_function(cdp_fvm,nc,nlev,name_out(ttidx),ie) + end if else - call util_function(elem(ie)%state%qdp(:,:,:,1 ,tl_qdp),np,nlev,name_out3,ie) - if (ixcldliq>0) call util_function(elem(ie)%state%qdp(:,:,:,ixcldliq,tl_qdp),np,nlev,name_out4,ie) - if (ixcldice>0) call util_function(elem(ie)%state%qdp(:,:,:,ixcldice,tl_qdp),np,nlev,name_out5,ie) - if (ixtt>0 ) call util_function(elem(ie)%state%qdp(:,:,:,ixtt ,tl_qdp),np,nlev,name_out6,ie) + cdp = elem(ie)%state%qdp(:,:,:,1,tl_qdp) + call util_function(cdp,np,nlev,name_out(wvidx),ie) + ! + ! sum over liquid water + ! + if (thermodynamic_active_species_liq_num>0) then + cdp = 0.0_r8 + do idx = 1,thermodynamic_active_species_liq_num + cdp = cdp + elem(ie)%state%qdp(:,:,:,thermodynamic_active_species_liq_idx(idx),tl_qdp) + end do + call util_function(cdp,np,nlev,name_out(wlidx),ie) + end if + ! + ! sum over ice water + ! + if (thermodynamic_active_species_ice_num>0) then + cdp = 0.0_r8 + do idx = 1,thermodynamic_active_species_ice_num + cdp = cdp + elem(ie)%state%qdp(:,:,:,thermodynamic_active_species_ice_idx(idx),tl_qdp) + end do + call util_function(cdp,np,nlev,name_out(wiidx),ie) + end if + if (ixtt>0) then + cdp = elem(ie)%state%qdp(:,:,:,ixtt ,tl_qdp) + call util_function(cdp,np,nlev,name_out(ttidx),ie) + end if end if - end do - end if - ! - ! Axial angular momentum diagnostics - ! - ! Code follows - ! - ! Lauritzen et al., (2014): Held-Suarez simulations with the Community Atmosphere Model + end do + ! + ! Axial angular momentum diagnostics + ! + ! Code follows + ! + ! Lauritzen et al., (2014): Held-Suarez simulations with the Community Atmosphere Model ! Spectral Element (CAM-SE) dynamical core: A global axial angularmomentum analysis using Eulerian ! and floating Lagrangian vertical coordinates. J. Adv. Model. Earth Syst. 6,129-140, ! doi:10.1002/2013MS000268 @@ -1599,19 +1621,16 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf ! MR is equation (6) without \Delta A and sum over areas (areas are in units of radians**2) ! MO is equation (7) without \Delta A and sum over areas (areas are in units of radians**2) ! - name_out1 = 'MR_' //trim(outfld_name_suffix) - name_out2 = 'MO_' //trim(outfld_name_suffix) - if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2)) then call strlist_get_ind(cnst_name_gll, 'CLDLIQ', ixcldliq, abort=.false.) call strlist_get_ind(cnst_name_gll, 'CLDICE', ixcldice, abort=.false.) - mr_cnst = rearth**3/gravit - mo_cnst = omega*rearth**4/gravit + mr_cnst = rga*rearth**3 + mo_cnst = rga*omega*rearth**4 do ie=nets,nete mr = 0.0_r8 mo = 0.0_r8 call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,tl_qdp), MASS_MIXING_RATIO, thermodynamic_active_species_idx_dycore,& - elem(ie)%state%dp3d(:,:,:,tl), pdel, ps=ps, ptop=hyai(1)*ps0) + elem(ie)%state%dp3d(:,:,:,tl), pdel) do k = 1, nlev do j=1,np do i = 1, np @@ -1624,17 +1643,17 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf end do end do end do - call outfld(name_out1 ,mr ,npsq,ie) - call outfld(name_out2 ,mo ,npsq,ie) + call outfld(name_out(mridx) ,mr ,npsq,ie) + call outfld(name_out(moidx) ,mo ,npsq,ie) end do - end if + endif ! if thermo budget history + end subroutine tot_energy_dyn - end subroutine calc_tot_energy_dynamics subroutine output_qdp_var_dynamics(qdp,nx,num_trac,nets,nete,outfld_name) - use dimensions_mod, only: nlev,ntrac - use cam_history , only: outfld, hist_fld_active + use dimensions_mod, only: nlev + use cam_history , only: hist_fld_active use constituents , only: cnst_get_ind !------------------------------Arguments-------------------------------- @@ -1674,17 +1693,15 @@ end subroutine output_qdp_var_dynamics ! column integrate mass-variable and outfld ! subroutine util_function(f_in,nx,nz,name_out,ie) - use physconst, only: gravit + use physconst, only: rga use cam_history, only: outfld, hist_fld_active integer, intent(in) :: nx,nz,ie real(kind=r8), intent(in) :: f_in(nx,nx,nz) character(len=16), intent(in) :: name_out real(kind=r8) :: f_out(nx*nx) integer :: i,j,k - real(kind=r8) :: inv_g if (hist_fld_active(name_out)) then f_out = 0.0_r8 - inv_g = 1.0_r8/gravit do k = 1, nz do j = 1, nx do i = 1, nx @@ -1692,7 +1709,7 @@ subroutine util_function(f_in,nx,nz,name_out,ie) end do end do end do - f_out = f_out*inv_g + f_out = f_out*rga call outfld(name_out,f_out,nx*nx,ie) end if end subroutine util_function @@ -1708,7 +1725,6 @@ subroutine compute_omega(hybrid,n0,qn0,elem,deriv,nets,nete,dt,hvcoord) use bndry_mod, only: bndry_exchange use viscosity_mod, only: biharmonic_wk_omega use cam_thermo, only: get_dp, MASS_MIXING_RATIO - use air_composition,only: thermodynamic_active_species_num use air_composition,only: thermodynamic_active_species_idx_dycore implicit none type (hybrid_t) , intent(in) :: hybrid @@ -1723,7 +1739,7 @@ subroutine compute_omega(hybrid,n0,qn0,elem,deriv,nets,nete,dt,hvcoord) real (kind=r8) :: dp_full(np,np,nlev) real (kind=r8) :: p_full(np,np,nlev),grad_p_full(np,np,2),vgrad_p_full(np,np,nlev) real (kind=r8) :: divdp_full(np,np,nlev),vdp_full(np,np,2) - real(kind=r8) :: Otens(np,np ,nlev,nets:nete), dt_hyper, sum_water(np,np,nlev) + real(kind=r8) :: Otens(np,np ,nlev,nets:nete), dt_hyper logical, parameter :: del4omega = .true. diff --git a/src/dynamics/se/dycore/prim_advection_mod.F90 b/src/dynamics/se/dycore/prim_advection_mod.F90 index 0391762cb5..7c54abc2cd 100644 --- a/src/dynamics/se/dycore/prim_advection_mod.F90 +++ b/src/dynamics/se/dycore/prim_advection_mod.F90 @@ -949,7 +949,7 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) use hybrid_mod, only: hybrid_t, config_thread_region,get_loop_ranges, PrintHybrid use fvm_control_volume_mod, only: fvm_struct use dimensions_mod, only: ntrac - use dimensions_mod, only: lcp_moist, kord_tr,kord_tr_cslam + use dimensions_mod, only: kord_tr,kord_tr_cslam use cam_logfile, only: iulog use physconst, only: pi use air_composition, only: thermodynamic_active_species_idx_dycore @@ -965,7 +965,7 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) type (hvcoord_t) :: hvcoord integer :: ie,i,j,k,np1,nets,nete,np1_qdp,q, m_cnst real (kind=r8), dimension(np,np,nlev) :: dp_moist,dp_star_moist, dp_dry,dp_star_dry - real (kind=r8), dimension(np,np,nlev) :: internal_energy_star + real (kind=r8), dimension(np,np,nlev) :: enthalpy_star real (kind=r8), dimension(np,np,nlev,2):: ttmp real(r8), parameter :: rad2deg = 180.0_r8/pi integer :: region_num_threads,qbeg,qend,kord_uvT(1) @@ -980,22 +980,20 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) ! prepare for mapping of temperature ! if (vert_remap_uvTq_alg>-20) then - if (lcp_moist) then - ! - ! compute internal energy on Lagrangian levels - ! (do it here since qdp is overwritten by remap1) - ! - call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & - elem(ie)%state%t(:,:,:,np1), elem(ie)%state%dp3d(:,:,:,np1), internal_energy_star, & - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - end if + ! + ! compute enthalpy on Lagrangian levels + ! (do it here since qdp is overwritten by remap1) + ! + call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & + elem(ie)%state%t(:,:,:,np1), elem(ie)%state%dp3d(:,:,:,np1), enthalpy_star, & + active_species_idx_dycore=thermodynamic_active_species_idx_dycore) else ! ! map Tv over log(p) following FV and FV3 ! - call get_virtual_temp(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), internal_energy_star, & + call get_virtual_temp(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), enthalpy_star, & dp_dry=elem(ie)%state%dp3d(:,:,:,np1), active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - internal_energy_star = internal_energy_star*elem(ie)%state%t(:,:,:,np1) + enthalpy_star = enthalpy_star*elem(ie)%state%t(:,:,:,np1) end if ! ! update final psdry @@ -1048,34 +1046,28 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) ! if (vert_remap_uvTq_alg>-20) then ! - ! remap internal energy and back out temperature + ! remap enthalpy energy and back out temperature ! - if (lcp_moist) then - call remap1(internal_energy_star,np,1,1,1,dp_star_dry,dp_dry,ptop,1,.true.,kord_uvT) - ! - ! compute sum c^(l)_p*m^(l)*dp on arrival (Eulerian) grid - ! - ttmp(:,:,:,1) = 1.0_r8 - call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & - ttmp(:,:,:,1), dp_dry,ttmp(:,:,:,2), & - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - elem(ie)%state%t(:,:,:,np1)=internal_energy_star/ttmp(:,:,:,2) - else - internal_energy_star(:,:,:)=elem(ie)%state%t(:,:,:,np1)*dp_star_moist - call remap1(internal_energy_star,np,1,1,1,dp_star_moist,dp_moist,ptop,1,.true.,kord_uvT) - elem(ie)%state%t(:,:,:,np1)=internal_energy_star/dp_moist - end if + call remap1(enthalpy_star,np,1,1,1,dp_star_dry,dp_dry,ptop,1,.true.,kord_uvT) + ! + ! compute sum c^(l)_p*m^(l)*dp on arrival (Eulerian) grid + ! + ttmp(:,:,:,1) = 1.0_r8 + call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & + ttmp(:,:,:,1), dp_dry,ttmp(:,:,:,2), & + active_species_idx_dycore=thermodynamic_active_species_idx_dycore) + elem(ie)%state%t(:,:,:,np1)=enthalpy_star/ttmp(:,:,:,2) else ! ! map Tv over log(p); following FV and FV3 ! - call remap1(internal_energy_star,np,1,1,1,dp_star_moist,dp_moist,ptop,1,.false.,kord_uvT) + call remap1(enthalpy_star,np,1,1,1,dp_star_moist,dp_moist,ptop,1,.false.,kord_uvT) call get_virtual_temp(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), ttmp(:,:,:,1), & dp_dry=dp_dry, active_species_idx_dycore=thermodynamic_active_species_idx_dycore) ! ! convert new Tv to T ! - elem(ie)%state%t(:,:,:,np1)=internal_energy_star/ttmp(:,:,:,1) + elem(ie)%state%t(:,:,:,np1)=enthalpy_star/ttmp(:,:,:,1) end if ! ! remap velocity components diff --git a/src/dynamics/se/dycore/prim_driver_mod.F90 b/src/dynamics/se/dycore/prim_driver_mod.F90 index 5ea869b53c..af22869f24 100644 --- a/src/dynamics/se/dycore/prim_driver_mod.F90 +++ b/src/dynamics/se/dycore/prim_driver_mod.F90 @@ -26,7 +26,7 @@ module prim_driver_mod subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) use dimensions_mod, only: irecons_tracer, fvm_supercycling - use dimensions_mod, only: fv_nphys, ntrac, nc + use dimensions_mod, only: fv_nphys, nc use parallel_mod, only: syncmp use time_mod, only: timelevel_t, tstep, phys_tscale, nsplit, TimeLevel_Qdp use time_mod, only: nsplit_baseline,rsplit_baseline @@ -40,7 +40,7 @@ subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) use hybvcoord_mod, only: hvcoord_t use prim_advection_mod, only: prim_advec_init2,deriv use prim_advance_mod, only: compute_omega - use physconst, only: gravit, cappa, cpair, tref, lapse_rate + use physconst, only: rga, cappa, cpair, tref, lapse_rate use cam_thermo, only: get_dp_ref use physconst, only: pstd @@ -157,7 +157,7 @@ subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) ! T1 = .0065*Tref*Cp/g ! = ~191 ! T0 = Tref-T1 ! = ~97 ! - T1 = lapse_rate*Tref*cpair/gravit + T1 = lapse_rate*Tref*cpair*rga T0 = Tref-T1 do ie=nets,nete do k=1,nlev @@ -221,13 +221,13 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst use time_mod, only: TimeLevel_t, timelevel_update, timelevel_qdp, nsplit use control_mod, only: statefreq,qsplit, rsplit, variable_nsplit use prim_advance_mod, only: applycamforcing - use prim_advance_mod, only: calc_tot_energy_dynamics,compute_omega + use prim_advance_mod, only: tot_energy_dyn,compute_omega use prim_state_mod, only: prim_printstate, adjust_nsplit use prim_advection_mod, only: vertical_remap, deriv use thread_mod, only: omp_get_thread_num use perf_mod , only: t_startf, t_stopf use fvm_mod , only: fill_halo_fvm, ghostBufQnhc_h - use dimensions_mod, only: ntrac,fv_nphys, ksponge_end + use dimensions_mod, only: use_cslam,fv_nphys, ksponge_end type (element_t) , intent(inout) :: elem(:) type(fvm_struct), intent(inout) :: fvm(:) @@ -282,9 +282,9 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst call TimeLevel_Qdp( tl, qsplit, n0_qdp) - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%n0,n0_qdp,'dAF') + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dAF') call ApplyCAMForcing(elem,fvm,tl%n0,n0_qdp,dt_remap,dt_phys,nets,nete,nsubstep) - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%n0,n0_qdp,'dBD') + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dBD') do r=1,rsplit if (r.ne.1) call TimeLevel_update(tl,"leapfrog") call prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,r) @@ -300,7 +300,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst ! always for tracers !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAD') + call tot_energy_dyn(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAD') if (variable_nsplit.or.compute_diagnostics) then ! @@ -317,7 +317,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! time step is complete. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAR') + call tot_energy_dyn(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAR') if (nsubstep==nsplit) then call compute_omega(hybrid,tl%np1,np1_qdp,elem,deriv,nets,nete,dt_remap,hvcoord) @@ -378,7 +378,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst call prim_printstate(elem, tl, hybrid,nets,nete, fvm, omega_cn) end if - if (ntrac>0.and.nsubstep==nsplit.and.nc.ne.fv_nphys) then + if (use_cslam.and.nsubstep==nsplit.and.nc.ne.fv_nphys) then ! ! fill the fvm halo for mapping in d_p_coupling if ! physics grid resolution is different than fvm resolution @@ -414,7 +414,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) use prim_advection_mod, only: prim_advec_tracers_remap, prim_advec_tracers_fvm, deriv use derivative_mod, only: subcell_integration use hybrid_mod, only: set_region_num_threads, config_thread_region, get_loop_ranges - use dimensions_mod, only: ntrac,fvm_supercycling,fvm_supercycling_jet + use dimensions_mod, only: use_cslam,fvm_supercycling,fvm_supercycling_jet use dimensions_mod, only: kmin_jet, kmax_jet use fvm_mod, only: ghostBufQnhc_vh,ghostBufQ1_vh, ghostBufFlux_vh use fvm_mod, only: ghostBufQ1_h,ghostBufQnhcJet_h, ghostBufFluxJet_h @@ -493,7 +493,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) ! defer final timelevel update until after Q update. enddo #ifdef HOMME_TEST_SUB_ELEMENT_MASS_FLUX - if (ntrac>0.and.rstep==1) then + if (use_cslam.and.rstep==1) then do ie=nets,nete do k=1,nlev tempdp3d = elem(ie)%state%dp3d(:,:,k,tl%np1) - & @@ -540,7 +540,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) if (qsize > 0) then call t_startf('prim_advec_tracers_remap') - if(ntrac>0) then + if(use_cslam) then ! Deactivate threading in the tracer dimension if this is a CSLAM run region_num_threads = 1 else @@ -548,7 +548,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) endif call omp_set_nested(.true.) !$OMP PARALLEL NUM_THREADS(region_num_threads), DEFAULT(SHARED), PRIVATE(hybridnew) - if(ntrac>0) then + if(use_cslam) then ! Deactivate threading in the tracer dimension if this is a CSLAM run hybridnew = config_thread_region(hybrid,'serial') else @@ -562,7 +562,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) ! ! only run fvm transport every fvm_supercycling rstep ! - if (ntrac>0) then + if (use_cslam) then ! ! FVM transport ! diff --git a/src/dynamics/se/dycore/prim_state_mod.F90 b/src/dynamics/se/dycore/prim_state_mod.F90 index f01ffbd049..2f4bcbb2db 100644 --- a/src/dynamics/se/dycore/prim_state_mod.F90 +++ b/src/dynamics/se/dycore/prim_state_mod.F90 @@ -19,7 +19,7 @@ module prim_state_mod CONTAINS subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) - use dimensions_mod, only: ntrac + use dimensions_mod, only: use_cslam use constituents, only: cnst_name use air_composition, only: thermodynamic_active_species_idx_dycore, dry_air_species_num use air_composition, only: thermodynamic_active_species_num,thermodynamic_active_species_idx @@ -60,7 +60,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) n0=tl%n0 call TimeLevel_Qdp( tl, qsplit, n0_qdp) ! moist surface pressure - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete moist_ps_fvm(:,:,ie)=SUM(fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3) do q=dry_air_species_num+1,thermodynamic_active_species_num @@ -86,7 +86,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) do ie=nets,nete da_gll(:,:,ie) = elem(ie)%mp(:,:)*elem(ie)%metdet(:,:) enddo - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete da_fvm(:,:,ie) = fvm(ie)%area_sphere(:,:) enddo @@ -103,7 +103,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) varname(3) = 'T ' varname(4) = 'OMEGA ' varname(5) = 'OMEGA CN ' - if (ntrac>0) then + if (use_cslam) then varname(6) = 'PSDRY(fvm)' varname(7) = 'PS(fvm) ' varname(8) = 'PSDRY(gll)' @@ -133,7 +133,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) min_local(ie,5) = 0.0_r8 max_local(ie,5) = 0.0_r8 end if - if (ntrac>0) then + if (use_cslam) then min_local(ie,6) = MINVAL(SUM(fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3)) max_local(ie,6) = MAXVAL(SUM(fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3)) min_local(ie,7) = MINVAL(moist_ps_fvm(:,:,ie)) @@ -168,7 +168,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) max_local(ie,nm2+1) = MAXVAL(elem(ie)%derived%FT(:,:,:)) min_local(ie,nm2+2) = MINVAL(elem(ie)%derived%FM(:,:,:,:)) max_local(ie,nm2+2) = MAXVAL(elem(ie)%derived%FM(:,:,:,:)) - if (ntrac>0) then + if (use_cslam) then do q=1,statediag_numtrac varname(nm2+2+q) = TRIM('F'//TRIM(cnst_name(q))) min_local(ie,nm2+2+q) = MINVAL(fvm(ie)%fc(1:nc,1:nc,:,q)) @@ -201,7 +201,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) ! tracers ! mass = -1.0_r8 - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete do q=1,statediag_numtrac tmp_fvm(:,:,q,ie) = SUM(fvm(ie)%c(1:nc,1:nc,:,q)*fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3) @@ -243,7 +243,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) if (tl%nstep==0.or..not. initial_run) then mass_chg(:) = 0.0_R8 elem(nets)%derived%mass(nm+1:nm+statediag_numtrac) = mass(nm+1:nm+statediag_numtrac) - if (ntrac>0) then + if (use_cslam) then elem(nets)%derived%mass(6:9) = mass(6:9) else elem(nets)%derived%mass(6:7) = mass(6:7) diff --git a/src/dynamics/se/dycore/viscosity_mod.F90 b/src/dynamics/se/dycore/viscosity_mod.F90 index 1240d4a15f..04b0a1a91d 100644 --- a/src/dynamics/se/dycore/viscosity_mod.F90 +++ b/src/dynamics/se/dycore/viscosity_mod.F90 @@ -52,7 +52,7 @@ module viscosity_mod subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid,nt,nets,nete,kbeg,kend,hvcoord) use derivative_mod, only : subcell_Laplace_fluxes - use dimensions_mod, only : ntrac, nu_div_lev,nu_lev + use dimensions_mod, only : use_cslam, nu_div_lev,nu_lev use hybvcoord_mod, only : hvcoord_t !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! compute weak biharmonic operator @@ -86,7 +86,7 @@ subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid, kblk = kend - kbeg + 1 - if (ntrac>0) dpflux = 0 + if (use_cslam) dpflux = 0 !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) !so tensor is only used on second call to laplace_sphere_wk var_coef1 = .true. @@ -150,7 +150,7 @@ subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid, kptr = kbeg - 1 + 3*nlev call edgeVunpack(edge3,dptens(:,:,kbeg:kend,ie),kblk,kptr,ie) - if (ntrac>0) then + if (use_cslam) then do k=1,nlev !CLEAN tmp(:,:)= rspheremv(:,:)*dptens(:,:,k,ie) tmp(:,:)= elem(ie)%rspheremp(:,:)*dptens(:,:,k,ie) diff --git a/src/dynamics/se/dycore_budget.F90 b/src/dynamics/se/dycore_budget.F90 new file mode 100644 index 0000000000..d2bfe0fceb --- /dev/null +++ b/src/dynamics/se/dycore_budget.F90 @@ -0,0 +1,528 @@ +module dycore_budget +use shr_kind_mod, only: r8=>shr_kind_r8 +implicit none + +public :: print_budget +real(r8), parameter :: eps = 1.0E-7_r8 +real(r8), parameter :: eps_mass = 1.0E-12_r8 + +real(r8), save :: previous_dEdt_adiabatic_dycore = 0.0_r8 +real(r8), save :: previous_dEdt_dry_mass_adjust = 0.0_r8 +real(r8), save :: previous_dEdt_phys_dyn_coupl_err = 0.0_r8 +!========================================================================================= +contains +!========================================================================================= + +subroutine print_budget(hstwr) + + use spmd_utils, only: masterproc + use cam_abortutils, only: endrun + use cam_logfile, only: iulog + use cam_budget, only: cam_budget_get_global, is_cam_budget, thermo_budget_histfile_num, thermo_budget_history + use cam_thermo, only: thermo_budget_vars_descriptor, thermo_budget_num_vars, thermo_budget_vars_massv, & + teidx, seidx, keidx, poidx + use dimensions_mod, only: use_cslam + use control_mod, only: ftype + + ! arguments + logical, intent(in) :: hstwr(:) + + ! Local variables + character(len=*), parameter :: subname = 'dycore_budget:print_budgets:' + ! + ! physics energy tendencies + ! + integer :: idx(4) + real(r8) :: dEdt_param_physE(4) ! dE/dt CAM physics using physics E formula (phAP-phBP) + real(r8) :: dEdt_param_dynE(4) ! dE/dt CAM physics using dycore E (dyAP-dyBP) + + real(r8) :: dEdt_efix_physE(4) ! dE/dt energy fixer using physics E formula (phBP-phBF) + real(r8) :: dEdt_efix_dynE(4) ! dE/dt energy fixer using dycore E formula (dyBP-dyBF) + + real(r8) :: dEdt_dme_adjust_physE(4) ! dE/dt dry mass adjustment using physics E formula (phAM-phAP) + real(r8) :: dEdt_dme_adjust_dynE(4) ! dE/dt dry mass adjustment using dycore E (dyAM-dyAP) + + real(r8) :: dEdt_param_efix_physE(4) ! dE/dt CAM physics + energy fixer using physics E formula (phAP-phBF) + real(r8) :: dEdt_param_efix_dynE(4) ! dE/dt CAM physics + energy fixer using dycore E formula (dyAP-dyBF) + + real(r8) :: dEdt_phys_total_dynE(4) ! dE/dt physics total using dycore E (dyAM-dyBF) + ! physics total = parameterizations + efix + dry-mass adjustment + ! + ! SE dycore specific energy tendencies + ! + real(r8) :: dEdt_phys_total_in_dyn(4) ! dEdt of physics total in dynamical core + ! physics total = parameterizations + efix + dry-mass adjustment + real(r8) :: dEdt_dycore_phys ! dEdt dycore (estimated in physics) + ! + ! mass budgets physics + ! + real(r8) :: dMdt_efix ! mass tendency energy fixer + real(r8) :: dMdt_parameterizations ! mass tendency physics paramterizations + real(r8) :: dMdt_dme_adjust ! mass tendency dry-mass adjustment + real(r8) :: dMdt_phys_total ! mass tendency physics total (energy fixer + parameterizations + dry-mass adjustment) + ! + ! mass budgets dynamics + ! + real(r8) :: dMdt_floating_dyn ! mass tendency floating dynamics (dAD-dBD) + real(r8) :: dMdt_vert_remap ! mass tendency vertical remapping (dAR-dAD) + real(r8) :: dMdt_del4_fric_heat ! mass tendency del4 frictional heating (dAH-dCH) + real(r8) :: dMdt_del4_tot ! mass tendency del4 + del4 frictional heating (dAH-dBH) + real(r8) :: dMdt_residual ! mass tendency residual (time truncation errors) + real(r8) :: dMdt_phys_total_in_dyn ! mass tendency physics total in dycore + real(r8) :: dMdt_PDC ! mass tendency physics-dynamics coupling + ! + ! energy budgets dynamics + ! + real(r8) :: dEdt_floating_dyn ! dE/dt floating dynamics (dAD-dBD) + real(r8) :: dEdt_vert_remap ! dE/dt vertical remapping (dAR-dAD) + real(r8) :: dEdt_del4 ! dE/dt del4 (dCH-dBH) + real(r8) :: dEdt_del4_fric_heat ! dE/dt del4 frictional heating (dAH-dCH) + real(r8) :: dEdt_del4_tot ! dE/dt del4 + del4 fricitional heating (dAH-dBH) + real(r8) :: dEdt_del2_sponge ! dE/dt del2 sponge (dAS-dBS) + real(r8) :: dEdt_del2_del4_tot ! dE/dt explicit diffusion total + real(r8) :: dEdt_residual ! dE/dt residual (dEdt_floating_dyn-dEdt_del2_del4_tot) + real(r8) :: dEdt_dycore_dyn ! dE/dt adiabatic dynamical core (calculated in dycore) + ! + ! physics-dynamics coupling variables + ! + real(r8) :: E_dBF(4) ! E of dynamics state at the end of dycore integration (on dycore deomposition) + real(r8) :: E_dyBF(4) ! E of physics state using dycore E + + + real(r8) :: diff, tmp ! dummy variables + integer :: m_cnst, i + character(LEN=*), parameter :: fmt = "(a40,a15,a1,F6.2,a1,F6.2,a1,E10.2,a5)" + character(LEN=*), parameter :: fmtf = "(a48,F8.4,a6)" + character(LEN=*), parameter :: fmtm = "(a48,E8.2,a9)" + character(LEN=15) :: str(4) + character(LEN=5) :: pf ! pass or fail identifier + !-------------------------------------------------------------------------------------- + + if (masterproc .and. thermo_budget_history .and. hstwr(thermo_budget_histfile_num)) then + idx(1) = teidx !total energy index + idx(2) = seidx !enthaly index + idx(3) = keidx !kinetic energy index + idx(4) = poidx !surface potential energy index + str(1) = "(total )" + str(2) = "(enthalpy )" + str(3) = "(kinetic )" + str(4) = "(srf potential)" + do i=1,4 + ! + ! CAM physics energy tendencies + ! + call cam_budget_get_global('phAP-phBP',idx(i),dEdt_param_physE(i)) + call cam_budget_get_global('phBP-phBF',idx(i),dEdt_efix_physE(i)) + call cam_budget_get_global('phAM-phAP',idx(i),dEdt_dme_adjust_physE(i)) + call cam_budget_get_global('phAP-phBF',idx(i),dEdt_param_efix_physE(i)) + ! + ! CAM physics energy tendencies using dycore energy formula scaling + ! temperature tendencies for consistency with CAM physics + ! + call cam_budget_get_global('dyAP-dyBP',idx(i),dEdt_param_dynE(i)) + call cam_budget_get_global('dyBP-dyBF',idx(i),dEdt_efix_dynE(i)) + call cam_budget_get_global('dyAM-dyAP',idx(i),dEdt_dme_adjust_dynE(i)) + call cam_budget_get_global('dyAP-dyBF',idx(i),dEdt_param_efix_dynE(i)) + call cam_budget_get_global('dyAM-dyBF',idx(i),dEdt_phys_total_dynE(i)) + call cam_budget_get_global('dyBF' ,idx(i),E_dyBF(i))!state beginning physics + ! + ! CAM physics energy tendencies in dynamical core + ! + call cam_budget_get_global('dBD-dAF',idx(i),dEdt_phys_total_in_dyn(i)) + call cam_budget_get_global('dBF' ,idx(i),E_dBF(i)) !state passed to physics + end do + + call cam_budget_get_global('dAD-dBD',teidx,dEdt_floating_dyn) + call cam_budget_get_global('dAR-dAD',teidx,dEdt_vert_remap) + dEdt_dycore_dyn = dEdt_floating_dyn+dEdt_vert_remap + + call cam_budget_get_global('dCH-dBH',teidx,dEdt_del4) + call cam_budget_get_global('dAH-dCH',teidx,dEdt_del4_fric_heat) + call cam_budget_get_global('dAH-dBH',teidx,dEdt_del4_tot) + call cam_budget_get_global('dAS-dBS',teidx,dEdt_del2_sponge) + dEdt_del2_del4_tot = dEdt_del4_tot+dEdt_del2_sponge + dEdt_residual = dEdt_floating_dyn-dEdt_del2_del4_tot + + write(iulog,*)" " + write(iulog,*)"======================================================================" + write(iulog,*)"Total energy diagnostics introduced in Lauritzen and Williamson (2019)" + write(iulog,*)"(DOI:10.1029/2018MS001549)" + write(iulog,*)"======================================================================" + write(iulog,*)" " + write(iulog,*)"Globally and vertically integrated total energy (E) diagnostics are" + write(iulog,*)"computed at various points in the physics and dynamics loops to compute" + write(iulog,*)"energy tendencies (dE/dt) and check for consistency (e.g., is E of" + write(iulog,*)"state passed to physics computed using dycore state variables the same" + write(iulog,*)"E of the state in the beginning of physics computed using the physics" + write(iulog,*)"representation of the state)" + write(iulog,*)" " + write(iulog,*)"Energy stages in physics:" + write(iulog,*)"-------------------------" + write(iulog,*)" " + write(iulog,*)" xxBF: state passed to parameterizations, before energy fixer" + write(iulog,*)" xxBP: after energy fixer, before parameterizations" + write(iulog,*)" xxAP: after last phys_update in parameterizations and state " + write(iulog,*)" saved for energy fixer" + write(iulog,*)" xxAM: after dry mass adjustment" + write(iulog,*)" history files saved off here" + write(iulog,*)" " + write(iulog,*)"where xx='ph','dy' " + write(iulog,*)" " + write(iulog,*)"Suffix ph is CAM physics total energy" + write(iulog,*)"(eq. 111 in Lauritzen et al. 2022; 10.1029/2022MS003117)" + write(iulog,*)" " + write(iulog,*)"Suffix dy is dycore energy computed in CAM physics using" + write(iulog,*)"CAM physics state variables" + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"Energy stages in dynamics (specific to the SE dycore)" + write(iulog,*)"-----------------------------------------------------" + write(iulog,*)" " + write(iulog,*)"suffix (d)" + write(iulog,*)"dED: state from end of previous dynamics (= pBF + time sampling)" + write(iulog,*)" loop over vertical remapping and physics dribbling -------- (nsplit) -------" + write(iulog,*)" (dribbling and remapping always done together) |" + write(iulog,*)" dAF: state from previous remapping |" + write(iulog,*)" dBD: state after physics dribble, before dynamics |" + write(iulog,*)" loop over vertical Lagrangian dynamics --------rsplit------------- |" + write(iulog,*)" dynamics here | |" + write(iulog,*)" loop over hyperviscosity ----------hypervis_sub------------ | |" + write(iulog,*)" dBH state before hyperviscosity | | |" + write(iulog,*)" dCH state after hyperviscosity | | |" + write(iulog,*)" dAH state after hyperviscosity momentum heating | | |" + write(iulog,*)" end hyperviscosity loop ----------------------------------- | |" + write(iulog,*)" dBS state before del2 sponge | | |" + write(iulog,*)" dAS state after del2+mom heating sponge | | |" + write(iulog,*)" end of vertical Lagrangian dynamics loop ------------------------- |" + write(iulog,*)" dAD state after dynamics, before vertical remapping |" + write(iulog,*)" dAR state after vertical remapping |" + write(iulog,*)" end of remapping loop ------------------------------------------------------" + write(iulog,*)"dBF state passed to parameterizations = state after last remapping " + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"FYI: all difference (diff) below are absolute normalized differences" + write(iulog,*)" " + write(iulog,*)"Consistency check 0:" + write(iulog,*)"--------------------" + write(iulog,*)" " + write(iulog,*)"For energetic consistency we require that dE/dt [W/m^2] from energy " + write(iulog,*)"fixer and all parameterizations computed using physics E and" + write(iulog,*)"dycore in physics E are the same! Checking:" + write(iulog,*)" " + write(iulog,*) " xx=ph xx=dy norm. diff." + write(iulog,*) " ----- ----- -----------" + do i=1,4 + diff = abs_diff(dEdt_efix_physE(i),dEdt_efix_dynE(i),pf=pf) + write(iulog,fmt)"dE/dt energy fixer (xxBP-xxBF) ",str(i)," ",dEdt_efix_physE(i), " ", & + dEdt_efix_dynE(i)," ",diff,pf + diff = abs_diff(dEdt_param_physE(i),dEdt_param_dynE(i),pf=pf) + write(iulog,fmt)"dE/dt all parameterizations (xxAP-xxBP) ",str(i)," ",dEdt_param_physE(i)," ", & + dEdt_param_dynE(i)," ",diff,pf + write(iulog,*) " " + if (diff>eps) then + write(iulog,*)"FAIL" + call endrun(subname//"dE/dt's in physics inconsistent") + end if + end do + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"dE/dt from dry-mass adjustment will differ if dynamics and physics use" + write(iulog,*)"different energy definitions! Checking:" + write(iulog,*)" " + write(iulog,*) " xx=ph xx=dy diff" + write(iulog,*) " ----- ----- ----" + do i=1,4 + diff = dEdt_dme_adjust_physE(i)-dEdt_dme_adjust_dynE(i) + write(iulog,fmt)"dE/dt dry mass adjustment (xxAM-xxAP) ",str(i)," ",dEdt_dme_adjust_physE(i)," ", & + dEdt_dme_adjust_dynE(i)," ",diff + end do + write(iulog,*)" " + write(iulog,*)" " + ! + ! these diagnostics only make sense time-step to time-step + ! + write(iulog,*)" " + write(iulog,*)"Some energy budget observations:" + write(iulog,*)"--------------------------------" + write(iulog,*)" " + write(iulog,*)"Note that total energy fixer fixes:" + write(iulog,*) " " + write(iulog,*) "-dE/dt energy fixer(t=n) = dE/dt dry mass adjustment (t=n-1) +" + write(iulog,*) " dE/dt adiabatic dycore (t=n-1) +" + write(iulog,*) " dE/dt physics-dynamics coupling errors (t=n-1)" + write(iulog,*) " " + write(iulog,*) "(equation 23 in Lauritzen and Williamson (2019))" + write(iulog,*) " " + + tmp = previous_dEdt_phys_dyn_coupl_err+previous_dEdt_adiabatic_dycore+previous_dEdt_dry_mass_adjust + diff = abs_diff(-dEdt_efix_dynE(1),tmp,pf) + if (.not.use_cslam) then + write(iulog,*) "Check if that is the case:", pf, diff + write(iulog,*) " " + if (abs(diff)>eps) then + write(iulog,*) "dE/dt energy fixer(t=n) = ",dEdt_efix_dynE(1) + write(iulog,*) "dE/dt dry mass adjustment (t=n-1) = ",previous_dEdt_dry_mass_adjust + write(iulog,*) "dE/dt adiabatic dycore (t=n-1) = ",previous_dEdt_adiabatic_dycore + write(iulog,*) "dE/dt physics-dynamics coupling errors (t=n-1) = ",previous_dEdt_phys_dyn_coupl_err + end if + else + previous_dEdt_phys_dyn_coupl_err = dEdt_efix_dynE(1)+previous_dEdt_dry_mass_adjust+previous_dEdt_adiabatic_dycore + write(iulog,*) "dE/dt energy fixer(t=n) = ",dEdt_efix_dynE(1) + write(iulog,*) "dE/dt dry mass adjustment (t=n-1) = ",previous_dEdt_dry_mass_adjust + write(iulog,*) "dE/dt adiabatic dycore (t=n-1) = ",previous_dEdt_adiabatic_dycore + write(iulog,*) "dE/dt physics-dynamics coupling errors (t=n-1) = ",previous_dEdt_phys_dyn_coupl_err + write(iulog,*) " " + write(iulog,*) "Note: when running CSLAM the physics-dynamics coupling error is diagnosed" + write(iulog,*) " (using equation above) rather than explicitly computed" + write(iulog,*) " " + write(iulog,*) " " + write(iulog,*) "Physics-dynamics coupling errors include: " + write(iulog,*) " " + write(iulog,*) " -dE/dt adiabatic dycore is computed on GLL grid;" + write(iulog,*) " error in mapping to physics grid" + write(iulog,*) " -dE/dt physics tendencies mapped to GLL grid" + write(iulog,*) " (tracer tendencies mapped non-conservatively!)" + write(iulog,*) " -dE/dt dynamics state mapped to GLL grid" + end if + write(iulog,*) "" + if (.not.use_cslam) then + dEdt_dycore_phys = -dEdt_efix_dynE(1)-previous_dEdt_phys_dyn_coupl_err-previous_dEdt_dry_mass_adjust + write(iulog,*) "Hence the dycore E dissipation estimated from energy fixer " + write(iulog,'(A39,F6.2,A6)') "based on previous time-step values is ",dEdt_dycore_phys," W/M^2" + write(iulog,*) " " + end if + write(iulog,*) " " + write(iulog,*) "-------------------------------------------------------------------" + write(iulog,*) " Consistency check 1: state passed to physics same as end dynamics?" + write(iulog,*) "-------------------------------------------------------------------" + write(iulog,*) " " + write(iulog,*) "Is globally integrated total energy of state at the end of dynamics (dBF)" + write(iulog,*) "and beginning of physics (using dynamics in physics energy; dyBF) the same?" + write(iulog,*) "" + if (.not.use_cslam) then + if (abs(E_dyBF(1))>eps) then + diff = abs_diff(E_dBF(1),E_dyBF(1)) + if (abs(diff)eps) then + ! + ! if errors print details + ! + if (ftype==1) then + write(iulog,*) "" + write(iulog,*) " You are using ftype==1 so physics-dynamics coupling errors should be round-off!" + write(iulog,*) "" + write(iulog,*) " Because of failure provide detailed diagnostics below:" + write(iulog,*) "" + else + write(iulog,*) "" + write(iulog,*) " Since ftype<>1 there are physics dynamics coupling errors" + write(iulog,*) "" + write(iulog,*) " Break-down below:" + write(iulog,*) "" + end if + + do i=1,4 + write(iulog,*) str(i),":" + write(iulog,*) "======" + diff = abs_diff(dEdt_phys_total_dynE(i),dEdt_phys_total_in_dyn(i),pf=pf) + write(iulog,*) "dE/dt physics-dynamics coupling errors (diff) ",diff + write(iulog,*) "dE/dt physics total in dynamics (dBD-dAF) ",dEdt_phys_total_in_dyn(i) + write(iulog,*) "dE/dt physics total in physics (dyAM-dyBF) ",dEdt_phys_total_dynE(i) + write(iulog,*) " " + write(iulog,*) " physics total = parameterizations + efix + dry-mass adjustment" + write(iulog,*) " " + end do +! Temporarily disable endrun until energy bias for consistancy check 2 is better understood. +! if (ftype==1) then +! call endrun(subname//"Physics-dynamics coupling error. See atm.log") +! end if + end if + else + write(iulog,'(a47,F6.2,a6)')" dE/dt physics tendency in dynamics (dBD-dAF) ",dEdt_phys_total_in_dyn(1)," W/M^2" + write(iulog,'(a47,F6.2,a6)')" dE/dt physics tendency in physics (dyAM-dyBF) ",dEdt_phys_total_dynE(1)," W/M^2" + write(iulog,*)" " + write(iulog,*) " When runnig with a physics grid this consistency check does not make sense" + write(iulog,*) " since it is computed on the GLL grid whereas we enforce energy conservation" + write(iulog,*) " on the physics grid. To assess the errors of running dynamics on GLL" + write(iulog,*) " grid, tracers on CSLAM grid and physics on physics grid we use the energy" + write(iulog,*) " fixer check from above:" + write(iulog,*) " " + write(iulog,*) " dE/dt physics-dynamics coupling errors (t=n-1) =",previous_dEdt_phys_dyn_coupl_err + write(iulog,*) "" + end if + write(iulog,*)" " + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)" SE dycore energy tendencies" + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)" " + write(iulog,fmtf)" dE/dt dycore ",dEdt_dycore_dyn," W/M^2" + write(iulog,*)" " + write(iulog,*)"Adiabatic dynamics can be divided into quasi-horizontal and vertical remapping: " + write(iulog,*)" " + write(iulog,fmtf)" dE/dt floating dynamics (dAD-dBD) ",dEdt_floating_dyn," W/M^2" + write(iulog,fmtf)" dE/dt vertical remapping (dAR-dAD) ",dEdt_vert_remap," W/M^2" + + write(iulog,*) " " + write(iulog,*) "Breakdown of floating dynamics:" + write(iulog,*) " " + write(iulog,fmtf)" dE/dt hypervis del4 (dCH-dBH) ",dEdt_del4, " W/M^2" + write(iulog,fmtf)" dE/dt hypervis frictional heating (dAH-dCH) ",dEdt_del4_fric_heat," W/M^2" + write(iulog,fmtf)" dE/dt hypervis del4 total (dAH-dBH) ",dEdt_del4_tot, " W/M^2" + write(iulog,fmtf)" dE/dt hypervis sponge del2 (dAS-dBS) ",dEdt_del2_sponge, " W/M^2" + write(iulog,fmtf)" dE/dt explicit diffusion total ",dEdt_del2_del4_tot, " W/M^2" + write(iulog,*) " " + write(iulog,fmtf)" dE/dt residual (time-truncation errors,...) ",dEdt_residual, " W/M^2" + write(iulog,*)" " + write(iulog,*)" " + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)"Tracer mass budgets" + write(iulog,*)"------------------------------------------------------------" + write(iulog,*)" " + write(iulog,*)"Below the physics-dynamics coupling error is computed as " + write(iulog,*)"dMASS/dt physics tendency in dycore (dBD-dAF) minus" + write(iulog,*)"dMASS/dt total physics (pAM-pBF)" + write(iulog,*)" " + write(iulog,*)" " + do m_cnst=1,thermo_budget_num_vars + if (thermo_budget_vars_massv(m_cnst)) then + write(iulog,*)thermo_budget_vars_descriptor(m_cnst) + write(iulog,*)"------------------------------" + call cam_budget_get_global('phBP-phBF',m_cnst,dMdt_efix) + call cam_budget_get_global('phAM-phAP',m_cnst,dMdt_dme_adjust) + call cam_budget_get_global('phAP-phBP',m_cnst,dMdt_parameterizations) + call cam_budget_get_global('phAM-phBF',m_cnst,dMdt_phys_total) + ! + ! total energy fixer should not affect mass - checking + ! + if (abs(dMdt_efix)>eps_mass) then + write(iulog,*) "dMASS/dt energy fixer (pBP-pBF) ",dMdt_efix," Pa/m^2/s" + write(iulog,*) "ERROR: Mass not conserved in energy fixer. ABORT" + call endrun(subname//"Mass not conserved in energy fixer. See atm.log") + endif + ! + ! dry-mass adjustmnt should not affect mass - checking + ! + if (abs(dMdt_dme_adjust)>eps_mass) then + write(iulog,*)"dMASS/dt dry mass adjustment (pAM-pAP) ",dMdt_dme_adjust," Pa/m^2/s" + write(iulog,*) "ERROR: Mass not conserved in dry mass adjustment. ABORT" + call endrun(subname//"Mass not conserved in dry mass adjustment. See atm.log") + end if + ! + ! all of the mass-tendency should come from parameterization - checking + ! + if (abs(dMdt_parameterizations-dMdt_phys_total)>eps_mass) then + write(iulog,*) "Error: dMASS/dt parameterizations (pAP-pBP) .ne. dMASS/dt physics total (pAM-pBF)" + write(iulog,*) "dMASS/dt parameterizations (pAP-pBP) ",dMdt_parameterizations," Pa/m^2/s" + write(iulog,*) "dMASS/dt physics total (pAM-pBF) ",dMdt_phys_total," Pa/m^2/s" + call endrun(subname//"mass change not only due to parameterizations. See atm.log") + end if + write(iulog,*)" " + ! + ! detailed mass budget in dynamical core + ! + if (is_cam_budget('dAD').and.is_cam_budget('dBD').and.is_cam_budget('dAR').and.is_cam_budget('dCH')) then + call cam_budget_get_global('dAD-dBD',m_cnst,dMdt_floating_dyn) + call cam_budget_get_global('dAR-dAD',m_cnst,dMdt_vert_remap) + tmp = dMdt_floating_dyn+dMdt_vert_remap + diff = abs_diff(tmp,0.0_r8,pf=pf) + write(iulog,fmtm)" dMASS/dt total adiabatic dynamics ",diff,pf + ! + ! check for mass-conservation in the adiabatic dynamical core - + ! if not conserved provide detailed break-down + ! + if (abs(diff)>eps_mass) then + write(iulog,*) "Error: mass non-conservation in dynamical core" + write(iulog,*) "(detailed budget below)" + write(iulog,*) " " + write(iulog,*)"dMASS/dt 2D dynamics (dAD-dBD) ",dMdt_floating_dyn," Pa/m^2/s" + write(iulog,*)"dE/dt vertical remapping (dAR-dAD) ",dMdt_vert_remap + write(iulog,*)" " + write(iulog,*)"Breakdown of 2D dynamics:" + write(iulog,*)" " + call cam_budget_get_global('dAH-dCH',m_cnst,dMdt_del4_fric_heat) + call cam_budget_get_global('dAH-dBH',m_cnst,dMdt_del4_tot) + write(iulog,*)"dMASS/dt hypervis (dAH-dBH) ",dMdt_del4_tot," Pa/m^2/s" + write(iulog,*)"dMASS/dt frictional heating (dAH-dCH) ",dMdt_del4_fric_heat," Pa/m^2/s" + dMdt_residual = dMdt_floating_dyn-dMdt_del4_tot + write(iulog,*)"dMASS/dt residual (time truncation errors)",dMdt_residual," Pa/m^2/s" + end if + end if + if (is_cam_budget('dBD').and.is_cam_budget('dAF')) then + ! + ! check if mass change in physics is the same as dynamical core + ! + call cam_budget_get_global('dBD-dAF',m_cnst,dMdt_phys_total_in_dyn) + dMdt_PDC = dMdt_phys_total-dMdt_phys_total_in_dyn + write(iulog,fmtm)" Mass physics-dynamics coupling error ",dMdt_PDC," Pa/m^2/s" + write(iulog,*)" " + if (abs(dMdt_PDC)>eps_mass) then + write(iulog,fmtm)" dMASS/dt physics tendency in dycore (dBD-dAF) ",dMdt_phys_total_in_dyn," Pa/m^2/s" + write(iulog,fmtm)" dMASS/dt total physics ",dMdt_phys_total," Pa/m^2/s" + end if + end if + end if + end do + ! + ! save adiabatic dycore dE/dt and dry-mass adjustment to avoid samping error + ! + previous_dEdt_adiabatic_dycore = dEdt_dycore_dyn + previous_dEdt_dry_mass_adjust = dEdt_dme_adjust_dynE(1) + end if +end subroutine print_budget +!========================================================================================= +function abs_diff(a,b,pf) + real(r8), intent(in) :: a,b + character(LEN=5), optional, intent(out):: pf + real(r8) :: abs_diff + if (abs(b)>eps) then + abs_diff = abs((b-a)/b) + else + abs_diff = abs(b-a) + end if + If (present(pf)) then + if (abs_diff>eps) then + pf = ' FAIL' + else + pf = ' PASS' + end if + end if +end function abs_diff +end module dycore_budget diff --git a/src/dynamics/se/dyn_comp.F90 b/src/dynamics/se/dyn_comp.F90 index f0d42d6ed2..6504eb75cd 100644 --- a/src/dynamics/se/dyn_comp.F90 +++ b/src/dynamics/se/dyn_comp.F90 @@ -15,7 +15,7 @@ module dyn_comp ini_grid_hdim_name use cam_grid_support, only: cam_grid_id, cam_grid_get_gcid, & - cam_grid_dimensions, cam_grid_get_dim_names, & + cam_grid_dimensions, & cam_grid_get_latvals, cam_grid_get_lonvals, & max_hcoordname_len use cam_map_utils, only: iMap @@ -38,8 +38,8 @@ module dyn_comp use parallel_mod, only: par use hybrid_mod, only: hybrid_t -use dimensions_mod, only: nelemd, nlev, np, npsq, ntrac, nc, fv_nphys, & - qsize +use dimensions_mod, only: nelemd, nlev, np, npsq, ntrac, nc, fv_nphys +use dimensions_mod, only: qsize, use_cslam use element_mod, only: element_t, elem_state_t use fvm_control_volume_mod, only: fvm_struct use time_mod, only: nsplit @@ -84,6 +84,7 @@ module dyn_comp real(r8), parameter :: rad2deg = 180.0_r8 / pi real(r8), parameter :: deg2rad = pi / 180.0_r8 +real(r8), parameter :: rarea_sphere = 1.0_r8 / (4.0_r8*PI) !=============================================================================== contains @@ -106,13 +107,12 @@ subroutine dyn_readnl(NLFileName) use control_mod, only: vert_remap_uvTq_alg, vert_remap_tracer_alg use control_mod, only: tstep_type, rk_stage_user use control_mod, only: ftype, limiter_option, partmethod - use control_mod, only: topology, phys_dyn_cp, variable_nsplit + use control_mod, only: topology, variable_nsplit use control_mod, only: fine_ne, hypervis_power, hypervis_scaling use control_mod, only: max_hypervis_courant, statediag_numtrac,refined_mesh use control_mod, only: molecular_diff use control_mod, only: sponge_del4_nu_div_fac, sponge_del4_nu_fac, sponge_del4_lev use dimensions_mod, only: ne, npart - use dimensions_mod, only: lcp_moist use dimensions_mod, only: large_Courant_incr use dimensions_mod, only: fvm_supercycling, fvm_supercycling_jet use dimensions_mod, only: kmin_jet, kmax_jet @@ -120,13 +120,11 @@ subroutine dyn_readnl(NLFileName) use parallel_mod, only: initmpi use thread_mod, only: initomp, max_num_threads use thread_mod, only: horz_num_threads, vert_num_threads, tracer_num_threads - use physconst, only: rearth ! Dummy argument character(len=*), intent(in) :: NLFileName ! Local variables integer :: unitn, ierr,k - real(r8) :: uniform_res_hypervis_scaling,nu_fac ! SE Namelist variables integer :: se_fine_ne @@ -162,14 +160,12 @@ subroutine dyn_readnl(NLFileName) integer :: se_horz_num_threads integer :: se_vert_num_threads integer :: se_tracer_num_threads - logical :: se_lcp_moist logical :: se_write_restart_unstruct logical :: se_large_Courant_incr integer :: se_fvm_supercycling integer :: se_fvm_supercycling_jet integer :: se_kmin_jet integer :: se_kmax_jet - integer :: se_phys_dyn_cp real(r8) :: se_molecular_diff namelist /dyn_se_inparm/ & @@ -209,14 +205,12 @@ subroutine dyn_readnl(NLFileName) se_horz_num_threads, & se_vert_num_threads, & se_tracer_num_threads, & - se_lcp_moist, & se_write_restart_unstruct, & se_large_Courant_incr, & se_fvm_supercycling, & se_fvm_supercycling_jet, & se_kmin_jet, & se_kmax_jet, & - se_phys_dyn_cp, & se_molecular_diff !-------------------------------------------------------------------------- @@ -284,14 +278,12 @@ subroutine dyn_readnl(NLFileName) call MPI_bcast(se_horz_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) call MPI_bcast(se_vert_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) call MPI_bcast(se_tracer_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) - call MPI_bcast(se_lcp_moist, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_write_restart_unstruct, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_large_Courant_incr, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_fvm_supercycling, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_fvm_supercycling_jet, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_kmin_jet, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_kmax_jet, 1, mpi_integer, masterprocid, mpicom, ierr) - call MPI_bcast(se_phys_dyn_cp, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_molecular_diff, 1, mpi_real8, masterprocid, mpicom, ierr) if (se_npes <= 0) then @@ -353,26 +345,26 @@ subroutine dyn_readnl(NLFileName) vert_remap_uvTq_alg = set_vert_remap(se_vert_remap_T, se_vert_remap_uvTq_alg) vert_remap_tracer_alg = set_vert_remap(se_vert_remap_T, se_vert_remap_tracer_alg) fv_nphys = se_fv_nphys - lcp_moist = se_lcp_moist large_Courant_incr = se_large_Courant_incr fvm_supercycling = se_fvm_supercycling fvm_supercycling_jet = se_fvm_supercycling_jet kmin_jet = se_kmin_jet kmax_jet = se_kmax_jet variable_nsplit = .false. - phys_dyn_cp = se_phys_dyn_cp molecular_diff = se_molecular_diff if (fv_nphys > 0) then ! Use finite volume physics grid and CSLAM for tracer advection nphys_pts = fv_nphys*fv_nphys qsize = thermodynamic_active_species_num ! number tracers advected by GLL - ntrac = pcnst ! number tracers advected by CSLAM + ntrac = pcnst ! number tracers advected by CSLAM + use_cslam = .true. else ! Use GLL grid for physics and tracer advection nphys_pts = npsq qsize = pcnst ntrac = 0 + use_cslam = .false. end if if (rsplit < 1) then @@ -431,7 +423,6 @@ subroutine dyn_readnl(NLFileName) end if write(iulog, '(a,i0)') 'dyn_readnl: se_npes = ',se_npes write(iulog, '(a,i0)') 'dyn_readnl: se_nsplit = ',se_nsplit - write(iulog, '(a,i0)') 'dyn_readnl: se_phys_dyn_cp = ',se_phys_dyn_cp ! ! se_nu<0 then coefficients are set automatically in module global_norms_mod ! @@ -451,7 +442,6 @@ subroutine dyn_readnl(NLFileName) write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_T = ',trim(se_vert_remap_T) write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_uvTq_alg = ',trim(se_vert_remap_uvTq_alg) write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_tracer_alg = ',trim(se_vert_remap_tracer_alg) - write(iulog, '(a,l4)') 'dyn_readnl: lcp_moist = ',lcp_moist write(iulog, '(a,i0)') 'dyn_readnl: se_fvm_supercycling = ',fvm_supercycling write(iulog, '(a,i0)') 'dyn_readnl: se_fvm_supercycling_jet = ',fvm_supercycling_jet write(iulog, '(a,i0)') 'dyn_readnl: se_kmin_jet = ',kmin_jet @@ -584,7 +574,7 @@ subroutine dyn_init(dyn_in, dyn_out) use prim_advance_mod, only: prim_advance_init use dyn_grid, only: elem, fvm use cam_pio_utils, only: clean_iodesc_list - use physconst, only: rair, cpair, pstd + use physconst, only: cpair, pstd use air_composition, only: thermodynamic_active_species_num, thermodynamic_active_species_idx use air_composition, only: thermodynamic_active_species_idx_dycore use air_composition, only: thermodynamic_active_species_liq_idx,thermodynamic_active_species_ice_idx @@ -595,36 +585,37 @@ subroutine dyn_init(dyn_in, dyn_out) use thread_mod, only: horz_num_threads use hybrid_mod, only: get_loop_ranges, config_thread_region - use dimensions_mod, only: nu_scale_top, nu_lev, nu_div_lev + use dimensions_mod, only: nu_scale_top use dimensions_mod, only: ksponge_end, kmvis_ref, kmcnd_ref,rho_ref,km_sponge_factor use dimensions_mod, only: cnst_name_gll, cnst_longname_gll use dimensions_mod, only: irecons_tracer_lev, irecons_tracer, kord_tr, kord_tr_cslam use prim_driver_mod, only: prim_init2 - use time_mod, only: time_at - use control_mod, only: runtype, molecular_diff, nu_top + use control_mod, only: molecular_diff, nu_top use test_fvm_mapping, only: test_mapping_addfld use phys_control, only: phys_getopts use cam_thermo, only: get_molecular_diff_coef_reference use control_mod, only: vert_remap_uvTq_alg, vert_remap_tracer_alg use std_atm_profile, only: std_atm_height use dyn_tests_utils, only: vc_dycore, vc_dry_pressure, string_vc, vc_str_lgth + use cam_budget, only: cam_budget_em_snapshot, cam_budget_em_register, thermo_budget_history + ! Dummy arguments: type(dyn_import_t), intent(out) :: dyn_in type(dyn_export_t), intent(out) :: dyn_out ! Local variables - integer :: ithr, nets, nete, ie, k, kmol_end, mfound + integer :: nets, nete, ie, k, kmol_end, mfound real(r8), parameter :: Tinit = 300.0_r8 real(r8) :: press(1), ptop, tref,z(1) type(hybrid_t) :: hybrid - integer :: ixcldice, ixcldliq, ixrain, ixsnow, ixgraupel + integer :: ixcldice, ixcldliq integer :: m_cnst, m ! variables for initializing energy and axial angular momentum diagnostics - integer, parameter :: num_stages = 12, num_vars = 8 - character (len = 3), dimension(num_stages) :: stage = (/"dED","dAF","dBD","dAD","dAR","dBF","dBH","dCH","dAH",'dBS','dAS','p2d'/) + integer, parameter :: num_stages = 12 + character (len = 4), dimension(num_stages) :: stage = (/"dED","dAF","dBD","dAD","dAR","dBF","dBH","dCH","dAH","dBS","dAS","p2d"/) character (len = 70),dimension(num_stages) :: stage_txt = (/& " end of previous dynamics ",& !dED " from previous remapping or state passed to dynamics",& !dAF - state in beginning of nsplit loop @@ -639,28 +630,11 @@ subroutine dyn_init(dyn_in, dyn_out) " state after sponge layer diffusion ",& !dAS - state after sponge del2 " phys2dyn mapping errors (requires ftype-1) " & !p2d - for assessing phys2dyn mapping errors /) - character (len = 2) , dimension(num_vars) :: vars = (/"WV" ,"WL" ,"WI" ,"SE" ,"KE" ,"MR" ,"MO" ,"TT" /) - !if ntrac>0 then tracers should be output on fvm grid but not energy (SE+KE) and AAM diags - logical , dimension(num_vars) :: massv = (/.true.,.true.,.true.,.false.,.false.,.false.,.false.,.false./) - character (len = 70) , dimension(num_vars) :: vars_descriptor = (/& - "Total column water vapor ",& - "Total column cloud water ",& - "Total column cloud ice ",& - "Total column static energy ",& - "Total column kinetic energy ",& - "Total column wind axial angular momentum",& - "Total column mass axial angular momentum",& - "Total column test tracer "/) - character (len = 14), dimension(num_vars) :: & - vars_unit = (/& - "kg/m2 ","kg/m2 ","kg/m2 ","J/m2 ",& - "J/m2 ","kg*m2/s*rad2 ","kg*m2/s*rad2 ","kg/m2 "/) - - integer :: istage, ivars - character (len=108) :: str1, str2, str3 + + integer :: istage character (len=vc_str_lgth) :: vc_str - logical :: history_budget ! output tendencies and state variables for budgets + logical :: history_budget ! output tendencies and state variables for budgets integer :: budget_hfile_num character(len=*), parameter :: sub = 'dyn_init' @@ -678,7 +652,7 @@ subroutine dyn_init(dyn_in, dyn_out) allocate(kord_tr(qsize)) kord_tr(:) = vert_remap_tracer_alg - if (ntrac>0) then + if (use_cslam) then allocate(kord_tr_cslam(ntrac)) kord_tr_cslam(:) = vert_remap_tracer_alg end if @@ -696,7 +670,7 @@ subroutine dyn_init(dyn_in, dyn_out) ! CSLAM tracers are always indexed as in physics ! of no CSLAM then SE tracers are always indexed as in physics ! - if (ntrac>0) then + if (use_cslam) then ! ! note that in this case qsize = thermodynamic_active_species_num ! @@ -720,7 +694,7 @@ subroutine dyn_init(dyn_in, dyn_out) end do do m=1,thermodynamic_active_species_liq_num - if (ntrac>0) then + if (use_cslam) then do mfound=1,qsize if (TRIM(cnst_name(thermodynamic_active_species_liq_idx(m)))==TRIM(cnst_name_gll(mfound))) then thermodynamic_active_species_liq_idx_dycore(m) = mfound @@ -734,7 +708,7 @@ subroutine dyn_init(dyn_in, dyn_out) end if end do do m=1,thermodynamic_active_species_ice_num - if (ntrac>0) then + if (use_cslam) then do mfound=1,qsize if (TRIM(cnst_name(thermodynamic_active_species_ice_idx(m)))==TRIM(cnst_name_gll(mfound))) then thermodynamic_active_species_ice_idx_dycore(m) = mfound @@ -880,7 +854,7 @@ subroutine dyn_init(dyn_in, dyn_out) call addfld ('FT', (/ 'lev' /), 'A', 'K/s', 'Temperature forcing term on GLL grid',gridname='GLL') ! Tracer forcing on fvm (CSLAM) grid and internal CSLAM pressure fields - if (ntrac>0) then + if (use_cslam) then do m = 1, ntrac call addfld (trim(cnst_name(m))//'_fvm', (/ 'lev' /), 'I', 'kg/kg', & trim(cnst_longname(m)), gridname='FVM') @@ -902,7 +876,7 @@ subroutine dyn_init(dyn_in, dyn_out) ! Energy diagnostics and axial angular momentum diagnostics call addfld ('ABS_dPSdt', horiz_only, 'A', 'Pa/s', 'Absolute surface pressure tendency',gridname='GLL') - if (ntrac>0) then + if (use_cslam) then #ifdef waccm_debug call addfld ('CSLAM_gamma', (/ 'lev' /), 'A', '', 'Courant number from CSLAM', gridname='FVM') #endif @@ -917,23 +891,43 @@ subroutine dyn_init(dyn_in, dyn_out) call addfld ('TT_PDC', horiz_only, 'A', 'kg/m2','Total column test tracer lost in physics-dynamics coupling',gridname='GLL') end if - do istage = 1, num_stages - do ivars=1, num_vars - write(str1,*) TRIM(ADJUSTL(vars(ivars))),"_",TRIM(ADJUSTL(stage(istage))) - write(str2,*) TRIM(ADJUSTL(vars_descriptor(ivars)))," ", & - TRIM(ADJUSTL(stage_txt(istage))) - write(str3,*) TRIM(ADJUSTL(vars_unit(ivars))) - if (ntrac>0.and.massv(ivars)) then - call addfld (TRIM(ADJUSTL(str1)), horiz_only, 'A', TRIM(ADJUSTL(str3)),TRIM(ADJUSTL(str2)),gridname='FVM') - else - call addfld (TRIM(ADJUSTL(str1)), horiz_only, 'A', TRIM(ADJUSTL(str3)),TRIM(ADJUSTL(str2)),gridname='GLL') - end if + if (thermo_budget_history) then + ! Register stages for budgets + do istage = 1, num_stages + call cam_budget_em_snapshot(TRIM(ADJUSTL(stage(istage))), 'dyn', & + longname=TRIM(ADJUSTL(stage_txt(istage)))) end do - end do + ! + ! Register tendency (difference) budgets + ! + call cam_budget_em_register('dEdt_floating_dyn' ,'dAD','dBD','dyn','dif', & + longname="dE/dt floating dynamics (dAD-dBD)" ) + call cam_budget_em_register('dEdt_vert_remap' ,'dAR','dAD','dyn','dif', & + longname="dE/dt vertical remapping (dAR-dAD)" ) + call cam_budget_em_register('dEdt_phys_tot_in_dyn','dBD','dAF','dyn','dif', & + longname="dE/dt physics tendency in dynamics (dBD-dAF)" ) + call cam_budget_em_register('dEdt_del4' ,'dCH','dBH','dyn','dif', & + longname="dE/dt del4 (dCH-dBH)" ) + call cam_budget_em_register('dEdt_del4_fric_heat','dAH','dCH','dyn','dif', & + longname="dE/dt del4 frictional heating (dAH-dCH)" ) + call cam_budget_em_register('dEdt_del4_tot' ,'dAH','dBH','dyn','dif', & + longname="dE/dt del4 + del4 frictional heating (dAH-dBH)" ) + call cam_budget_em_register('dEdt_del2_sponge' ,'dAS','dBS','dyn','dif', & + longname="dE/dt del2 sponge (dAS-dBS)" ) + ! + ! Register derived budgets + ! + call cam_budget_em_register('dEdt_dycore' ,'dEdt_floating_dyn','dEdt_vert_remap' ,'dyn','sum', & + longname="dE/dt adiabatic dynamics" ) + call cam_budget_em_register('dEdt_del2_del4_tot' ,'dEdt_del4_tot' ,'dEdt_del2_sponge' ,'dyn','sum', & + longname="dE/dt explicit diffusion total" ) + call cam_budget_em_register('dEdt_residual' ,'dEdt_floating_dyn','dEdt_del2_del4_tot','dyn','dif',& + longname="dE/dt residual (dEdt_floating_dyn-dEdt_del2_del4_tot)" ) + end if ! ! add dynamical core tracer tendency output ! - if (ntrac>0) then + if (use_cslam) then do m = 1, pcnst call addfld(tottnam(m),(/ 'lev' /),'A','kg/kg/s',trim(cnst_name(m))//' horz + vert', & gridname='FVM') @@ -961,7 +955,6 @@ end subroutine dyn_init subroutine dyn_run(dyn_state) use air_composition, only: thermodynamic_active_species_num, dry_air_species_num use air_composition, only: thermodynamic_active_species_idx_dycore - use prim_advance_mod, only: calc_tot_energy_dynamics use prim_driver_mod, only: prim_run_subcycle use dimensions_mod, only: cnst_name_gll use time_mod, only: tstep, nsplit, timelevel_qdp @@ -975,7 +968,7 @@ subroutine dyn_run(dyn_state) type(hybrid_t) :: hybrid integer :: tl_f integer :: n - integer :: nets, nete, ithr + integer :: nets, nete integer :: i, ie, j, k, m, nq, m_cnst integer :: n0_qdp, nsplit_local logical :: ldiag @@ -1078,7 +1071,7 @@ subroutine dyn_run(dyn_state) end if - if (ntrac > 0) then + if (use_cslam) then do ie = nets, nete do m = 1, ntrac do k = 1, nlev @@ -1126,8 +1119,6 @@ subroutine dyn_run(dyn_state) end do end if - - call calc_tot_energy_dynamics(dyn_state%elem,dyn_state%fvm, nets, nete, TimeLevel%n0, n0_qdp,'dBF') !$OMP END PARALLEL if (ldiag) then @@ -1157,7 +1148,7 @@ subroutine read_inidat(dyn_in) use element_mod, only: timelevels use fvm_mapping, only: dyn2fvm_mass_vars - use control_mod, only: runtype,initial_global_ave_dry_ps + use control_mod, only: runtype use prim_driver_mod, only: prim_set_dry_mass use air_composition, only: thermodynamic_active_species_idx use cam_initfiles, only: scale_dry_air_mass @@ -1180,8 +1171,8 @@ subroutine read_inidat(dyn_in) logical, allocatable :: pmask(:) ! (npsq*nelemd) unique grid vals character(len=max_hcoordname_len):: grid_name - real(r8), allocatable :: latvals(:),latvals_phys(:) - real(r8), allocatable :: lonvals(:),lonvals_phys(:) + real(r8), allocatable :: latvals(:) + real(r8), allocatable :: lonvals(:) real(r8), pointer :: latvals_deg(:) real(r8), pointer :: lonvals_deg(:) @@ -1193,9 +1184,6 @@ subroutine read_inidat(dyn_in) integer :: kptr, m_cnst type(EdgeBuffer_t) :: edge - character(len=max_fieldname_len) :: varname - integer :: ierr - integer :: rndm_seed_sz integer, allocatable :: rndm_seed(:) integer :: dims(2) @@ -1206,10 +1194,6 @@ subroutine read_inidat(dyn_in) character(len=128) :: errmsg character(len=*), parameter :: sub='READ_INIDAT' - ! fvm vars - real(r8), allocatable :: inv_dp_darea_fvm(:,:,:) - real(r8) :: min_val, max_val - real(r8) :: dp_tmp, pstmp(np,np) ! Variables for analytic initial conditions @@ -1701,7 +1685,7 @@ subroutine read_inidat(dyn_in) ! if CSLAM active then we only advect water vapor and condensate ! loading tracers in state%qdp - if (ntrac > 0) then + if (use_cslam) then do ie = 1, nelemd do nq = 1, thermodynamic_active_species_num m_cnst = thermodynamic_active_species_idx(nq) @@ -1732,7 +1716,7 @@ subroutine read_inidat(dyn_in) ! interpolate fvm tracers and fvm pressure variables - if (ntrac > 0) then + if (use_cslam) then if (par%masterproc) then write(iulog,*) 'Initializing dp_fvm from spectral element dp' end if @@ -1754,7 +1738,7 @@ subroutine read_inidat(dyn_in) write(iulog,*) 'FVM tracers, FVM pressure variables and se_area_sphere initialized.' end if - end if ! (ntrac > 0) + end if ! (use_cslam) ! Cleanup deallocate(qtmp) @@ -2021,7 +2005,6 @@ subroutine check_file_layout(file, elem, dyn_cols, file_desc, dyn_ok) integer :: ncol_did, ncol_size integer :: ierr integer :: ie, i, j - integer :: grid_id integer :: indx real(r8) :: dbuf2(npsq, nelemd) logical :: found @@ -2300,7 +2283,7 @@ subroutine write_dyn_vars(dyn_out) integer :: ie, m !---------------------------------------------------------------------------- - if (ntrac > 0) then + if (use_cslam) then do ie = 1, nelemd call outfld('dp_fvm', RESHAPE(dyn_out%fvm(ie)%dp_fvm(1:nc,1:nc,:), & (/nc*nc,nlev/)), nc*nc, ie) diff --git a/src/dynamics/se/dyn_grid.F90 b/src/dynamics/se/dyn_grid.F90 index 77f3a27f2f..766fb893d7 100644 --- a/src/dynamics/se/dyn_grid.F90 +++ b/src/dynamics/se/dyn_grid.F90 @@ -41,7 +41,7 @@ module dyn_grid use pio, only: file_desc_t use dimensions_mod, only: globaluniquecols, nelem, nelemd, nelemdmax -use dimensions_mod, only: ne, np, npsq, fv_nphys, nlev, ntrac +use dimensions_mod, only: ne, np, npsq, fv_nphys, nlev, use_cslam use element_mod, only: element_t use fvm_control_volume_mod, only: fvm_struct use hybvcoord_mod, only: hvcoord_t @@ -59,7 +59,6 @@ module dyn_grid integer, parameter :: fvm_decomp = 102 ! The FVM (CSLAM) grid integer, parameter :: physgrid_d = 103 ! physics grid on dynamics decomp integer, parameter :: ini_decomp = 104 ! alternate dynamics grid for reading initial file - character(len=3), protected :: ini_grid_name ! Name of horizontal grid dimension in initial file. @@ -733,6 +732,7 @@ subroutine define_cam_grids() use cam_grid_support, only: horiz_coord_t, horiz_coord_create use cam_grid_support, only: cam_grid_register, cam_grid_attribute_register use dimensions_mod, only: nc + use shr_const_mod, only: PI => SHR_CONST_PI ! Local variables integer :: i, ii, j, k, ie, mapind @@ -744,22 +744,40 @@ subroutine define_cam_grids() real(r8), allocatable :: pelat_deg(:) ! pe-local latitudes (degrees) real(r8), allocatable :: pelon_deg(:) ! pe-local longitudes (degrees) - real(r8), pointer :: pearea(:) => null() ! pe-local areas - real(r8) :: areaw(np,np) + real(r8), pointer :: pearea(:) ! pe-local areas + real(r8), pointer :: pearea_wt(:) ! pe-local areas normalized for unit sphere integer(iMap) :: fdofP_local(npsq,nelemd) ! pe-local map for dynamics decomp integer(iMap), allocatable :: pemap(:) ! pe-local map for PIO decomp integer :: ncols_fvm, ngcols_fvm real(r8), allocatable :: fvm_coord(:) real(r8), pointer :: fvm_area(:) + real(r8), pointer :: fvm_areawt(:) integer(iMap), pointer :: fvm_map(:) integer :: ncols_physgrid, ngcols_physgrid real(r8), allocatable :: physgrid_coord(:) real(r8), pointer :: physgrid_area(:) + real(r8), pointer :: physgrid_areawt(:) integer(iMap), pointer :: physgrid_map(:) + + real(r8), parameter :: rarea_unit_sphere = 1.0_r8 / (4.0_r8*PI) + !---------------------------------------------------------------------------- + !----------------------- + ! initialize pointers to null + !----------------------- + nullify(pearea_wt) + nullify(pearea) + nullify(fvm_area) + nullify(fvm_areawt) + nullify(fvm_map) + nullify(physgrid_area) + nullify(physgrid_areawt) + nullify(physgrid_map) + nullify(grid_map) + !----------------------- ! Create GLL grid object !----------------------- @@ -777,16 +795,17 @@ subroutine define_cam_grids() allocate(pelat_deg(np*np*nelemd)) allocate(pelon_deg(np*np*nelemd)) allocate(pearea(np*np*nelemd)) + allocate(pearea_wt(np*np*nelemd)) allocate(pemap(np*np*nelemd)) pemap = 0_iMap ii = 1 do ie = 1, nelemd - areaw = 1.0_r8 / elem(ie)%rspheremp(:,:) - pearea(ii:ii+npsq-1) = reshape(areaw, (/ np*np /)) pemap(ii:ii+npsq-1) = fdofp_local(:,ie) do j = 1, np do i = 1, np + pearea(ii) = elem(ie)%mp(i,j)*elem(ie)%metdet(i,j) + pearea_wt(ii) = pearea(ii)*rarea_unit_sphere pelat_deg(ii) = elem(ie)%spherep(i,j)%lat * rad2deg pelon_deg(ii) = elem(ie)%spherep(i,j)%lon * rad2deg ii = ii + 1 @@ -832,6 +851,8 @@ subroutine define_cam_grids() grid_map, block_indexed=.false., unstruct=.true.) call cam_grid_attribute_register('GLL', 'area_d', 'gll grid areas', & 'ncol_d', pearea, map=pemap) + call cam_grid_attribute_register('GLL', 'area_weight_gll', 'gll grid area weights', & + 'ncol_d', pearea_wt, map=pemap) call cam_grid_attribute_register('GLL', 'np', '', np) call cam_grid_attribute_register('GLL', 'ne', '', ne) @@ -848,6 +869,8 @@ subroutine define_cam_grids() grid_map, block_indexed=.false., unstruct=.true.) call cam_grid_attribute_register('INI', 'area', 'ini grid areas', & 'ncol', pearea, map=pemap) + call cam_grid_attribute_register('INI', 'area_weight_ini', 'ini grid area weights', & + 'ncol', pearea_wt, map=pemap) ini_grid_name = 'INI' else @@ -865,6 +888,7 @@ subroutine define_cam_grids() ! to that memory. It can be nullified since the attribute object has ! the reference. nullify(pearea) + nullify(pearea_wt) ! grid_map cannot be deallocated as the cam_filemap_t object just points ! to it. It can be nullified. @@ -874,13 +898,14 @@ subroutine define_cam_grids() ! Create FVM grid object for CSLAM !--------------------------------- - if (ntrac > 0) then + if (use_cslam) then ncols_fvm = nc * nc * nelemd ngcols_fvm = nc * nc * nelem_d allocate(fvm_coord(ncols_fvm)) allocate(fvm_map(ncols_fvm)) allocate(fvm_area(ncols_fvm)) + allocate(fvm_areawt(ncols_fvm)) do ie = 1, nelemd k = 1 @@ -890,6 +915,7 @@ subroutine define_cam_grids() fvm_coord(mapind) = fvm(ie)%center_cart(i,j)%lon*rad2deg fvm_map(mapind) = k + ((elem(ie)%GlobalId-1) * nc * nc) fvm_area(mapind) = fvm(ie)%area_sphere(i,j) + fvm_areawt(mapind) = fvm_area(mapind)*rarea_unit_sphere k = k + 1 end do end do @@ -930,12 +956,15 @@ subroutine define_cam_grids() grid_map, block_indexed=.false., unstruct=.true.) call cam_grid_attribute_register('FVM', 'area_fvm', 'fvm grid areas', & 'ncol_fvm', fvm_area, map=fvm_map) + call cam_grid_attribute_register('FVM', 'area_weight_fvm', 'fvm grid area weights', & + 'ncol_fvm', fvm_areawt, map=fvm_map) call cam_grid_attribute_register('FVM', 'nc', '', nc) call cam_grid_attribute_register('FVM', 'ne', '', ne) deallocate(fvm_coord) deallocate(fvm_map) nullify(fvm_area) + nullify(fvm_areawt) nullify(grid_map) end if @@ -951,6 +980,7 @@ subroutine define_cam_grids() allocate(physgrid_coord(ncols_physgrid)) allocate(physgrid_map(ncols_physgrid)) allocate(physgrid_area(ncols_physgrid)) + allocate(physgrid_areawt(ncols_physgrid)) do ie = 1, nelemd k = 1 @@ -960,6 +990,7 @@ subroutine define_cam_grids() physgrid_coord(mapind) = fvm(ie)%center_cart_physgrid(i,j)%lon*rad2deg physgrid_map(mapind) = k + ((elem(ie)%GlobalId-1) * fv_nphys * fv_nphys) physgrid_area(mapind) = fvm(ie)%area_sphere_physgrid(i,j) + physgrid_areawt(mapind) = physgrid_area(mapind)*rarea_unit_sphere k = k + 1 end do end do @@ -1000,12 +1031,15 @@ subroutine define_cam_grids() grid_map, block_indexed=.false., unstruct=.true.) call cam_grid_attribute_register('physgrid_d', 'area_physgrid', 'physics grid areas', & 'ncol', physgrid_area, map=physgrid_map) + call cam_grid_attribute_register('physgrid_d', 'area_weight_physgrid', 'physics grid area weight', & + 'ncol', physgrid_areawt, map=physgrid_map) call cam_grid_attribute_register('physgrid_d', 'fv_nphys', '', fv_nphys) call cam_grid_attribute_register('physgrid_d', 'ne', '', ne) deallocate(physgrid_coord) deallocate(physgrid_map) nullify(physgrid_area) + nullify(physgrid_areawt) nullify(grid_map) end if diff --git a/src/dynamics/se/restart_dynamics.F90 b/src/dynamics/se/restart_dynamics.F90 index d3b1aa28fa..f5b3c6a0d8 100644 --- a/src/dynamics/se/restart_dynamics.F90 +++ b/src/dynamics/se/restart_dynamics.F90 @@ -43,7 +43,7 @@ module restart_dynamics use parallel_mod, only: par use thread_mod, only: horz_num_threads -use dimensions_mod, only: np, npsq, ne, nlev, qsize, nelemd, nc, ntrac +use dimensions_mod, only: np, npsq, ne, nlev, qsize, nelemd, nc, ntrac, use_cslam use dof_mod, only: UniquePoints use element_mod, only: element_t use time_mod, only: tstep, TimeLevel_Qdp @@ -148,7 +148,7 @@ subroutine init_restart_dynamics(file, dyn_out) ! CSLAM restart fields - if (ntrac > 0) then + if (use_cslam) then grid_id = cam_grid_id('FVM') call cam_grid_write_attr(File, grid_id, info) @@ -223,7 +223,7 @@ subroutine write_restart_dynamics(File, dyn_out) ! write CSLAM fields - if (ntrac > 0) then + if (use_cslam) then grid_id = cam_grid_id('FVM') @@ -621,7 +621,7 @@ subroutine read_restart_dynamics(File, dyn_in, dyn_out) ! read cslam fields - if (ntrac > 0) then + if (use_cslam) then ! Checks that file and model dimensions agree. diff --git a/src/dynamics/se/stepon.F90 b/src/dynamics/se/stepon.F90 index febda50539..88dda66c3d 100644 --- a/src/dynamics/se/stepon.F90 +++ b/src/dynamics/se/stepon.F90 @@ -154,7 +154,7 @@ subroutine stepon_run2(phys_state, phys_tend, dyn_in, dyn_out) use time_mod, only: TimeLevel_Qdp use control_mod, only: qsplit - use prim_advance_mod, only: calc_tot_energy_dynamics + use prim_advance_mod, only: tot_energy_dyn ! arguments @@ -194,7 +194,7 @@ subroutine stepon_run2(phys_state, phys_tend, dyn_in, dyn_out) call t_stopf('p_d_coupling') if (iam < par%nprocs) then - call calc_tot_energy_dynamics(dyn_in%elem,dyn_in%fvm, 1, nelemd, tl_f, tl_fQdp,'dED') + call tot_energy_dyn(dyn_in%elem,dyn_in%fvm, 1, nelemd, tl_f, tl_fQdp,'dED') end if end subroutine stepon_run2 diff --git a/src/dynamics/se/test_fvm_mapping.F90 b/src/dynamics/se/test_fvm_mapping.F90 index ef0481b5e0..4a26484854 100644 --- a/src/dynamics/se/test_fvm_mapping.F90 +++ b/src/dynamics/se/test_fvm_mapping.F90 @@ -3,7 +3,7 @@ module test_fvm_mapping use fvm_control_volume_mod, only: fvm_struct use cam_history, only: outfld use physconst, only: pi - use dimensions_mod, only: np, nelemd, nlev, npsq, ntrac + use dimensions_mod, only: np, nelemd, nlev, npsq, ntrac, use_cslam use element_mod, only: element_t implicit none private @@ -147,10 +147,6 @@ subroutine test_mapping_overwrite_tendencies(phys_state,phys_tend,ncols,lchnk,q_ integer :: m_cnst, nq, ie q_prev(:,:,ntrac) = 0.0_r8 - do ie=1,nelemd -!xxx fvm(ie)%c(:,:,:,ntrac) = 0.0_r8 - end do - phys_state%pdel(1:ncols,:) = phys_state%pdeldry(1:ncols,:) !make sure there is no conversion from wet to dry do nq=ntrac,ntrac m_cnst = nq @@ -243,7 +239,7 @@ subroutine test_mapping_output_mapped_tendencies(fvm,elem,nets,nete,tl_f,tl_qdp) name = 'p2d_'//trim(cnst_name(m_cnst))//'_err_gll' call outfld(TRIM(name), RESHAPE(elem(ie)%derived%fq(:,:,:,nq),(/npsq,nlev/)), npsq, ie) end do - if (ntrac>0) then + if (use_cslam) then do nq=ntrac,ntrac m_cnst = nq name = 'p2f_'//trim(cnst_name(m_cnst))//'_fvm' @@ -356,7 +352,6 @@ subroutine test_mapping_overwrite_dyn_state(elem,fvm) end do end if end do -! call fill_halo_fvm_noprealloc(elem,fvm,hybrid,nets,nete,nhc,1,nlev)!xxx nhr chould be a function of interp_method #endif end subroutine test_mapping_overwrite_dyn_state @@ -370,15 +365,11 @@ subroutine test_mapping_output_phys_state(phys_state,fvm) integer :: lchnk, ncol,k,icol,m_cnst,nq,ie character(LEN=128) :: name - do ie=1,nelemd -!xxx fvm(ie)%c(:,:,:,ntrac) = 0.0_r8 - end do - do lchnk = begchunk, endchunk call outfld('d2p_scalar', phys_state(lchnk)%omega(1:pcols,1:pver), pcols, lchnk) call outfld('d2p_u', phys_state(lchnk)%U(1:pcols,1:pver), pcols, lchnk) call outfld('d2p_v', phys_state(lchnk)%V(1:pcols,1:pver), pcols, lchnk) - if (ntrac>0) then + if (use_cslam) then do nq=ntrac,ntrac m_cnst = nq name = 'f2p_'//trim(cnst_name(m_cnst)) diff --git a/src/infrastructure/phys_grid.F90 b/src/infrastructure/phys_grid.F90 index 505fdb0c26..3426c86f27 100644 --- a/src/infrastructure/phys_grid.F90 +++ b/src/infrastructure/phys_grid.F90 @@ -190,6 +190,7 @@ subroutine phys_grid_init() use cam_grid_support, only: iMap, hclen => max_hcoordname_len use cam_grid_support, only: horiz_coord_t, horiz_coord_create use cam_grid_support, only: cam_grid_attribute_copy, cam_grid_attr_exists + use shr_const_mod, only: PI => SHR_CONST_PI ! Local variables integer :: index @@ -206,6 +207,7 @@ subroutine phys_grid_init() type(horiz_coord_t), pointer :: lat_coord type(horiz_coord_t), pointer :: lon_coord real(r8), pointer :: area_d(:) + real(r8), pointer :: areawt_d(:) real(r8) :: mem_hw_beg, mem_hw_end real(r8) :: mem_beg, mem_end logical :: unstructured @@ -214,6 +216,7 @@ subroutine phys_grid_init() character(len=hclen), pointer :: copy_attributes(:) character(len=hclen) :: copy_gridname character(len=*), parameter :: subname = 'phys_grid_init: ' + real(r8), parameter :: rarea_sphere = 1.0_r8 / (4.0_r8*PI) nullify(lonvals) nullify(latvals) @@ -221,6 +224,7 @@ subroutine phys_grid_init() nullify(lat_coord) nullify(lon_coord) nullify(area_d) + nullify(areawt_d) nullify(copy_attributes) if (calc_memory_increase) then @@ -416,6 +420,14 @@ subroutine phys_grid_init() call cam_grid_attribute_register('physgrid', 'area', & 'physics column areas', 'ncol', area_d, map=grid_map(3,:)) nullify(area_d) ! Belongs to attribute now + + allocate(areawt_d(size(grid_map, 2))) + do col_index = 1, columns_on_task + areawt_d(col_index) = phys_columns(col_index)%weight*rarea_sphere + end do + call cam_grid_attribute_register('physgrid', 'areawt', & + 'physics column area weight', 'ncol', areawt_d, map=grid_map(3,:)) + nullify(areawt_d) ! Belongs to attribute now else call endrun(subname//"No 'area' attribute from dycore") end if diff --git a/src/physics/cam/cam_diagnostics.F90 b/src/physics/cam/cam_diagnostics.F90 index f0131dab0e..10612edfa9 100644 --- a/src/physics/cam/cam_diagnostics.F90 +++ b/src/physics/cam/cam_diagnostics.F90 @@ -13,8 +13,9 @@ module cam_diagnostics use physics_buffer, only: dyn_time_lvls, pbuf_get_field, pbuf_get_index, pbuf_old_tim_idx use cam_history, only: outfld, write_inithist, hist_fld_active, inithist_all +use cam_history_support, only: max_fieldname_len use constituents, only: pcnst, cnst_name, cnst_longname, cnst_cam_outfld -use constituents, only: ptendnam, dmetendnam, apcnst, bpcnst, cnst_get_ind +use constituents, only: ptendnam, apcnst, bpcnst, cnst_get_ind use dycore, only: dycore_is use phys_control, only: phys_getopts use wv_saturation, only: qsat, qsat_water, svp_ice_vect @@ -46,6 +47,18 @@ module cam_diagnostics diag_physvar_ic, & nsurf +integer, public, parameter :: num_stages = 8 +character (len = max_fieldname_len), dimension(num_stages) :: stage = (/"phBF","phBP","phAP","phAM","dyBF","dyBP","dyAP","dyAM"/) +character (len = 45),dimension(num_stages) :: stage_txt = (/& + " before energy fixer ",& !phBF - physics energy + " before parameterizations ",& !phBF - physics energy + " after parameterizations ",& !phAP - physics energy + " after dry mass correction ",& !phAM - physics energy + " before energy fixer (dycore) ",& !dyBF - dynamics energy + " before parameterizations (dycore) ",& !dyBF - dynamics energy + " after parameterizations (dycore) ",& !dyAP - dynamics energy + " after dry mass correction (dycore) " & !dyAM - dynamics energy + /) ! Private data @@ -176,46 +189,12 @@ subroutine diag_init_dry(pbuf2d) use cam_history, only: addfld, add_default, horiz_only use cam_history, only: register_vector_field - use constituent_burden, only: constituent_burden_init - use physics_buffer, only: pbuf_set_field use tidal_diag, only: tidal_diag_init + use cam_budget, only: cam_budget_em_snapshot, cam_budget_em_register, thermo_budget_history type(physics_buffer_desc), pointer, intent(in) :: pbuf2d(:,:) - integer :: k, m - integer :: ierr - ! - ! variables for energy diagnostics - ! - integer :: istage, ivars - character (len=108) :: str1, str2, str3 - integer, parameter :: num_stages = 8, num_vars = 8 - character (len = 4), dimension(num_stages) :: stage = (/"phBF","phBP","phAP","phAM","dyBF","dyBP","dyAP","dyAM"/) - character (len = 45),dimension(num_stages) :: stage_txt = (/& - " before energy fixer ",& !phBF - physics energy - " before parameterizations ",& !phBF - physics energy - " after parameterizations ",& !phAP - physics energy - " after dry mass correction ",& !phAM - physics energy - " before energy fixer (dycore) ",& !dyBF - dynamics energy - " before parameterizations (dycore) ",& !dyBF - dynamics energy - " after parameterizations (dycore) ",& !dyAP - dynamics energy - " after dry mass correction (dycore) " & !dyAM - dynamics energy - /) - character (len = 2) , dimension(num_vars) :: vars = (/"WV" ,"WL" ,"WI" ,"SE" ,"KE" ,"MR" ,"MO" ,"TT" /) - character (len = 45) , dimension(num_vars) :: vars_descriptor = (/& - "Total column water vapor ",& - "Total column liquid water ",& - "Total column frozen water ",& - "Total column dry static energy ",& - "Total column kinetic energy ",& - "Total column wind axial angular momentum",& - "Total column mass axial angular momentum",& - "Total column test tracer "/) - character (len = 14), dimension(num_vars) :: & - vars_unit = (/& - "kg/m2 ","kg/m2 ","kg/m2 ","J/m2 ",& - "J/m2 ","kg*m2/s*rad2 ","kg*m2/s*rad2 ","kg/m2 "/) - + integer :: istage ! outfld calls in diag_phys_writeout call addfld (cnst_name(1), (/ 'lev' /), 'A', 'kg/kg', cnst_longname(1)) call addfld ('NSTEP', horiz_only, 'A', 'timestep', 'Model timestep') @@ -242,7 +221,7 @@ subroutine diag_init_dry(pbuf2d) call register_vector_field('UAP','VAP') call addfld (apcnst(1), (/ 'lev' /), 'A','kg/kg', trim(cnst_longname(1))//' (after physics)') - if ( dycore_is('LR') .or. dycore_is('SE') .or. dycore_is('FV3') ) then + if (.not.dycore_is('EUL')) then call addfld ('TFIX', horiz_only, 'A', 'K/s', 'T fixer (T equivalent of Energy correction)') end if call addfld ('TTEND_TOT', (/ 'lev' /), 'A', 'K/s', 'Total temperature tendency') @@ -276,8 +255,8 @@ subroutine diag_init_dry(pbuf2d) call addfld ('UU', (/ 'lev' /), 'A', 'm2/s2', 'Zonal velocity squared' ) call addfld ('WSPEED', (/ 'lev' /), 'X', 'm/s', 'Horizontal total wind speed maximum' ) - call addfld ('WSPDSRFMX', horiz_only, 'X', 'm/s', 'Horizontal total wind speed maximum at the surface' ) - call addfld ('WSPDSRFAV', horiz_only, 'A', 'm/s', 'Horizontal total wind speed average at the surface' ) + call addfld ('WSPDSRFMX', horiz_only, 'X', 'm/s', 'Horizontal total wind speed maximum at surface layer midpoint' ) + call addfld ('WSPDSRFAV', horiz_only, 'A', 'm/s', 'Horizontal total wind speed average at surface layer midpoint' ) call addfld ('OMEGA', (/ 'lev' /), 'A', 'Pa/s', 'Vertical velocity (pressure)') call addfld ('OMEGAT', (/ 'lev' /), 'A', 'K Pa/s ', 'Vertical heat flux' ) @@ -386,7 +365,7 @@ subroutine diag_init_dry(pbuf2d) call add_default ('UAP ' , history_budget_histfile_num, ' ') call add_default ('VAP ' , history_budget_histfile_num, ' ') call add_default (apcnst(1) , history_budget_histfile_num, ' ') - if ( dycore_is('LR') .or. dycore_is('SE') .or. dycore_is('FV3') ) then + if (.not.dycore_is('EUL')) then call add_default ('TFIX ' , history_budget_histfile_num, ' ') end if end if @@ -412,22 +391,30 @@ subroutine diag_init_dry(pbuf2d) ! and semidiurnal tide in T, U, V, and Z3 call tidal_diag_init() - ! - ! energy diagnostics - ! - do istage = 1, num_stages - do ivars=1, num_vars - write(str1,*) TRIM(ADJUSTL(vars(ivars))),"_",TRIM(ADJUSTL(stage(istage))) - write(str2,*) TRIM(ADJUSTL(vars_descriptor(ivars)))," ", & - TRIM(ADJUSTL(stage_txt(istage))) - write(str3,*) TRIM(ADJUSTL(vars_unit(ivars))) - call addfld (TRIM(ADJUSTL(str1)), horiz_only, 'A', TRIM(ADJUSTL(str3)),TRIM(ADJUSTL(str2))) - end do - end do - call addfld( 'CPAIRV', (/ 'lev' /), 'I', 'J/K/kg', 'Variable specific heat cap air' ) call addfld( 'RAIRV', (/ 'lev' /), 'I', 'J/K/kg', 'Variable dry air gas constant' ) + if (thermo_budget_history) then + ! + ! energy diagnostics addflds for vars_stage combinations plus e_m_snapshots + ! + do istage = 1, num_stages + call cam_budget_em_snapshot(TRIM(ADJUSTL(stage(istage))),'phy',longname=TRIM(ADJUSTL(stage_txt(istage)))) + end do + + ! Create budgets that are a sum/dif of 2 stages + + call cam_budget_em_register('dEdt_param_efix_physE','phAP','phBF','phy','dif',longname='dE/dt CAM physics + energy fixer using physics E formula (phAP-phBF)') + call cam_budget_em_register('dEdt_param_efix_dynE' ,'dyAP','dyBF','phy','dif',longname='dE/dt CAM physics + energy fixer using dycore E formula (dyAP-dyBF)') + call cam_budget_em_register('dEdt_param_physE' ,'phAP','phBP','phy','dif',longname='dE/dt CAM physics using physics E formula (phAP-phBP)') + call cam_budget_em_register('dEdt_param_dynE' ,'dyAP','dyBP','phy','dif',longname='dE/dt CAM physics using dycore E (dyAP-dyBP)') + call cam_budget_em_register('dEdt_dme_adjust_physE','phAM','phAP','phy','dif',longname='dE/dt dry mass adjustment using physics E formula (phAM-phAP)') + call cam_budget_em_register('dEdt_dme_adjust_dynE' ,'dyAM','dyAP','phy','dif',longname='dE/dt dry mass adjustment using dycore E (dyAM-dyAP)') + call cam_budget_em_register('dEdt_efix_physE' ,'phBP','phBF','phy','dif',longname='dE/dt energy fixer using physics E formula (phBP-phBF)') + call cam_budget_em_register('dEdt_efix_dynE' ,'dyBP','dyBF','phy','dif',longname='dE/dt energy fixer using dycore E formula (dyBP-dyBF)') + call cam_budget_em_register('dEdt_phys_tot_physE' ,'phAM','phBF','phy','dif',longname='dE/dt physics total using physics E formula (phAM-phBF)') + call cam_budget_em_register('dEdt_phys_tot_dynE' ,'dyAM','dyBF','phy','dif',longname='dE/dt physics total using dycore E (dyAM-dyBF)') + endif end subroutine diag_init_dry subroutine diag_init_moist(pbuf2d) @@ -440,7 +427,7 @@ subroutine diag_init_moist(pbuf2d) type(physics_buffer_desc), pointer, intent(in) :: pbuf2d(:,:) - integer :: k, m + integer :: m integer :: ixcldice, ixcldliq ! constituent indices for cloud liquid and ice water. integer :: ierr ! column burdens for all constituents except water vapor @@ -547,18 +534,6 @@ subroutine diag_init_moist(pbuf2d) if (ixcldice > 0) then call addfld (ptendnam(ixcldice),(/ 'lev' /), 'A', 'kg/kg/s',trim(cnst_name(ixcldice))//' total physics tendency ') end if - if ( dycore_is('LR') .or. dycore_is('FV3') )then - call addfld (dmetendnam( 1),(/ 'lev' /), 'A','kg/kg/s', & - trim(cnst_name( 1))//' dme adjustment tendency (FV) ') - if (ixcldliq > 0) then - call addfld (dmetendnam(ixcldliq),(/ 'lev' /), 'A','kg/kg/s', & - trim(cnst_name(ixcldliq))//' dme adjustment tendency (FV) ') - end if - if (ixcldice > 0) then - call addfld (dmetendnam(ixcldice),(/ 'lev' /), 'A','kg/kg/s', & - trim(cnst_name(ixcldice))//' dme adjustment tendency (FV) ') - end if - end if ! outfld calls in diag_physvar_ic @@ -649,15 +624,6 @@ subroutine diag_init_moist(pbuf2d) if (ixcldice > 0) then call add_default (ptendnam(ixcldice), history_budget_histfile_num, ' ') end if - if ( dycore_is('LR') .or. dycore_is('FV3') )then - call add_default(dmetendnam(1) , history_budget_histfile_num, ' ') - if (ixcldliq > 0) then - call add_default(dmetendnam(ixcldliq), history_budget_histfile_num, ' ') - end if - if (ixcldice > 0) then - call add_default(dmetendnam(ixcldice), history_budget_histfile_num, ' ') - end if - end if if( history_budget_histfile_num > 1 ) then call add_default ('DTCOND ' , history_budget_histfile_num, ' ') end if @@ -753,7 +719,6 @@ subroutine diag_init_moist(pbuf2d) end subroutine diag_init_moist subroutine diag_init(pbuf2d) - use cam_history, only: addfld ! Declare the history fields for which this module contains outfld calls. @@ -934,15 +899,11 @@ subroutine diag_phys_writeout_dry(state, pbuf, p_surf_t) ! Purpose: output dry physics diagnostics ! !----------------------------------------------------------------------- - use physconst, only: gravit, rga, rair, cpair, latvap, rearth, pi, cappa + use physconst, only: gravit, rga, rair, cappa use time_manager, only: get_nstep use interpolate_data, only: vertinterp - use constituent_burden, only: constituent_burden_comp - use co2_cycle, only: c_i, co2_transport - use tidal_diag, only: tidal_diag_write use air_composition, only: cpairv, rairv - !----------------------------------------------------------------------- ! ! Arguments @@ -954,15 +915,9 @@ subroutine diag_phys_writeout_dry(state, pbuf, p_surf_t) !---------------------------Local workspace----------------------------- ! real(r8) :: ftem(pcols,pver) ! temporary workspace - real(r8) :: ftem1(pcols,pver) ! another temporary workspace - real(r8) :: ftem2(pcols,pver) ! another temporary workspace real(r8) :: z3(pcols,pver) ! geo-potential height real(r8) :: p_surf(pcols) ! data interpolated to a pressure surface - real(r8) :: tem2(pcols,pver) ! temporary workspace real(r8) :: timestep(pcols) ! used for outfld call - real(r8) :: esl(pcols,pver) ! saturation vapor pressures - real(r8) :: esi(pcols,pver) ! - real(r8) :: dlon(pcols) ! width of grid cell (meters) real(r8), pointer :: psl(:) ! Sea Level Pressure @@ -1276,8 +1231,7 @@ subroutine diag_phys_writeout_moist(state, pbuf, p_surf_t) ! Purpose: record dynamics variables on physics grid ! !----------------------------------------------------------------------- - use physconst, only: gravit, rga, rair, cpair, latvap, rearth, pi, cappa, & - epsilo, rh2o + use physconst, only: gravit, rga, rair, cpair, latvap, rearth, cappa use interpolate_data, only: vertinterp use constituent_burden, only: constituent_burden_comp use co2_cycle, only: c_i, co2_transport @@ -1294,7 +1248,6 @@ subroutine diag_phys_writeout_moist(state, pbuf, p_surf_t) real(r8) :: ftem(pcols,pver) ! temporary workspace real(r8) :: ftem1(pcols,pver) ! another temporary workspace real(r8) :: ftem2(pcols,pver) ! another temporary workspace - real(r8) :: z3(pcols,pver) ! geo-potential height real(r8) :: p_surf(pcols) ! data interpolated to a pressure surface real(r8) :: p_surf_q1(pcols) ! data interpolated to a pressure surface real(r8) :: p_surf_q2(pcols) ! data interpolated to a pressure surface @@ -1611,7 +1564,6 @@ subroutine diag_conv(state, ztodt, pbuf) ! Output diagnostics associated with all convective processes. ! !----------------------------------------------------------------------- - use physconst, only: cpair use tidal_diag, only: get_tidal_coeffs ! Arguments: @@ -1973,7 +1925,6 @@ subroutine diag_physvar_ic (lchnk, pbuf, cam_out, cam_in) ! !---------------------------Local workspace----------------------------- ! - integer :: k ! indices integer :: itim_old ! indices real(r8), pointer, dimension(:,:) :: cwat_var @@ -2104,7 +2055,7 @@ subroutine diag_phys_tend_writeout_dry(state, pbuf, tend, ztodt) ! Total physics tendency for Temperature ! (remove global fixer tendency from total for FV and SE dycores) - if (dycore_is('LR') .or. dycore_is('SE') .or. dycore_is('FV3') ) then + if (.not.dycore_is('EUL')) then call check_energy_get_integrals( heat_glob_out=heat_glob ) ftem2(:ncol) = heat_glob/cpair call outfld('TFIX', ftem2, pcols, lchnk ) @@ -2144,7 +2095,7 @@ end subroutine diag_phys_tend_writeout_dry !####################################################################### subroutine diag_phys_tend_writeout_moist(state, pbuf, tend, ztodt, & - tmp_q, tmp_cldliq, tmp_cldice, qini, cldliqini, cldiceini) + qini, cldliqini, cldiceini) !--------------------------------------------------------------- ! @@ -2159,9 +2110,6 @@ subroutine diag_phys_tend_writeout_moist(state, pbuf, tend, ztodt, & type(physics_buffer_desc), pointer :: pbuf(:) type(physics_tend ), intent(in) :: tend real(r8), intent(in) :: ztodt ! physics timestep - real(r8), intent(inout) :: tmp_q (pcols,pver) ! As input, holds pre-adjusted tracers (FV) - real(r8), intent(inout) :: tmp_cldliq(pcols,pver) ! As input, holds pre-adjusted tracers (FV) - real(r8), intent(inout) :: tmp_cldice(pcols,pver) ! As input, holds pre-adjusted tracers (FV) real(r8), intent(in) :: qini (pcols,pver) ! tracer fields at beginning of physics real(r8), intent(in) :: cldliqini (pcols,pver) ! tracer fields at beginning of physics real(r8), intent(in) :: cldiceini (pcols,pver) ! tracer fields at beginning of physics @@ -2194,35 +2142,6 @@ subroutine diag_phys_tend_writeout_moist(state, pbuf, tend, ztodt, & end if end if - ! Tendency for dry mass adjustment of q (FV only) - - if (dycore_is('LR') .or. dycore_is('FV3') ) then - tmp_q (:ncol,:pver) = (state%q(:ncol,:pver, 1) - tmp_q (:ncol,:pver))*rtdt - if (ixcldliq > 0) then - tmp_cldliq(:ncol,:pver) = (state%q(:ncol,:pver,ixcldliq) - tmp_cldliq(:ncol,:pver))*rtdt - else - tmp_cldliq(:ncol,:pver) = 0.0_r8 - end if - if (ixcldice > 0) then - tmp_cldice(:ncol,:pver) = (state%q(:ncol,:pver,ixcldice) - tmp_cldice(:ncol,:pver))*rtdt - else - tmp_cldice(:ncol,:pver) = 0.0_r8 - end if - if ( cnst_cam_outfld( 1) ) then - call outfld (dmetendnam( 1), tmp_q , pcols, lchnk) - end if - if (ixcldliq > 0) then - if ( cnst_cam_outfld(ixcldliq) ) then - call outfld (dmetendnam(ixcldliq), tmp_cldliq, pcols, lchnk) - end if - end if - if (ixcldice > 0) then - if ( cnst_cam_outfld(ixcldice) ) then - call outfld (dmetendnam(ixcldice), tmp_cldice, pcols, lchnk) - end if - end if - end if - ! Total physics tendency for moisture and other tracers if ( cnst_cam_outfld( 1) ) then @@ -2247,7 +2166,7 @@ end subroutine diag_phys_tend_writeout_moist !####################################################################### subroutine diag_phys_tend_writeout(state, pbuf, tend, ztodt, & - tmp_q, tmp_cldliq, tmp_cldice, qini, cldliqini, cldiceini) + qini, cldliqini, cldiceini) !--------------------------------------------------------------- ! @@ -2262,9 +2181,6 @@ subroutine diag_phys_tend_writeout(state, pbuf, tend, ztodt, & type(physics_buffer_desc), pointer :: pbuf(:) type(physics_tend ), intent(in) :: tend real(r8), intent(in) :: ztodt ! physics timestep - real(r8) , intent(inout) :: tmp_q (pcols,pver) ! As input, holds pre-adjusted tracers (FV) - real(r8), intent(inout) :: tmp_cldliq(pcols,pver) ! As input, holds pre-adjusted tracers (FV) - real(r8), intent(inout) :: tmp_cldice(pcols,pver) ! As input, holds pre-adjusted tracers (FV) real(r8), intent(in) :: qini (pcols,pver) ! tracer fields at beginning of physics real(r8), intent(in) :: cldliqini (pcols,pver) ! tracer fields at beginning of physics real(r8), intent(in) :: cldiceini (pcols,pver) ! tracer fields at beginning of physics @@ -2274,7 +2190,7 @@ subroutine diag_phys_tend_writeout(state, pbuf, tend, ztodt, & call diag_phys_tend_writeout_dry(state, pbuf, tend, ztodt) if (moist_physics) then call diag_phys_tend_writeout_moist(state, pbuf, tend, ztodt, & - tmp_q, tmp_cldliq, tmp_cldice, qini, cldliqini, cldiceini) + qini, cldliqini, cldiceini) end if end subroutine diag_phys_tend_writeout diff --git a/src/physics/cam/check_energy.F90 b/src/physics/cam/check_energy.F90 index 4e55c3de58..7615f0e432 100644 --- a/src/physics/cam/check_energy.F90 +++ b/src/physics/cam/check_energy.F90 @@ -25,8 +25,8 @@ module check_energy use spmd_utils, only: masterproc use gmean_mod, only: gmean - use physconst, only: gravit, latvap, latice, cpair, rair - use air_composition, only: cpairv, rairv + use physconst, only: gravit, rga, latvap, latice, cpair, rair + use air_composition, only: cpairv, rairv, cp_or_cv_dycore use physics_types, only: physics_state, physics_tend, physics_ptend, physics_ptend_init use constituents, only: cnst_get_ind, pcnst, cnst_name, cnst_get_type_byind use time_manager, only: is_first_step @@ -50,7 +50,7 @@ module check_energy public :: check_tracers_init ! initialize tracer integrals and cumulative boundary fluxes public :: check_tracers_chng ! check changes in integrals against cumulative boundary fluxes - public :: calc_te_and_aam_budgets ! calculate and output total energy and axial angular momentum diagnostics + public :: tot_energy_phys ! calculate and output total energy and axial angular momentum diagnostics ! Private module data @@ -221,7 +221,7 @@ subroutine check_energy_timestep_init(state, tend, pbuf, col_type) use cam_thermo, only: get_hydrostatic_energy use physics_buffer, only: physics_buffer_desc, pbuf_set_field use cam_abortutils, only: endrun - use dyn_tests_utils, only: vc_physics, vc_dycore, vc_height + use dyn_tests_utils, only: vc_physics, vc_dycore, vc_height, vc_dry_pressure use physics_types, only: phys_te_idx, dyn_te_idx !----------------------------------------------------------------------- ! Compute initial values of energy and water integrals, @@ -237,7 +237,6 @@ subroutine check_energy_timestep_init(state, tend, pbuf, col_type) real(r8) :: cp_or_cv(state%psetcols,pver) integer lchnk ! chunk identifier integer ncol ! number of atmospheric columns - integer i,k ! column, level indices !----------------------------------------------------------------------- lchnk = state%lchnk @@ -250,17 +249,17 @@ subroutine check_energy_timestep_init(state, tend, pbuf, col_type) if (state%psetcols == pcols) then cp_or_cv(:,:) = cpairv(:,:,lchnk) else if (state%psetcols > pcols .and. all(cpairv(:,:,lchnk) == cpair)) then - cp_or_cv(:,:) = cpair + cp_or_cv(1:ncol,:) = cpair else call endrun('check_energy_timestep_init: cpairv is not allowed to vary when subcolumns are turned on') end if ! ! CAM physics total energy ! - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),& + call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & - vc_physics, ps = state%ps(1:ncol), phis = state%phis(1:ncol), & + vc_physics, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol),& te = state%te_ini(1:ncol,phys_te_idx), H2O = state%tw_ini(1:ncol,phys_te_idx)) ! ! Dynamical core total energy @@ -269,25 +268,41 @@ subroutine check_energy_timestep_init(state, tend, pbuf, col_type) state%z_ini(:ncol,:) = state%zm(:ncol,:) if (vc_dycore == vc_height) then ! - ! compute cv if vertical coordinate is height: cv = cp - R + ! MPAS specific hydrostatic energy computation (internal energy) ! if (state%psetcols == pcols) then - cp_or_cv(:,:) = cpairv(:,:,lchnk)-rairv(:,:,lchnk) + cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) else - cp_or_cv(:,:) = cpair-rair + cp_or_cv(:ncol,:) = cpair-rair endif - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),& + call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & + state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & + state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & + vc_dycore, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & + z_mid = state%z_ini(1:ncol,:), & + te = state%te_ini(1:ncol,dyn_te_idx), H2O = state%tw_ini(1:ncol,dyn_te_idx)) + else if (vc_dycore == vc_dry_pressure) then + ! + ! SE specific hydrostatic energy (enthalpy) + ! + if (state%psetcols == pcols) then + cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) + else + cp_or_cv(:ncol,:) = cpair + endif + call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & - vc_dycore, ps = state%ps(1:ncol), phis = state%phis(1:ncol), & - z_mid = state%z_ini(1:ncol,:), & + vc_dry_pressure, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & te = state%te_ini(1:ncol,dyn_te_idx), H2O = state%tw_ini(1:ncol,dyn_te_idx)) else + ! + ! dycore energy is the same as physics + ! state%te_ini(1:ncol,dyn_te_idx) = state%te_ini(1:ncol,phys_te_idx) state%tw_ini(1:ncol,dyn_te_idx) = state%tw_ini(1:ncol,phys_te_idx) end if - state%te_cur(:ncol,:) = state%te_ini(:ncol,:) state%tw_cur(:ncol,:) = state%tw_ini(:ncol,:) @@ -309,7 +324,7 @@ end subroutine check_energy_timestep_init subroutine check_energy_chng(state, tend, name, nstep, ztodt, & flx_vap, flx_cnd, flx_ice, flx_sen) use cam_thermo, only: get_hydrostatic_energy - use dyn_tests_utils, only: vc_physics, vc_dycore, vc_height + use dyn_tests_utils, only: vc_physics, vc_dycore, vc_height, vc_dry_pressure use cam_abortutils, only: endrun use physics_types, only: phys_te_idx, dyn_te_idx !----------------------------------------------------------------------- @@ -351,12 +366,16 @@ subroutine check_energy_chng(state, tend, name, nstep, ztodt, & real(r8) :: scaling(state%psetcols,pver) ! scaling for conversion of temperature increment real(r8) :: temp(state%ncol,pver) ! temperature + real(r8) :: se(state%ncol) ! enthalpy or internal energy (J/m2) + real(r8) :: po(state%ncol) ! surface potential or potential energy (J/m2) + real(r8) :: ke(state%ncol) ! kinetic energy (J/m2) + real(r8) :: wv(state%ncol) ! column integrated vapor (kg/m2) + real(r8) :: liq(state%ncol) ! column integrated liquid (kg/m2) + real(r8) :: ice(state%ncol) ! column integrated ice (kg/m2) + integer lchnk ! chunk identifier integer ncol ! number of atmospheric columns - integer i,k ! column, level indices - integer :: ixcldice, ixcldliq ! CLDICE and CLDLIQ indices - integer :: ixrain, ixsnow ! RAINQM and SNOWQM indices - integer :: ixgrau ! GRAUQM index + integer i ! column index !----------------------------------------------------------------------- lchnk = state%lchnk @@ -373,12 +392,12 @@ subroutine check_energy_chng(state, tend, name, nstep, ztodt, & call endrun('check_energy_chng: cpairv is not allowed to vary when subcolumns are turned on') end if - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),& + call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), state%T(1:ncol,1:pver), & - vc_physics, ps = state%ps(1:ncol), phis = state%phis(1:ncol), & - te = te, H2O = tw) - + vc_physics, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & + te = te(1:ncol), H2O = tw(1:ncol), se=se(1:ncol),po=po(1:ncol), & + ke=ke(1:ncol),wv=wv(1:ncol),liq=liq(1:ncol),ice=ice(1:ncol)) ! compute expected values and tendencies do i = 1, ncol ! change in static energy and total water @@ -447,20 +466,37 @@ subroutine check_energy_chng(state, tend, name, nstep, ztodt, & ! compute cv if vertical coordinate is height: cv = cp - R ! ! Note: cp_or_cv set above for pressure coordinate - ! if (state%psetcols == pcols) then - cp_or_cv(:,:) = cpairv(:,:,lchnk)-rairv(:,:,lchnk) + cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) else - cp_or_cv(:,:) = cpair-rair + cp_or_cv(:ncol,:) = cpair-rair endif - scaling(:,:) = cpairv(:,:,lchnk)/cp_or_cv(:,:) !cp/cv scaling - + scaling(:,:) = cpairv(:,:,lchnk)/cp_or_cv(:,:) !cp/cv scaling temp(1:ncol,:) = state%temp_ini(1:ncol,:)+scaling(1:ncol,:)*(state%T(1:ncol,:)-state%temp_ini(1:ncol,:)) - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),& + call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & + state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & + state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), temp(1:ncol,1:pver), & + vc_dycore, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & + z_mid = state%z_ini(1:ncol,:), & + te = state%te_cur(1:ncol,dyn_te_idx), H2O = state%tw_cur(1:ncol,dyn_te_idx)) + else if (vc_dycore == vc_dry_pressure) then + ! + ! SE specific hydrostatic energy + ! + if (state%psetcols == pcols) then + cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) + else + cp_or_cv(:ncol,:) = cpair + endif + ! + ! enthalpy scaling for energy consistency + ! + scaling(:ncol,:) = cpairv(:ncol,:,lchnk)/cp_or_cv_dycore(:ncol,:,lchnk) + temp(1:ncol,:) = state%temp_ini(1:ncol,:)+scaling(1:ncol,:)*(state%T(1:ncol,:)-state%temp_ini(1:ncol,:)) + call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), temp(1:ncol,1:pver), & - vc_dycore, ps = state%ps(1:ncol), phis = state%phis(1:ncol), & - z_mid = state%z_ini(1:ncol,:), & + vc_dry_pressure, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & te = state%te_cur(1:ncol,dyn_te_idx), H2O = state%tw_cur(1:ncol,dyn_te_idx)) else state%te_cur(1:ncol,dyn_te_idx) = te(1:ncol) @@ -472,7 +508,6 @@ end subroutine check_energy_chng subroutine check_energy_gmean(state, pbuf2d, dtime, nstep) use physics_buffer, only : physics_buffer_desc, pbuf_get_field, pbuf_get_chunk - use dyn_tests_utils, only: vc_dycore, vc_height use physics_types, only: dyn_te_idx !----------------------------------------------------------------------- ! Compute global mean total energy of physics input and output states @@ -563,13 +598,11 @@ subroutine check_energy_fix(state, ptend, nstep, eshflx) #endif ! add (-) global mean total energy difference as heating ptend%s(:ncol,:pver) = heat_glob -!!$ write(iulog,*) "chk_fix: heat", state%lchnk, ncol, heat_glob ! compute effective sensible heat flux do i = 1, ncol - eshflx(i) = heat_glob * (state%pint(i,pver+1) - state%pint(i,1)) / gravit + eshflx(i) = heat_glob * (state%pint(i,pver+1) - state%pint(i,1)) * rga end do -!!! if (nstep > 0) write(iulog,*) "heat", heat_glob, eshflx(1) return end subroutine check_energy_fix @@ -624,7 +657,7 @@ subroutine check_tracers_init(state, tracerint) tr = 0._r8 do k = 1, pver do i = 1, ncol - tr(i) = tr(i) + state%q(i,k,m)*trpdel(i,k)/gravit + tr(i) = tr(i) + state%q(i,k,m)*trpdel(i,k)*rga end do end do @@ -687,7 +720,6 @@ subroutine check_tracers_chng(state, tracerint, name, nstep, ztodt, cflx) integer :: m ! tracer index character(len=8) :: tracname ! tracername !----------------------------------------------------------------------- -!!$ if (.true.) return lchnk = state%lchnk ncol = state%ncol @@ -713,7 +745,7 @@ subroutine check_tracers_chng(state, tracerint, name, nstep, ztodt, cflx) tr = 0._r8 do k = 1, pver do i = 1, ncol - tr(i) = tr(i) + state%q(i,k,m)*trpdel(i,k)/gravit + tr(i) = tr(i) + state%q(i,k,m)*trpdel(i,k)*rga end do end do @@ -785,12 +817,16 @@ end subroutine check_tracers_chng !####################################################################### - subroutine calc_te_and_aam_budgets(state, outfld_name_suffix,vc) - use physconst, only: gravit,cpair,pi,rearth,omega - use cam_thermo, only: get_hydrostatic_energy - use cam_history, only: hist_fld_active, outfld - use dyn_tests_utils, only: vc_physics, vc_height + subroutine tot_energy_phys(state, outfld_name_suffix,vc) + use physconst, only: rga,rearth,omega + use cam_thermo, only: get_hydrostatic_energy,thermo_budget_num_vars,thermo_budget_vars, & + wvidx,wlidx,wiidx,seidx,poidx,keidx,moidx,mridx,ttidx,teidx + use cam_history, only: outfld + use dyn_tests_utils, only: vc_physics, vc_height, vc_dry_pressure + use cam_abortutils, only: endrun + use cam_history_support, only: max_fieldname_len + use cam_budget, only: thermo_budget_history !------------------------------Arguments-------------------------------- type(physics_state), intent(inout) :: state @@ -799,6 +835,7 @@ subroutine calc_te_and_aam_budgets(state, outfld_name_suffix,vc) !---------------------------Local storage------------------------------- real(r8) :: se(pcols) ! Dry Static energy (J/m2) + real(r8) :: po(pcols) ! surface potential or potential energy (J/m2) real(r8) :: ke(pcols) ! kinetic energy (J/m2) real(r8) :: wv(pcols) ! column integrated vapor (kg/m2) real(r8) :: liq(pcols) ! column integrated liquid (kg/m2) @@ -817,88 +854,81 @@ subroutine calc_te_and_aam_budgets(state, outfld_name_suffix,vc) integer :: i,k ! column, level indices integer :: vc_loc ! local vertical coordinate variable integer :: ixtt ! test tracer index - character(len=16) :: name_out1,name_out2,name_out3,name_out4,name_out5,name_out6 -!----------------------------------------------------------------------- + character(len=max_fieldname_len) :: name_out(thermo_budget_num_vars) - name_out1 = 'SE_' //trim(outfld_name_suffix) - name_out2 = 'KE_' //trim(outfld_name_suffix) - name_out3 = 'WV_' //trim(outfld_name_suffix) - name_out4 = 'WL_' //trim(outfld_name_suffix) - name_out5 = 'WI_' //trim(outfld_name_suffix) - name_out6 = 'TT_' //trim(outfld_name_suffix) +!----------------------------------------------------------------------- - if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2).or.hist_fld_active(name_out3).or.& - hist_fld_active(name_out4).or.hist_fld_active(name_out5).or.hist_fld_active(name_out6)) then + if (.not.thermo_budget_history) return - lchnk = state%lchnk - ncol = state%ncol + do i=1,thermo_budget_num_vars + name_out(i)=trim(thermo_budget_vars(i))//'_'//trim(outfld_name_suffix) + end do - if (present(vc)) then - vc_loc = vc - else - vc_loc = vc_physics - end if + lchnk = state%lchnk + ncol = state%ncol - if (state%psetcols == pcols) then - if (vc_loc == vc_height) then - ! - ! compute cv if vertical coordinate is height: cv = cp - R - ! - cp_or_cv(:,:) = cpairv(:,:,lchnk)-rairv(:,:,lchnk)!cv - else - cp_or_cv(:,:) = cpairv(:,:,lchnk) !cp - end if - else - call endrun('calc_te_and_aam_budgets: energy diagnostics not implemented/tested for subcolumns') - end if + if (present(vc)) then + vc_loc = vc + else + vc_loc = vc_physics + end if - if (vc_loc == vc_height) then - scaling(:,:) = cpairv(:,:,lchnk)/cp_or_cv(:,:) !cp/cv scaling for temperature increment under constant volume + if (state%psetcols == pcols) then + if (vc_loc == vc_height .or. vc_loc == vc_dry_pressure) then + cp_or_cv(:ncol,:) = cp_or_cv_dycore(:ncol,:,lchnk) else - scaling(:,:) = 1.0_r8 + cp_or_cv(:ncol,:) = cpairv(:ncol,:,lchnk) end if - ! scale accumulated temperature increment for constant volume (otherwise effectively do nothing) - temp(1:ncol,:) = state%temp_ini(1:ncol,:)+scaling(1:ncol,:)*(state%T(1:ncol,:)- state%temp_ini(1:ncol,:)) + else + call endrun('tot_energy_phys: energy diagnostics not implemented/tested for subcolumns') + end if - call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),& - state%pdel(1:ncol,1:pver), cp_or_cv, & - state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), temp(1:ncol,1:pver), & - vc_loc, ps = state%ps(1:ncol), phis = state%phis(1:ncol), & - z_mid = state%z_ini(1:ncol,:), se = se, ke = ke, wv = wv, liq = liq, ice = ice) - - call cnst_get_ind('TT_LW' , ixtt , abort=.false.) - - tt = 0._r8 - if (ixtt > 1) then - if (name_out6 == 'TT_pAM'.or.name_out6 == 'TT_zAM') then - ! - ! after dme_adjust mixing ratios are all wet - ! - do k = 1, pver - do i = 1, ncol - tt_tmp = state%q(i,k,ixtt)*state%pdel(i,k)/gravit - tt (i) = tt(i) + tt_tmp - end do + if (vc_loc == vc_height .or. vc_loc == vc_dry_pressure) then + scaling(:ncol,:) = cpairv(:ncol,:,lchnk)/cp_or_cv(:ncol,:)!scaling for energy consistency + else + scaling(:ncol,:) = 1.0_r8 !internal energy / enthalpy same as CAM physics + end if + ! scale accumulated temperature increment for internal energy / enthalpy consistency + temp(1:ncol,:) = state%temp_ini(1:ncol,:)+scaling(1:ncol,:)*(state%T(1:ncol,:)- state%temp_ini(1:ncol,:)) + call get_hydrostatic_energy(state%q(1:ncol,1:pver,1:pcnst),.true., & + state%pdel(1:ncol,1:pver), cp_or_cv(1:ncol,1:pver), & + state%u(1:ncol,1:pver), state%v(1:ncol,1:pver), temp(1:ncol,1:pver), & + vc_loc, ptop=state%pintdry(1:ncol,1), phis = state%phis(1:ncol), & + z_mid = state%z_ini(1:ncol,:), se = se(1:ncol), & + po = po(1:ncol), ke = ke(1:ncol), wv = wv(1:ncol), liq = liq(1:ncol), & + ice = ice(1:ncol)) + + call cnst_get_ind('TT_LW' , ixtt , abort=.false.) + tt = 0._r8 + if (ixtt > 1) then + if (name_out(ttidx) == 'TT_pAM'.or.name_out(ttidx) == 'TT_zAM') then + ! + ! after dme_adjust mixing ratios are all wet + ! + do k = 1, pver + do i = 1, ncol + tt_tmp = state%q(i,k,ixtt)*state%pdel(i,k)*rga + tt (i) = tt(i) + tt_tmp end do - else - do k = 1, pver - do i = 1, ncol - tt_tmp = state%q(i,k,ixtt)*state%pdeldry(i,k)/gravit - tt (i) = tt(i) + tt_tmp - end do + end do + else + do k = 1, pver + do i = 1, ncol + tt_tmp = state%q(i,k,ixtt)*state%pdeldry(i,k)*rga + tt (i) = tt(i) + tt_tmp end do - end if + end do end if - - ! Output energy diagnostics - - call outfld(name_out1 ,se , pcols ,lchnk ) - call outfld(name_out2 ,ke , pcols ,lchnk ) - call outfld(name_out3 ,wv , pcols ,lchnk ) - call outfld(name_out4 ,liq , pcols ,lchnk ) - call outfld(name_out5 ,ice , pcols ,lchnk ) - call outfld(name_out6 ,tt , pcols ,lchnk ) end if + + call outfld(name_out(seidx) ,se , pcols ,lchnk ) + call outfld(name_out(poidx) ,po , pcols ,lchnk ) + call outfld(name_out(keidx) ,ke , pcols ,lchnk ) + call outfld(name_out(wvidx) ,wv , pcols ,lchnk ) + call outfld(name_out(wlidx) ,liq , pcols ,lchnk ) + call outfld(name_out(wiidx) ,ice , pcols ,lchnk ) + call outfld(name_out(ttidx) ,tt , pcols ,lchnk ) + call outfld(name_out(teidx) ,se+ke+po, pcols ,lchnk ) ! ! Axial angular momentum diagnostics ! @@ -912,32 +942,27 @@ subroutine calc_te_and_aam_budgets(state, outfld_name_suffix,vc) ! MR is equation (6) without \Delta A and sum over areas (areas are in units of radians**2) ! MO is equation (7) without \Delta A and sum over areas (areas are in units of radians**2) ! - name_out1 = 'MR_' //trim(outfld_name_suffix) - name_out2 = 'MO_' //trim(outfld_name_suffix) - - if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2)) then - lchnk = state%lchnk - ncol = state%ncol - - mr_cnst = rearth**3/gravit - mo_cnst = omega*rearth**4/gravit - - mr = 0.0_r8 - mo = 0.0_r8 - do k = 1, pver - do i = 1, ncol + + mr_cnst = rga*rearth**3 + mo_cnst = rga*omega*rearth**4 + + mr = 0.0_r8 + mo = 0.0_r8 + do k = 1, pver + do i = 1, ncol cos_lat = cos(state%lat(i)) mr_tmp = mr_cnst*state%u(i,k)*state%pdel(i,k)*cos_lat mo_tmp = mo_cnst*state%pdel(i,k)*cos_lat**2 - + mr(i) = mr(i) + mr_tmp mo(i) = mo(i) + mo_tmp - end do - end do - call outfld(name_out1 ,mr, pcols,lchnk ) - call outfld(name_out2 ,mo, pcols,lchnk ) - end if - end subroutine calc_te_and_aam_budgets + end do + end do + + call outfld(name_out(mridx) ,mr, pcols,lchnk ) + call outfld(name_out(moidx) ,mo, pcols,lchnk ) + + end subroutine tot_energy_phys end module check_energy diff --git a/src/physics/cam/clubb_intr.F90 b/src/physics/cam/clubb_intr.F90 index 8a9c35bfd2..07444cbfa3 100644 --- a/src/physics/cam/clubb_intr.F90 +++ b/src/physics/cam/clubb_intr.F90 @@ -17,23 +17,24 @@ module clubb_intr ! ! !----------------------------------------------------------------------------------------------------- ! - use shr_kind_mod, only: r8=>shr_kind_r8 - use ppgrid, only: pver, pverp, pcols, begchunk, endchunk - use phys_control, only: phys_getopts - use physconst, only: cpair, gravit, rga, latvap, latice, zvir, rh2o, karman - use air_composition, only: rairv, cpairv - - use spmd_utils, only: masterproc - use constituents, only: pcnst, cnst_add - use pbl_utils, only: calc_ustar, calc_obklen - use ref_pres, only: top_lev => trop_cloud_top_lev - use zm_conv_intr, only: zmconv_microp + use shr_kind_mod, only: r8=>shr_kind_r8 + use ppgrid, only: pver, pverp, pcols, begchunk, endchunk + use phys_control, only: phys_getopts + use physconst, only: cpair, gravit, rga, latvap, latice, zvir, rh2o, karman + use air_composition, only: rairv, cpairv + use cam_history_support, only: max_fieldname_len + + use spmd_utils, only: masterproc + use constituents, only: pcnst, cnst_add + use pbl_utils, only: calc_ustar, calc_obklen + use ref_pres, only: top_lev => trop_cloud_top_lev + use zm_conv_intr, only: zmconv_microp #ifdef CLUBB_SGS - use clubb_api_module, only: pdf_parameter, implicit_coefs_terms - use clubb_api_module, only: clubb_config_flags_type, grid, stats, nu_vertical_res_dep - use clubb_api_module, only: nparams - use clubb_mf, only: do_clubb_mf, do_clubb_mf_diag - use cloud_fraction, only: dp1, dp2 + use clubb_api_module, only: pdf_parameter, implicit_coefs_terms + use clubb_api_module, only: clubb_config_flags_type, grid, stats, nu_vertical_res_dep + use clubb_api_module, only: nparams + use clubb_mf, only: do_clubb_mf, do_clubb_mf_diag + use cloud_fraction, only: dp1, dp2 #endif implicit none @@ -4305,7 +4306,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & temp1 = trim(stats_zt(1)%file%grid_avg_var(j)%name) sub = temp1 - if (len(temp1) > 16) sub = temp1(1:16) + if (len(temp1) > max_fieldname_len) sub = temp1(1:max_fieldname_len) call outfld(trim(sub), out_zt(:,:,j), pcols, lchnk ) enddo @@ -4314,7 +4315,7 @@ subroutine clubb_tend_cam( state, ptend_all, pbuf, hdtime, & temp1 = trim(stats_zm(1)%file%grid_avg_var(j)%name) sub = temp1 - if (len(temp1) > 16) sub = temp1(1:16) + if (len(temp1) > max_fieldname_len) sub = temp1(1:max_fieldname_len) call outfld(trim(sub),out_zm(:,:,j), pcols, lchnk) enddo @@ -5020,7 +5021,7 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & temp1 = trim(stats_zt%file%grid_avg_var(i)%name) sub = temp1 - if (len(temp1) > 16) sub = temp1(1:16) + if (len(temp1) > max_fieldname_len) sub = temp1(1:max_fieldname_len) call addfld(trim(sub),(/ 'ilev' /),& 'A',trim(stats_zt%file%grid_avg_var(i)%units),trim(stats_zt%file%grid_avg_var(i)%description)) @@ -5030,7 +5031,7 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, & temp1 = trim(stats_zm%file%grid_avg_var(i)%name) sub = temp1 - if (len(temp1) > 16) sub = temp1(1:16) + if (len(temp1) > max_fieldname_len) sub = temp1(1:max_fieldname_len) call addfld(trim(sub),(/ 'ilev' /),& 'A',trim(stats_zm%file%grid_avg_var(i)%units),trim(stats_zm%file%grid_avg_var(i)%description)) diff --git a/src/physics/cam/constituents.F90 b/src/physics/cam/constituents.F90 index 9d47652318..cda9c82db4 100644 --- a/src/physics/cam/constituents.F90 +++ b/src/physics/cam/constituents.F90 @@ -72,7 +72,6 @@ module constituents character(len=16), public :: fixcnam (pcnst) ! names of species slt fixer tendencies character(len=16), public :: tendnam (pcnst) ! names of total tendencies of species character(len=16), public :: ptendnam (pcnst) ! names of total physics tendencies of species -character(len=16), public :: dmetendnam(pcnst) ! names of dme adjusted tracers (FV) character(len=16), public :: sflxnam (pcnst) ! names of surface fluxes of species character(len=16), public :: tottnam (pcnst) ! names for horz + vert + fixer tendencies @@ -497,7 +496,6 @@ subroutine cnst_chk_dim fixcnam (m) = 'DF'//cnst_name(m) tendnam (m) = 'TE'//cnst_name(m) ptendnam (m) = 'PTE'//cnst_name(m) - dmetendnam(m) = 'DME'//cnst_name(m) tottnam (m) = 'TA'//cnst_name(m) sflxnam(m) = 'SF'//cnst_name(m) end do diff --git a/src/physics/cam/cospsimulator_intr.F90 b/src/physics/cam/cospsimulator_intr.F90 index 7dea97d94e..855a8e82d5 100644 --- a/src/physics/cam/cospsimulator_intr.F90 +++ b/src/physics/cam/cospsimulator_intr.F90 @@ -220,7 +220,7 @@ module cospsimulator_intr ! pbuf indices integer :: cld_idx, concld_idx, lsreffrain_idx, lsreffsnow_idx, cvreffliq_idx integer :: cvreffice_idx, dpcldliq_idx, dpcldice_idx - integer :: shcldliq_idx, shcldice_idx, shcldliq1_idx, shcldice1_idx, dpflxprc_idx + integer :: shcldliq1_idx, shcldice1_idx, dpflxprc_idx integer :: dpflxsnw_idx, shflxprc_idx, shflxsnw_idx, lsflxprc_idx, lsflxsnw_idx integer :: rei_idx, rel_idx @@ -687,7 +687,7 @@ subroutine cospsimulator_intr_init() use mod_cosp_config, only : R_UNDEF integer :: ncid,latid,lonid,did,hrid,minid,secid, istat - integer :: i + integer :: i, ierr ! ISCCP OUTPUTS if (lisccp_sim) then @@ -1164,14 +1164,12 @@ subroutine cospsimulator_intr_init() cvreffice_idx = pbuf_get_index('CV_REFFICE') dpcldliq_idx = pbuf_get_index('DP_CLDLIQ') dpcldice_idx = pbuf_get_index('DP_CLDICE') - shcldliq_idx = pbuf_get_index('SH_CLDLIQ') - shcldice_idx = pbuf_get_index('SH_CLDICE') shcldliq1_idx = pbuf_get_index('SH_CLDLIQ1') shcldice1_idx = pbuf_get_index('SH_CLDICE1') dpflxprc_idx = pbuf_get_index('DP_FLXPRC') dpflxsnw_idx = pbuf_get_index('DP_FLXSNW') - shflxprc_idx = pbuf_get_index('SH_FLXPRC') - shflxsnw_idx = pbuf_get_index('SH_FLXSNW') + shflxprc_idx = pbuf_get_index('SH_FLXPRC', errcode=ierr) + shflxsnw_idx = pbuf_get_index('SH_FLXSNW', errcode=ierr) lsflxprc_idx = pbuf_get_index('LS_FLXPRC') lsflxsnw_idx = pbuf_get_index('LS_FLXSNW') @@ -1411,6 +1409,7 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn real(r8), pointer, dimension(:,:) :: cv_reffice ! convective cld ice effective drop size (microns) !! precip flux pointers (use for cam4 or cam5) + real(r8), target, dimension(pcols,pverp) :: zero_ifc ! zero array for interface fields not in the pbuf ! Added pointers; pbuff in zm_conv_intr.F90, calc in zm_conv.F90 real(r8), pointer, dimension(:,:) :: dp_flxprc ! deep interface gbm flux_convective_cloud_rain+snow (kg m^-2 s^-1) real(r8), pointer, dimension(:,:) :: dp_flxsnw ! deep interface gbm flux_convective_cloud_snow (kg m^-2 s^-1) @@ -1567,6 +1566,8 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn lchnk = state%lchnk ! state variable contains a number of columns, one chunk ncol = state%ncol ! number of columns in the chunk + zero_ifc = 0._r8 + ! Initialize temporary variables as R_UNDEF - need to do this otherwise array expansion puts garbage in history ! file for columns over which COSP did make calculations. tmp(1:pcols) = R_UNDEF @@ -1807,8 +1808,16 @@ subroutine cospsimulator_intr_run(state,pbuf, cam_in,emis,coszrs,cld_swtau_in,sn !! precipitation fluxes (use for both cam4 and cam5 for now....) call pbuf_get_field(pbuf, dpflxprc_idx, dp_flxprc ) call pbuf_get_field(pbuf, dpflxsnw_idx, dp_flxsnw ) - call pbuf_get_field(pbuf, shflxprc_idx, sh_flxprc ) - call pbuf_get_field(pbuf, shflxsnw_idx, sh_flxsnw ) + if (shflxprc_idx > 0) then + call pbuf_get_field(pbuf, shflxprc_idx, sh_flxprc ) + else + sh_flxprc => zero_ifc + end if + if (shflxsnw_idx > 0) then + call pbuf_get_field(pbuf, shflxsnw_idx, sh_flxsnw ) + else + sh_flxsnw => zero_ifc + end if call pbuf_get_field(pbuf, lsflxprc_idx, ls_flxprc ) call pbuf_get_field(pbuf, lsflxsnw_idx, ls_flxsnw ) diff --git a/src/physics/cam/geopotential.F90 b/src/physics/cam/geopotential.F90 index b06b145e51..93e99644ac 100644 --- a/src/physics/cam/geopotential.F90 +++ b/src/physics/cam/geopotential.F90 @@ -20,102 +20,9 @@ module geopotential private save - public geopotential_dse public geopotential_t contains -!=============================================================================== - subroutine geopotential_dse( & - piln , pmln , pint , pmid , pdel , rpdel , & - dse , q , phis , rair , gravit , cpair , & - zvir , t , zi , zm , ncol ) -!----------------------------------------------------------------------- -! -! Purpose: -! Compute the temperature and geopotential height (above the surface) at the -! midpoints and interfaces from the input dry static energy and pressures. -! -!----------------------------------------------------------------------- -!------------------------------Arguments-------------------------------- -! -! Input arguments - integer, intent(in) :: ncol ! Number of longitudes - - ! rair, and cpair are passed in as slices of rank 3 arrays allocated - ! at runtime. Don't specify size to avoid temporary copy. - real(r8), intent(in) :: piln (:,:) ! (pcols,pverp) - Log interface pressures - real(r8), intent(in) :: pmln (:,:) ! (pcols,pver) - Log midpoint pressures - real(r8), intent(in) :: pint (:,:) ! (pcols,pverp) - Interface pressures - real(r8), intent(in) :: pmid (:,:) ! (pcols,pver) - Midpoint pressures - real(r8), intent(in) :: pdel (:,:) ! (pcols,pver) - layer thickness - real(r8), intent(in) :: rpdel(:,:) ! (pcols,pver) - inverse of layer thickness - real(r8), intent(in) :: dse (:,:) ! (pcols,pver) - dry static energy - real(r8), intent(in) :: q (:,:) ! (pcols,pver) - specific humidity - real(r8), intent(in) :: phis (:) ! (pcols) - surface geopotential - real(r8), intent(in) :: rair (:,:) ! - Gas constant for dry air - real(r8), intent(in) :: gravit ! - Acceleration of gravity - real(r8), intent(in) :: cpair(:,:) ! - specific heat at constant p for dry air - real(r8), intent(in) :: zvir (:,:) ! (pcols,pver) - rh2o/rair - 1 - -! Output arguments - - real(r8), intent(out) :: t(:,:) ! (pcols,pver) - temperature - real(r8), intent(out) :: zi(:,:) ! (pcols,pverp) - Height above surface at interfaces - real(r8), intent(out) :: zm(:,:) ! (pcols,pver) - Geopotential height at mid level -! -!---------------------------Local variables----------------------------------------- -! - logical :: calc1 ! switch for calculation method - integer :: i,k ! Lon, level, level indices - real(r8) :: hkk(ncol) ! diagonal element of hydrostatic matrix - real(r8) :: hkl(ncol) ! off-diagonal element - real(r8) :: rog(ncol,pver) ! Rair / gravit - real(r8) :: tv ! virtual temperature - real(r8) :: tvfac ! Tv/T -! -!---------------------------------------------------------------------------------- - rog(:ncol,:) = rair(:ncol,:) / gravit - -! set calculation method based on dycore type - calc1 = dycore_is ('LR').or.dycore_is('FV3') - -! The surface height is zero by definition. - do i = 1,ncol - zi(i,pverp) = 0.0_r8 - end do - -! Compute the virtual temperature, zi, zm from bottom up -! Note, zi(i,k) is the interface above zm(i,k) - do k = pver, 1, -1 - -! First set hydrostatic elements consistent with dynamics - if (calc1) then - do i = 1,ncol - hkl(i) = piln(i,k+1) - piln(i,k) - hkk(i) = 1._r8 - pint(i,k) * hkl(i) * rpdel(i,k) - end do - else - do i = 1,ncol - hkl(i) = pdel(i,k) / pmid(i,k) - hkk(i) = 0.5_r8 * hkl(i) - end do - end if - -! Now compute tv, t, zm, zi - do i = 1,ncol - tvfac = 1._r8 + zvir(i,k) * q(i,k) - tv = (dse(i,k) - phis(i) - gravit*zi(i,k+1)) / ((cpair(i,k) / tvfac) + & - rair(i,k)*hkk(i)) - - t (i,k) = tv / tvfac - - zm(i,k) = zi(i,k+1) + rog(i,k) * tv * hkk(i) - zi(i,k) = zi(i,k+1) + rog(i,k) * tv * hkl(i) - end do - end do - - return - end subroutine geopotential_dse !=============================================================================== subroutine geopotential_t( & @@ -132,7 +39,7 @@ subroutine geopotential_t( & !----------------------------------------------------------------------- use ppgrid, only : pcols - +use air_composition, only: thermodynamic_active_species_num,thermodynamic_active_species_idx !------------------------------Arguments-------------------------------- ! ! Input arguments @@ -146,7 +53,7 @@ subroutine geopotential_t( & real(r8), intent(in) :: pdel (:,:) ! (pcols,pver) - layer thickness real(r8), intent(in) :: rpdel(:,:) ! (pcols,pver) - inverse of layer thickness real(r8), intent(in) :: t (:,:) ! (pcols,pver) - temperature - real(r8), intent(in) :: q (:,:) ! (pcols,pver) - specific humidity + real(r8), intent(in) :: q (:,:,:) ! (pcols,pver,:)- tracers (moist mixing ratios) real(r8), intent(in) :: rair (:,:) ! (pcols,pver) - Gas constant for dry air real(r8), intent(in) :: gravit ! - Acceleration of gravity real(r8), intent(in) :: zvir (:,:) ! (pcols,pver) - rh2o/rair - 1 @@ -158,12 +65,15 @@ subroutine geopotential_t( & ! !---------------------------Local variables----------------------------- ! - integer :: i,k ! Lon, level indices + integer :: i,k,idx ! Lon, level indices, water species index real(r8) :: hkk(ncol) ! diagonal element of hydrostatic matrix real(r8) :: hkl(ncol) ! off-diagonal element real(r8) :: rog(ncol,pver) ! Rair / gravit real(r8) :: tv ! virtual temperature real(r8) :: tvfac ! Tv/T + real(r8) :: qfac(ncol,pver) ! factor to convert from wet to dry mixing ratio + real(r8) :: sum_dry_mixing_ratio(ncol,pver)! sum of dry water mixing ratios + ! !----------------------------------------------------------------------- ! @@ -175,40 +85,105 @@ subroutine geopotential_t( & zi(i,pverp) = 0.0_r8 end do -! Compute zi, zm from bottom up. -! Note, zi(i,k) is the interface above zm(i,k) - - do k = pver, 1, -1 - -! First set hydrostatic elements consistent with dynamics - - if ((dycore_is('LR') .or. dycore_is('FV3'))) then + ! Compute zi, zm from bottom up. + ! Note, zi(i,k) is the interface above zm(i,k) + + ! + ! original code for backwards compatability with FV and EUL + ! + if (.not.(dycore_is('MPAS') .or. dycore_is('SE'))) then + do k = pver, 1, -1 + + ! First set hydrostatic elements consistent with dynamics + + if ((dycore_is('LR') .or. dycore_is('FV3'))) then + do i = 1,ncol + hkl(i) = piln(i,k+1) - piln(i,k) + hkk(i) = 1._r8 - pint(i,k) * hkl(i) * rpdel(i,k) + end do + else + do i = 1,ncol + hkl(i) = pdel(i,k) / pmid(i,k) + hkk(i) = 0.5_r8 * hkl(i) + end do + end if + + ! Now compute tv, zm, zi + do i = 1,ncol - hkl(i) = piln(i,k+1) - piln(i,k) - hkk(i) = 1._r8 - pint(i,k) * hkl(i) * rpdel(i,k) + tvfac = 1._r8 + zvir(i,k) * q(i,k,1) + tv = t(i,k) * tvfac + + zm(i,k) = zi(i,k+1) + rog(i,k) * tv * hkk(i) + zi(i,k) = zi(i,k+1) + rog(i,k) * tv * hkl(i) + end do + end do + else + ! + ! For the computation of generalized virtual temperature (equation 16 + ! in Lauritzen et al. (2018); https://doi.org/10.1029/2017MS001257) + ! + ! Compute factor for converting wet to dry mixing ratio (eq.7) + ! + qfac = 1.0_r8 + do idx = 1,thermodynamic_active_species_num + do k = 1,pver + do i = 1,ncol + qfac(i,k) = qfac(i,k)-q(i,k,thermodynamic_active_species_idx(idx)) + end do + end do + end do + qfac = 1.0_r8/qfac + + ! Compute sum of dry water mixing ratios + sum_dry_mixing_ratio = 1.0_r8 + do idx = 1,thermodynamic_active_species_num + do k = 1,pver + do i = 1,ncol + sum_dry_mixing_ratio(i,k) = sum_dry_mixing_ratio(i,k)& + +q(i,k,thermodynamic_active_species_idx(idx))*qfac(i,k) + end do end do - else!MPAS, SE or EUL + end do + sum_dry_mixing_ratio(:,:) = 1.0_r8/sum_dry_mixing_ratio(:,:) + ! Compute zi, zm from bottom up. + ! Note, zi(i,k) is the interface above zm(i,k) + do k = pver, 1, -1 + + ! First set hydrostatic elements consistent with dynamics + ! - ! For EUL and SE: pmid = 0.5*(pint(k+1)+pint(k)) - ! For MPAS : pmid is computed from theta_m, rhodry, etc. + ! the outcommented code is left for when/if we will support + ! FV3 and/or FV with condensate loading ! + +! if ((dycore_is('LR') .or. dycore_is('FV3'))) then +! do i = 1,ncol +! hkl(i) = piln(i,k+1) - piln(i,k) +! hkk(i) = 1._r8 - pint(i,k) * hkl(i) * rpdel(i,k) +! end do +! else!MPAS, SE or EUL + ! + ! For SE : pmid = 0.5*(pint(k+1)+pint(k)) + ! For MPAS : pmid is computed from theta_m, rhodry, etc. + ! + do i = 1,ncol + hkl(i) = pdel(i,k) / pmid(i,k) + hkk(i) = 0.5_r8 * hkl(i) + end do +! end if + + ! Now compute tv, zm, zi + do i = 1,ncol - hkl(i) = pdel(i,k) / pmid(i,k) - hkk(i) = 0.5_r8 * hkl(i) - end do - end if - -! Now compute tv, zm, zi - - do i = 1,ncol - tvfac = 1._r8 + zvir(i,k) * q(i,k) + tvfac = (1._r8 + (zvir(i,k)+1.0_r8) * q(i,k,1)*qfac(i,k))*sum_dry_mixing_ratio(i,k) tv = t(i,k) * tvfac - + zm(i,k) = zi(i,k+1) + rog(i,k) * tv * hkk(i) zi(i,k) = zi(i,k+1) + rog(i,k) * tv * hkl(i) - end do - end do - + end do + end do + end if return end subroutine geopotential_t end module geopotential diff --git a/src/physics/cam/hetfrz_classnuc.F90 b/src/physics/cam/hetfrz_classnuc.F90 index f0afa46525..effb978718 100644 --- a/src/physics/cam/hetfrz_classnuc.F90 +++ b/src/physics/cam/hetfrz_classnuc.F90 @@ -9,11 +9,11 @@ module hetfrz_classnuc ! hetfrz_classnuc_init ! hetfrz_classnuc_calc ! -! Author: +! Author: ! Corinna Hoose, UiO, May 2009 -! Yong Wang and Xiaohong Liu, UWyo, 12/2012, +! Yong Wang and Xiaohong Liu, UWyo, 12/2012, ! implement in CAM5 and constrain uncertain parameters using natural dust and -! BC(soot) datasets. +! BC(soot) datasets. ! Yong Wang and Xiaohong Liu, UWyo, 05/2013, implement the PDF-contact angle ! approach: Y. Wang et al., Atmos. Chem. Phys., 2014. ! Jack Chen, NCAR, 09/2015, modify calculation of dust activation fraction. @@ -39,7 +39,7 @@ module hetfrz_classnuc real(r8) :: pi !***************************************************************************** -! PDF theta model +! PDF theta model !***************************************************************************** ! some variables for PDF theta model ! immersion freezing @@ -64,13 +64,16 @@ module hetfrz_classnuc integer :: iulog +real(r8) :: limfacbc = -huge(1._r8) ! soot ice nucleating fraction +real(r8) :: limfacdst = -huge(1._r8) ! dust ice nucleating fraction + !=================================================================================================== contains !=================================================================================================== subroutine hetfrz_classnuc_init( & rair_in, cpair_in, rh2o_in, rhoh2o_in, mwh2o_in, & - tmelt_in, pi_in, iulog_in) + tmelt_in, pi_in, iulog_in, bc_limfac_in, dust_limfac_in) real(r8), intent(in) :: rair_in real(r8), intent(in) :: cpair_in @@ -80,6 +83,8 @@ subroutine hetfrz_classnuc_init( & real(r8), intent(in) :: tmelt_in real(r8), intent(in) :: pi_in integer, intent(in) :: iulog_in + real(r8), intent(in) :: bc_limfac_in + real(r8), intent(in) :: dust_limfac_in rair = rair_in cpair = cpair_in @@ -89,6 +94,8 @@ subroutine hetfrz_classnuc_init( & tmelt = tmelt_in pi = pi_in iulog = iulog_in + limfacbc = bc_limfac_in + limfacdst = dust_limfac_in ! Initialize all the PDF theta variables: if (pdf_imm_in) then @@ -150,48 +157,47 @@ subroutine hetfrz_classnuc_calc( & logical :: do_bc, do_dst1, do_dst3 real(r8), parameter :: n1 = 1.e19_r8 ! number of water molecules in contact with unit area of substrate [m-2] - real(r8), parameter :: kboltz = 1.38e-23_r8 + real(r8), parameter :: kboltz = 1.38e-23_r8 real(r8), parameter :: hplanck = 6.63e-34_r8 real(r8), parameter :: rhplanck = 1._r8/hplanck - real(r8), parameter :: amu = 1.66053886e-27_r8 - real(r8), parameter :: nus = 1.e13_r8 ! frequ. of vibration [s-1] higher freq. (as in P&K, consistent with Anupam's data) + real(r8), parameter :: amu = 1.66053886e-27_r8 + real(r8), parameter :: nus = 1.e13_r8 ! frequ. of vibration [s-1] higher freq. (as in P&K, consistent with Anupam's data) real(r8), parameter :: taufrz = 195.435_r8 ! time constant for falloff of freezing rate [s] real(r8), parameter :: rhwincloud = 0.98_r8 ! 98% RH in mixed-phase clouds (Korolev & Isaac, JAS 2006) - real(r8), parameter :: limfacbc = 0.01_r8 ! max. ice nucleating fraction soot - real(r8) :: tc - real(r8) :: vwice - real(r8) :: rhoice - real(r8) :: sigma_iw ! [J/m2] - real(r8) :: sigma_iv ! [J/m2] - real(r8) :: esice ! [Pa] - real(r8) :: eswtr ! [Pa] - real(r8) :: rgimm - real(r8) :: rgdep - real(r8) :: dg0dep - real(r8) :: Adep - real(r8) :: dg0cnt - real(r8) :: Acnt - real(r8) :: rgimm_bc - real(r8) :: rgimm_dust_a1, rgimm_dust_a3 - real(r8) :: dg0imm_bc - real(r8) :: dg0imm_dust_a1, dg0imm_dust_a3 + real(r8) :: tc + real(r8) :: vwice + real(r8) :: rhoice + real(r8) :: sigma_iw ! [J/m2] + real(r8) :: sigma_iv ! [J/m2] + real(r8) :: esice ! [Pa] + real(r8) :: eswtr ! [Pa] + real(r8) :: rgimm + real(r8) :: rgdep + real(r8) :: dg0dep + real(r8) :: Adep + real(r8) :: dg0cnt + real(r8) :: Acnt + real(r8) :: rgimm_bc + real(r8) :: rgimm_dust_a1, rgimm_dust_a3 + real(r8) :: dg0imm_bc + real(r8) :: dg0imm_dust_a1, dg0imm_dust_a3 real(r8) :: Aimm_bc real(r8) :: Aimm_dust_a1, Aimm_dust_a3 - real(r8) :: q, m, phi - real(r8) :: r_bc ! model radii of BC modes [m] - real(r8) :: r_dust_a1, r_dust_a3 ! model radii of dust modes [m] - real(r8) :: f_imm_bc - real(r8) :: f_imm_dust_a1, f_imm_dust_a3 + real(r8) :: q, m, phi + real(r8) :: r_bc ! model radii of BC modes [m] + real(r8) :: r_dust_a1, r_dust_a3 ! model radii of dust modes [m] + real(r8) :: f_imm_bc + real(r8) :: f_imm_dust_a1, f_imm_dust_a3 real(r8) :: Jimm_bc real(r8) :: Jimm_dust_a1, Jimm_dust_a3 - real(r8) :: f_dep_bc - real(r8) :: f_dep_dust_a1, f_dep_dust_a3 - real(r8) :: Jdep_bc - real(r8) :: Jdep_dust_a1, Jdep_dust_a3 - real(r8) :: f_cnt_bc - real(r8) :: f_cnt_dust_a1,f_cnt_dust_a3 + real(r8) :: f_dep_bc + real(r8) :: f_dep_dust_a1, f_dep_dust_a3 + real(r8) :: Jdep_bc + real(r8) :: Jdep_dust_a1, Jdep_dust_a3 + real(r8) :: f_cnt_bc + real(r8) :: f_cnt_dust_a1,f_cnt_dust_a3 real(r8) :: Jcnt_bc - real(r8) :: Jcnt_dust_a1,Jcnt_dust_a3 + real(r8) :: Jcnt_dust_a1,Jcnt_dust_a3 integer :: i !******************************************************** @@ -245,9 +251,9 @@ subroutine hetfrz_classnuc_calc( & sigma_iv = (76.1_r8-0.155_r8*tc + 28.5_r8+0.25_r8*tc)*1E-3_r8 ! get mass mean radius - r_bc = hetraer(1) - r_dust_a1 = hetraer(2) - r_dust_a3 = hetraer(3) + r_bc = hetraer(1) + r_dust_a1 = hetraer(2) + r_dust_a3 = hetraer(3) ! calculate collision kernels as a function of environmental parameters and aerosol/droplet sizes call collkernel(t, p, eswtr, rhwincloud, r3lx, & @@ -255,9 +261,9 @@ subroutine hetfrz_classnuc_calc( & r_dust_a1, r_dust_a3, & ! dust modes Kcoll_bc, & ! collision kernel [cm3 s-1] Kcoll_dust_a1, Kcoll_dust_a3) - + !***************************************************************************** - ! take water activity into account + ! take water activity into account !***************************************************************************** ! solute effect aw(:) = 1._r8 @@ -267,9 +273,9 @@ subroutine hetfrz_classnuc_calc( & ! increasing total solute mole fraction. Therefore, the large solution concentration ! will cause the freezing point depression and the ice freezing temperatures of all ! IN will get close to the homogeneous ice freezing temperatures. Since we take into - ! account water activity for three heterogeneous freezing modes(immersion, deposition, - ! and contact), we utilize interstitial aerosols(not cloudborne aerosols) to calculate - ! water activity. + ! account water activity for three heterogeneous freezing modes(immersion, deposition, + ! and contact), we utilize interstitial aerosols(not cloudborne aerosols) to calculate + ! water activity. ! If the index of IN is 0, it means three freezing modes of this aerosol are depressed. do i = 1, 3 @@ -282,8 +288,8 @@ subroutine hetfrz_classnuc_calc( & end do !***************************************************************************** - ! immersion freezing begin - !***************************************************************************** + ! immersion freezing begin + !***************************************************************************** frzbcimm = 0._r8 frzduimm = 0._r8 @@ -321,7 +327,7 @@ subroutine hetfrz_classnuc_calc( & else do_dst3 = .false. end if - + ! form factor ! only consider flat surfaces due to uncertainty of curved surfaces @@ -352,7 +358,7 @@ subroutine hetfrz_classnuc_calc( & ! 1/sqrt(f) ! the expression of Chen et al. (sqrt(f)) may however lead to unphysical ! behavior as it implies J->0 when f->0 (i.e. ice nucleation would be - ! more difficult on easily wettable materials). + ! more difficult on easily wettable materials). Jimm_dust_a1 = Aimm_dust_a1*r_dust_a1**2/SQRT(f_imm_dust_a1)*EXP((-dga_imm_dust-f_imm_dust_a1*dg0imm_dust_a1)/(kboltz*T)) Jimm_dust_a3 = Aimm_dust_a3*r_dust_a3**2/SQRT(f_imm_dust_a3)*EXP((-dga_imm_dust-f_imm_dust_a3*dg0imm_dust_a3)/(kboltz*T)) end if @@ -372,7 +378,7 @@ subroutine hetfrz_classnuc_calc( & end do end if - ! Limit to 1% of available potential IN (for BC), no limit for dust + ! Limit to 1% of available potential IN (for BC), no limit for dust if (pdf_imm_in) then sum_imm_dust_a1 = 0._r8 sum_imm_dust_a3 = 0._r8 @@ -390,38 +396,38 @@ subroutine hetfrz_classnuc_calc( & sum_imm_dust_a3 = 1.0_r8 end if end do - + end if if (.not.tot_in) then if (do_bc) frzbcimm = frzbcimm+MIN(limfacbc*total_cloudborne_aer_num(id_bc)/deltat, & - total_cloudborne_aer_num(id_bc)/deltat*(1._r8-exp(-Jimm_bc*deltat))) + total_cloudborne_aer_num(id_bc)/deltat*(1._r8-exp(-Jimm_bc*deltat))) if (.not. pdf_imm_in) then - if (do_dst1) frzduimm = frzduimm+MIN(1*total_cloudborne_aer_num(id_dst1)/deltat, & + if (do_dst1) frzduimm = frzduimm+MIN(limfacdst*total_cloudborne_aer_num(id_dst1)/deltat, & total_cloudborne_aer_num(id_dst1)/deltat*(1._r8-exp(-Jimm_dust_a1*deltat))) - if (do_dst3) frzduimm = frzduimm+MIN(1*total_cloudborne_aer_num(id_dst3)/deltat, & + if (do_dst3) frzduimm = frzduimm+MIN(limfacdst*total_cloudborne_aer_num(id_dst3)/deltat, & total_cloudborne_aer_num(id_dst3)/deltat*(1._r8-exp(-Jimm_dust_a3*deltat))) else - if (do_dst1) frzduimm = frzduimm+MIN(1*total_cloudborne_aer_num(id_dst1)/deltat, & + if (do_dst1) frzduimm = frzduimm+MIN(limfacdst*total_cloudborne_aer_num(id_dst1)/deltat, & total_cloudborne_aer_num(id_dst1)/deltat*(1._r8-sum_imm_dust_a1)) - if (do_dst3) frzduimm = frzduimm+MIN(1*total_cloudborne_aer_num(id_dst3)/deltat, & + if (do_dst3) frzduimm = frzduimm+MIN(limfacdst*total_cloudborne_aer_num(id_dst3)/deltat, & total_cloudborne_aer_num(id_dst3)/deltat*(1._r8-sum_imm_dust_a3)) end if else - if (do_bc) frzbcimm = frzbcimm+MIN(limfacbc*fn(id_bc)*total_aer_num(id_bc)/deltat, & - fn(id_bc)*total_aer_num(id_bc)/deltat*(1._r8-exp(-Jimm_bc*deltat))) + if (do_bc) frzbcimm = frzbcimm+MIN(limfacbc*fn(id_bc)*total_aer_num(id_bc)/deltat, & + fn(id_bc)*total_aer_num(id_bc)/deltat*(1._r8-exp(-Jimm_bc*deltat))) if (.not. pdf_imm_in) then - if (do_dst1) frzduimm = frzduimm+MIN(1*fn(id_dst1)*total_aer_num(id_dst1)/deltat, & + if (do_dst1) frzduimm = frzduimm+MIN(limfacdst*fn(id_dst1)*total_aer_num(id_dst1)/deltat, & fn(id_dst1)*total_aer_num(id_dst1)/deltat*(1._r8-exp(-Jimm_dust_a1*deltat))) - if (do_dst3) frzduimm = frzduimm+MIN(1*fn(id_dst3)*total_aer_num(id_dst3)/deltat, & + if (do_dst3) frzduimm = frzduimm+MIN(limfacdst*fn(id_dst3)*total_aer_num(id_dst3)/deltat, & fn(id_dst3)*total_aer_num(id_dst3)/deltat*(1._r8-exp(-Jimm_dust_a3*deltat))) else - if (do_dst1) frzduimm = frzduimm+MIN(1*fn(id_dst1)*total_aer_num(id_dst1)/deltat, & + if (do_dst1) frzduimm = frzduimm+MIN(limfacdst*fn(id_dst1)*total_aer_num(id_dst1)/deltat, & fn(id_dst1)*total_aer_num(id_dst1)/deltat*(1._r8-sum_imm_dust_a1)) - if (do_dst3) frzduimm = frzduimm+MIN(1*fn(id_dst3)*total_aer_num(id_dst3)/deltat, & + if (do_dst3) frzduimm = frzduimm+MIN(limfacdst*fn(id_dst3)*total_aer_num(id_dst3)/deltat, & fn(id_dst3)*total_aer_num(id_dst3)/deltat*(1._r8-sum_imm_dust_a3)) end if end if @@ -436,7 +442,7 @@ subroutine hetfrz_classnuc_calc( & !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! critical germ size ! assume 98% RH in mixed-phase clouds (Korolev & Isaac, JAS 2006) - rgdep=2*vwice*sigma_iv/(kboltz*t*LOG(rhwincloud*supersatice)) + rgdep=2*vwice*sigma_iv/(kboltz*t*LOG(rhwincloud*supersatice)) ! form factor m = COS(theta_dep_bc*pi/180._r8) @@ -466,30 +472,30 @@ subroutine hetfrz_classnuc_calc( & Jdep_dust_a3 = 0._r8 end if - ! Limit to 1% of available potential IN (for BC), no limit for dust + ! Limit available potential IN (for BC and dust) if (.not.tot_in) then if (do_bc) frzbcdep = frzbcdep+MIN(limfacbc*uncoated_aer_num(id_bc)/deltat, & uncoated_aer_num(id_bc)/deltat & - *(1._r8-exp(-Jdep_bc*deltat))) - if (do_dst1) frzdudep = frzdudep+MIN(uncoated_aer_num(id_dst1)/deltat, & + *(1._r8-exp(-Jdep_bc*deltat))) + if (do_dst1) frzdudep = frzdudep+MIN(limfacdst*uncoated_aer_num(id_dst1)/deltat, & uncoated_aer_num(id_dst1)/deltat & *(1._r8-exp(-Jdep_dust_a1*deltat))) - if (do_dst3) frzdudep = frzdudep+MIN(uncoated_aer_num(id_dst3)/deltat, & + if (do_dst3) frzdudep = frzdudep+MIN(limfacdst*uncoated_aer_num(id_dst3)/deltat, & uncoated_aer_num(id_dst3)/deltat & *(1._r8-exp(-Jdep_dust_a3*deltat))) else if (do_bc) frzbcdep = frzbcdep+MIN(limfacbc*(1._r8-fn(id_bc)) & *(1._r8-dstcoat(1))*total_aer_num(id_bc)/deltat, & (1._r8-fn(id_bc))*(1._r8-dstcoat(1))*total_aer_num(id_bc)/deltat & - *(1._r8-exp(-Jdep_bc*deltat))) - if (do_dst1) frzdudep = frzdudep+MIN((1._r8-fn(id_dst1)) & + *(1._r8-exp(-Jdep_bc*deltat))) + if (do_dst1) frzdudep = frzdudep+MIN(limfacdst*(1._r8-fn(id_dst1)) & *(1._r8-dstcoat(2))*total_aer_num(id_dst1)/deltat, & (1._r8-fn(id_dst1))*(1._r8-dstcoat(2))*total_aer_num(id_dst1)/deltat & - *(1._r8-exp(-Jdep_dust_a1*deltat))) - if (do_dst3) frzdudep = frzdudep+MIN((1._r8-fn(id_dst3)) & + *(1._r8-exp(-Jdep_dust_a1*deltat))) + if (do_dst3) frzdudep = frzdudep+MIN(limfacdst*(1._r8-fn(id_dst3)) & *(1._r8-dstcoat(3))*total_aer_num(id_dst3)/deltat, & (1._r8-fn(id_dst3))*(1._r8-dstcoat(3))*total_aer_num(id_dst3)/deltat & - *(1._r8-exp(-Jdep_dust_a3*deltat))) + *(1._r8-exp(-Jdep_dust_a3*deltat))) end if !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -518,31 +524,31 @@ subroutine hetfrz_classnuc_calc( & Jcnt_dust_a1 = Acnt*r_dust_a1**2*EXP((-dga_dep_dust-f_cnt_dust_a1*dg0cnt)/(kboltz*T))*Kcoll_dust_a1*icnlx Jcnt_dust_a3 = Acnt*r_dust_a3**2*EXP((-dga_dep_dust-f_cnt_dust_a3*dg0cnt)/(kboltz*T))*Kcoll_dust_a3*icnlx - ! Limit to 1% of available potential IN (for BC), no limit for dust + ! Limit available potential IN (for BC and dust) if (.not.tot_in) then if (do_bc) frzbccnt = frzbccnt+MIN(limfacbc*uncoated_aer_num(id_bc)/deltat, & uncoated_aer_num(id_bc)/deltat & - *(1._r8-exp(-Jcnt_bc*deltat))) - if (do_dst1) frzducnt = frzducnt+MIN(uncoated_aer_num(id_dst1)/deltat, & + *(1._r8-exp(-Jcnt_bc*deltat))) + if (do_dst1) frzducnt = frzducnt+MIN(limfacdst*uncoated_aer_num(id_dst1)/deltat, & uncoated_aer_num(id_dst1)/deltat & *(1._r8-exp(-Jcnt_dust_a1*deltat))) - if (do_dst3) frzducnt = frzducnt+MIN(uncoated_aer_num(id_dst3)/deltat, & + if (do_dst3) frzducnt = frzducnt+MIN(limfacdst*uncoated_aer_num(id_dst3)/deltat, & uncoated_aer_num(id_dst3)/deltat & *(1._r8-exp(-Jcnt_dust_a3*deltat))) else if (do_bc) frzbccnt = frzbccnt+MIN(limfacbc*(1._r8-fn(id_bc))*(1._r8-dstcoat(1))*total_aer_num(id_bc)/deltat, & (1._r8-fn(id_bc))*(1._r8-dstcoat(1))*total_aer_num(id_bc)/deltat & - *(1._r8-exp(-Jcnt_bc*deltat))) - if (do_dst1) frzducnt = frzducnt+MIN((1._r8-fn(id_dst1))*(1._r8-dstcoat(2))*total_aer_num(id_dst1)/deltat, & + *(1._r8-exp(-Jcnt_bc*deltat))) + if (do_dst1) frzducnt = frzducnt+MIN(limfacdst*(1._r8-fn(id_dst1))*(1._r8-dstcoat(2))*total_aer_num(id_dst1)/deltat, & (1._r8-fn(id_dst1))*(1._r8-dstcoat(2))*total_aer_num(id_dst1)/deltat & *(1._r8-exp(-Jcnt_dust_a1*deltat))) - if (do_dst3) frzducnt = frzducnt+MIN((1._r8-fn(id_dst3))*(1._r8-dstcoat(3))*total_aer_num(id_dst3)/deltat, & + if (do_dst3) frzducnt = frzducnt+MIN(limfacdst*(1._r8-fn(id_dst3))*(1._r8-dstcoat(3))*total_aer_num(id_dst3)/deltat, & (1._r8-fn(id_dst3))*(1._r8-dstcoat(3))*total_aer_num(id_dst3)/deltat & *(1._r8-exp(-Jcnt_dust_a3*deltat))) end if - + if (frzducnt <= -1._r8) then - write(iulog,*) 'hetfrz_classnuc_calc: frzducnt', frzducnt, Jcnt_dust_a1,Jcnt_dust_a3, & + write(iulog,*) 'hetfrz_classnuc_calc: frzducnt', frzducnt, Jcnt_dust_a1,Jcnt_dust_a3, & Kcoll_dust_a1, Kcoll_dust_a3 errstring = 'ERROR in hetfrz_classnuc_calc::frzducnt' return @@ -607,7 +613,7 @@ subroutine collkernel( & real(r8) :: K_total ! total collision kernel [cm3 s-1] integer :: i !------------------------------------------------------------------------------------------------ - + Kcoll_bc = 0._r8 Kcoll_dust_a1 = 0._r8 Kcoll_dust_a3 = 0._r8 @@ -640,11 +646,11 @@ subroutine collkernel( & ! Prandtl number Pr = viscos_air*cpair/Ktherm_air ! water vapor diffusivity: Pruppacher & Klett 13-3 - Dvap = 0.211e-4_r8*(t/273.15_r8)*(101325._r8/pres) + Dvap = 0.211e-4_r8*(t/273.15_r8)*(101325._r8/pres) ! G-factor = rhoh2o*Xi in Rogers & Yau, p. 104 G = rhoh2o/((latvap/(rh2o*t) - 1)*latvap*rhoh2o/(Ktherm_air*t) & + rhoh2o*rh2o*t/(Dvap*eswtr)) - + ! variables depending on aerosol radius ! loop over 3 aerosol modes do i = 1, 3 @@ -680,9 +686,9 @@ subroutine collkernel( & if (i == 1) Kcoll_bc = K_total if (i == 2) Kcoll_dust_a1 = K_total if (i == 3) Kcoll_dust_a3 = K_total - + end do - + end subroutine collkernel !=================================================================================================== diff --git a/src/physics/cam/hetfrz_classnuc_cam.F90 b/src/physics/cam/hetfrz_classnuc_cam.F90 index 83542f0281..9c5794eae7 100644 --- a/src/physics/cam/hetfrz_classnuc_cam.F90 +++ b/src/physics/cam/hetfrz_classnuc_cam.F90 @@ -39,11 +39,12 @@ module hetfrz_classnuc_cam hetfrz_classnuc_cam_readnl, & hetfrz_classnuc_cam_register, & hetfrz_classnuc_cam_init, & - hetfrz_classnuc_cam_calc, & - hetfrz_classnuc_cam_save_cbaero + hetfrz_classnuc_cam_calc ! Namelist variables logical :: hist_hetfrz_classnuc = .false. +real(r8) :: hetfrz_bc_scalfac = -huge(1._r8) ! scaling factor for BC +real(r8) :: hetfrz_dust_scalfac = -huge(1._r8) ! scaling factor for dust ! Vars set via init method. real(r8) :: mincld ! minimum allowed cloud fraction @@ -143,7 +144,7 @@ subroutine hetfrz_classnuc_cam_readnl(nlfile) use namelist_utils, only: find_group_name use units, only: getunit, freeunit - use mpishorthand + use spmd_utils, only: mpicom, mstrid=>masterprocid, mpi_logical, mpi_real8, mpi_success character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input @@ -151,7 +152,7 @@ subroutine hetfrz_classnuc_cam_readnl(nlfile) integer :: unitn, ierr character(len=*), parameter :: subname = 'hetfrz_classnuc_cam_readnl' - namelist /hetfrz_classnuc_nl/ hist_hetfrz_classnuc + namelist /hetfrz_classnuc_nl/ hist_hetfrz_classnuc, hetfrz_bc_scalfac, hetfrz_dust_scalfac !----------------------------------------------------------------------------- @@ -167,13 +168,21 @@ subroutine hetfrz_classnuc_cam_readnl(nlfile) end if close(unitn) call freeunit(unitn) - end if -#ifdef SPMD ! Broadcast namelist variables - call mpibcast(hist_hetfrz_classnuc, 1, mpilog, 0, mpicom) -#endif + call mpi_bcast(hist_hetfrz_classnuc, 1, mpi_logical, mstrid, mpicom, ierr) + if (ierr /= mpi_success) call endrun(subname//" mpi_bcast: hist_hetfrz_classnuc") + call mpi_bcast(hetfrz_bc_scalfac, 1, mpi_real8, mstrid, mpicom, ierr) + if (ierr /= mpi_success) call endrun(subname//" mpi_bcast: hetfrz_bc_scalfac") + call mpi_bcast(hetfrz_dust_scalfac, 1, mpi_real8, mstrid, mpicom, ierr) + if (ierr /= mpi_success) call endrun(subname//" mpi_bcast: hetfrz_dust_scalfac") + + if (masterproc) then + write(iulog,*) subname,': hist_hetfrz_classnuc = ',hist_hetfrz_classnuc + write(iulog,*) subname,': hetfrz_bc_scalfac = ',hetfrz_bc_scalfac + write(iulog,*) subname,': hetfrz_dust_scalfac = ',hetfrz_dust_scalfac + end if end subroutine hetfrz_classnuc_cam_readnl @@ -239,7 +248,7 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) call addfld('bc_c1_num', (/ 'lev' /), 'A', '#/cm3', 'cloud borne bc number') call addfld('dst_c1_num', (/ 'lev' /), 'A', '#/cm3', 'cloud borne dst1 number') call addfld('dst_c3_num', (/ 'lev' /), 'A', '#/cm3', 'cloud borne dst3 number') - + call addfld('fn_bc_c1_num', (/ 'lev' /), 'A', '#/cm3', 'cloud borne bc number derived from fn') call addfld('fn_dst_c1_num', (/ 'lev' /), 'A', '#/cm3', 'cloud borne dst1 number derived from fn') call addfld('fn_dst_c3_num', (/ 'lev' /), 'A', '#/cm3', 'cloud borne dst3 number derived from fn') @@ -306,7 +315,7 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) call add_default('bc_c1_num', 1, ' ') call add_default('dst_c1_num', 1, ' ') call add_default('dst_c3_num', 1, ' ') - + call add_default('fn_bc_c1_num', 1, ' ') call add_default('fn_dst_c1_num', 1, ' ') call add_default('fn_dst_c3_num', 1, ' ') @@ -328,7 +337,7 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) call add_default('BCFREZDEP', 1, ' ') call add_default('NIMIX_IMM', 1, ' ') - call add_default('NIMIX_CNT', 1, ' ') + call add_default('NIMIX_CNT', 1, ' ') call add_default('NIMIX_DEP', 1, ' ') call add_default('DSTNIDEP', 1, ' ') @@ -391,7 +400,7 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) call rad_cnst_get_mode_props(0, mode_accum_idx, sigmag=sigma_logr_aer) alnsg_mode_accum = log(sigma_logr_aer) - + if (nmodes == MAM3_nmodes) then call rad_cnst_get_mode_props(0, mode_coarse_idx, sigmag=sigma_logr_aer) alnsg_mode_coarse = log(sigma_logr_aer) @@ -415,7 +424,7 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) end if ! Set list indices for all constituents (mass and number) used in this module. - ! The list is specific to the aerosol model used. Note that the order of the + ! The list is specific to the aerosol model used. Note that the order of the ! constituents in these lists is arbitrary. if (nmodes == MAM3_nmodes) then @@ -466,7 +475,7 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) num_pcarbon = 14 end if - ! Allocate arrays to hold specie and mode indices for all constitutents (mass and number) + ! Allocate arrays to hold specie and mode indices for all constitutents (mass and number) ! needed in this module. allocate(mode_idx(ncnst), spec_idx(ncnst), stat=istat) call alloc_err(istat, routine, 'mode_idx, spec_idx', ncnst) @@ -545,7 +554,7 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) spec_idx(pom_pcarbon) = rad_cnst_get_spec_idx(0, mode_pcarbon_idx, 'p-organic') mode_idx(pom_pcarbon) = mode_pcarbon_idx end if - + ! Check that all required specie types were found if (any(spec_idx == -1)) then write(iulog,*) routine//': ERROR required species type not found - indicies:', spec_idx @@ -563,9 +572,8 @@ subroutine hetfrz_classnuc_cam_init(mincld_in) call rad_cnst_get_aer_props(0, mode_idx(soa_accum), spec_idx(soa_accum), density_aer=specdens_soa) call rad_cnst_get_aer_props(0, mode_idx(pom_accum), spec_idx(pom_accum), density_aer=specdens_pom) - call hetfrz_classnuc_init( & - rair, cpair, rh2o, rhoh2o, mwh2o, & - tmelt, pi, iulog) + call hetfrz_classnuc_init(rair, cpair, rh2o, rhoh2o, mwh2o, tmelt, pi, iulog, & + hetfrz_bc_scalfac, hetfrz_dust_scalfac ) end subroutine hetfrz_classnuc_cam_init @@ -579,7 +587,7 @@ subroutine hetfrz_classnuc_cam_calc( & real(r8), intent(in) :: deltatin ! time step (s) real(r8), intent(in) :: factnum(:,:,:) ! activation fraction for aerosol number type(physics_buffer_desc), pointer :: pbuf(:) - + ! local workspace ! outputs shared with the microphysics via the pbuf @@ -592,7 +600,7 @@ subroutine hetfrz_classnuc_cam_calc( & real(r8) :: rho(pcols,pver) ! air density (kg m-3) - real(r8), pointer :: ast(:,:) + real(r8), pointer :: ast(:,:) real(r8) :: lcldm(pcols,pver) @@ -611,7 +619,7 @@ subroutine hetfrz_classnuc_cam_calc( & real(r8) :: fn_cloudborne_aer_num(pcols,pver,3) - real(r8) :: esi(pcols), esl(pcols) + real(r8) :: esi(pcols), esl(pcols) real(r8) :: con1, r3lx, supersatice real(r8) :: qcic @@ -664,8 +672,6 @@ subroutine hetfrz_classnuc_cam_calc( & ! Convert interstitial and cloud borne aerosols from a mass to a volume basis before ! being used in get_aer_num do i = 1, ncnst - aer_cb(:ncol,:,i,lchnk) = aer_cb(:ncol,:,i,lchnk) * rho(:ncol,:) - ! Check whether constituent is a mass or number mixing ratio if (spec_idx(i) == 0) then call rad_cnst_get_mode_num(0, mode_idx(i), 'a', state, pbuf, ptr2d) @@ -673,7 +679,15 @@ subroutine hetfrz_classnuc_cam_calc( & call rad_cnst_get_aer_mmr(0, mode_idx(i), spec_idx(i), 'a', state, pbuf, ptr2d) end if aer(:ncol,:,i,lchnk) = ptr2d(:ncol,:) * rho(:ncol,:) - end do + + ! Check whether constituent is a mass or number mixing ratio + if (spec_idx(i) == 0) then + call rad_cnst_get_mode_num(0, mode_idx(i), 'c', state, pbuf, ptr2d) + else + call rad_cnst_get_aer_mmr(0, mode_idx(i), spec_idx(i), 'c', state, pbuf, ptr2d) + end if + aer_cb(:ncol,:,i,lchnk) = ptr2d(:ncol,:) * rho(:ncol,:) + end do ! Init top levels of outputs of get_aer_num total_aer_num = 0._r8 @@ -702,8 +716,8 @@ subroutine hetfrz_classnuc_cam_calc( & fn_cloudborne_aer_num(i,k,2) = total_aer_num(i,k,2)*factnum(i,k,mode_accum_idx) ! dst_a1 fn_cloudborne_aer_num(i,k,3) = total_aer_num(i,k,3)*factnum(i,k,mode_coarse_idx) ! dst_a3 else if (nmodes == MAM7_nmodes) then - fn_cloudborne_aer_num(i,k,2) = total_aer_num(i,k,2)*factnum(i,k,mode_finedust_idx) - fn_cloudborne_aer_num(i,k,3) = total_aer_num(i,k,3)*factnum(i,k,mode_coardust_idx) + fn_cloudborne_aer_num(i,k,2) = total_aer_num(i,k,2)*factnum(i,k,mode_finedust_idx) + fn_cloudborne_aer_num(i,k,3) = total_aer_num(i,k,3)*factnum(i,k,mode_coardust_idx) end if end do end do @@ -731,7 +745,7 @@ subroutine hetfrz_classnuc_cam_calc( & call outfld('fn_bc_c1_num', fn_cloudborne_aer_num(:,:,1), pcols, lchnk) call outfld('fn_dst_c1_num', fn_cloudborne_aer_num(:,:,2), pcols, lchnk) call outfld('fn_dst_c3_num', fn_cloudborne_aer_num(:,:,3), pcols, lchnk) - + call outfld('na500', na500, pcols, lchnk) call outfld('totna500', tot_na500, pcols, lchnk) @@ -739,7 +753,7 @@ subroutine hetfrz_classnuc_cam_calc( & call pbuf_get_field(pbuf, frzimm_idx, frzimm) call pbuf_get_field(pbuf, frzcnt_idx, frzcnt) call pbuf_get_field(pbuf, frzdep_idx, frzdep) - + frzimm(:ncol,:) = 0._r8 frzcnt(:ncol,:) = 0._r8 frzdep(:ncol,:) = 0._r8 @@ -795,8 +809,8 @@ subroutine hetfrz_classnuc_cam_calc( & fn(2) = factnum(i,k,mode_accum_idx) ! dust_a1 accumulation mode fn(3) = factnum(i,k,mode_coarse_idx) ! dust_a3 coarse mode else if (nmodes == MAM7_nmodes) then - fn(2) = factnum(i,k,mode_finedust_idx) - fn(3) = factnum(i,k,mode_coardust_idx) + fn(2) = factnum(i,k,mode_finedust_idx) + fn(3) = factnum(i,k,mode_coardust_idx) end if call hetfrz_classnuc_calc( & @@ -828,7 +842,7 @@ subroutine hetfrz_classnuc_cam_calc( & nnudep_bc(i,k) = frzbcdep(i,k)*1.0e6_r8*ast(i,k) nnuccc_dst(i,k) = frzduimm(i,k)*1.0e6_r8*ast(i,k) - nnucct_dst(i,k) = frzducnt(i,k)*1.0e6_r8*ast(i,k) + nnucct_dst(i,k) = frzducnt(i,k)*1.0e6_r8*ast(i,k) nnudep_dst(i,k) = frzdudep(i,k)*1.0e6_r8*ast(i,k) niimm_bc(i,k) = frzbcimm(i,k)*1.0e6_r8*deltatin @@ -859,7 +873,7 @@ subroutine hetfrz_classnuc_cam_calc( & call outfld('BCFREZDEP', nnudep_bc, pcols, lchnk) call outfld('NIMIX_IMM', niimm_bc+niimm_dst, pcols, lchnk) - call outfld('NIMIX_CNT', nicnt_bc+nicnt_dst, pcols, lchnk) + call outfld('NIMIX_CNT', nicnt_bc+nicnt_dst, pcols, lchnk) call outfld('NIMIX_DEP', nidep_bc+nidep_dst, pcols, lchnk) call outfld('DSTNICNT', nicnt_dst, pcols, lchnk) @@ -880,37 +894,6 @@ end subroutine hetfrz_classnuc_cam_calc !==================================================================================================== -subroutine hetfrz_classnuc_cam_save_cbaero(state, pbuf) - - ! Save the required cloud borne aerosol constituents. - type(physics_state), intent(in) :: state - type(physics_buffer_desc), pointer :: pbuf(:) - - ! local variables - integer :: i, lchnk - real(r8), pointer :: ptr2d(:,:) - !------------------------------------------------------------------------------- - - lchnk = state%lchnk - - ! loop over the cloud borne constituents required by this module and save - ! a local copy - - do i = 1, ncnst - - ! Check whether constituent is a mass or number mixing ratio - if (spec_idx(i) == 0) then - call rad_cnst_get_mode_num(0, mode_idx(i), 'c', state, pbuf, ptr2d) - else - call rad_cnst_get_aer_mmr(0, mode_idx(i), spec_idx(i), 'c', state, pbuf, ptr2d) - end if - aer_cb(:,:,i,lchnk) = ptr2d - end do - -end subroutine hetfrz_classnuc_cam_save_cbaero - -!==================================================================================================== - subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& total_aer_num, & coated_aer_num, & @@ -919,7 +902,7 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& total_cloudborne_aer_num, & hetraer, awcam, awfacm, dstcoat, & na500, tot_na500) - + !***************************************************************************** ! Purpose: Calculate BC and Dust number, including total number(interstitial+ ! cloud borne), one monolayer coated number, and uncoated number @@ -940,7 +923,7 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& real(r8), intent(out) :: total_aer_num(3) ! #/cm^3 real(r8), intent(out) :: total_interstial_aer_num(3) ! #/cm^3 real(r8), intent(out) :: total_cloudborne_aer_num(3) ! #/cm^3 - real(r8), intent(out) :: coated_aer_num(3) ! #/cm^3 + real(r8), intent(out) :: coated_aer_num(3) ! #/cm^3 real(r8), intent(out) :: uncoated_aer_num(3) ! #/cm^3 real(r8), intent(out) :: hetraer(3) ! BC and Dust mass mean radius [m] real(r8), intent(out) :: awcam(3) ! modal added mass [mug m-3] @@ -960,26 +943,26 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& real(r8), parameter :: soa_equivso4_factor = spechygro_soa/spechygro_so4 real(r8), parameter :: pom_equivso4_factor = spechygro_pom/spechygro_so4 real(r8) :: vol_shell(3) - real(r8) :: vol_core(3) + real(r8) :: vol_core(3) real(r8) :: fac_volsfc_dust_a1, fac_volsfc_dust_a3, fac_volsfc_bc real(r8) :: tmp1, tmp2 - real(r8) :: bc_num ! bc number in accumulation mode for MAM3 + real(r8) :: bc_num ! bc number in accumulation mode for MAM3 ! bc number in accumulation and primary carbon mode for MAM7 and MAM4 real(r8) :: dst1_num, dst3_num ! dust number in accumulation and corase mode for MAM3 ! dust number in fine dust and corase dust mode for MAM7 and MAM4 - logical :: num_to_mass_in = .true. + logical :: num_to_mass_in = .false. real(r8), parameter :: bc_num_to_mass = 4.669152e+17_r8 ! #/kg from emission real(r8), parameter :: dst1_num_to_mass = 3.484e+15_r8 ! #/kg for dust in accumulation mode - real(r8) :: dmc, ssmc + real(r8) :: dmc, ssmc, so4 real(r8) :: as_so4, as_du, as_soa real(r8) :: dst1_num_imm, dst3_num_imm, bc_num_imm - real(r8) :: dmc_imm, ssmc_imm + real(r8) :: dmc_imm, ssmc_imm, so4_imm real(r8) :: as_bc, as_pom, as_ss - - real(r8) :: r_bc ! model radii of BC modes [m] - real(r8) :: r_dust_a1, r_dust_a3 ! model radii of dust modes [m] + real(r8) :: bc4_num + real(r8) :: r_bc ! model radii of BC modes [m] + real(r8) :: r_dust_a1, r_dust_a3 ! model radii of dust modes [m] integer :: i real(r8) :: dst1_scale @@ -999,9 +982,9 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& tot_na500 = 0._r8 !***************************************************************************** - ! calculate intersitial aerosol + ! calculate intersitial aerosol !***************************************************************************** - + if (nmodes == MAM3_nmodes .or. nmodes == MAM4_nmodes .or. nmodes == MAM5_nmodes) then if (.not. num_to_mass_in) then @@ -1034,26 +1017,34 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& end if dmc = aer(ii,kk,dst_coarse) ssmc = aer(ii,kk,ncl_coarse) - + so4 = aer(ii,kk,so4_coarse) + if (dmc > 0._r8 ) then - dst3_num = dmc/(ssmc+dmc) * aer(ii,kk,num_coarse)*1.0e-6_r8 ! #/cm^3 + dst3_num = dmc/(ssmc+dmc+so4) * aer(ii,kk,num_coarse)*1.0e-6_r8 ! #/cm^3 else dst3_num = 0.0_r8 end if if (nmodes == MAM4_nmodes .or. nmodes == MAM5_nmodes) then - bc_num = bc_num+(aer(ii,kk,bc_pcarbon)) * bc_num_to_mass*1.0e-6_r8 ! #/cm^3 + if (num_to_mass_in) then + bc_num = bc_num+(aer(ii,kk,bc_pcarbon)) * bc_num_to_mass*1.0e-6_r8 ! #/cm^3 + else + as_bc = aer(ii,kk,bc_pcarbon) + as_pom = aer(ii,kk,pom_pcarbon) + bc4_num = as_bc/(as_bc+as_pom)*aer(ii,kk,num_pcarbon)*1.0e-6_r8 ! #/cm^3 + bc_num = bc_num + bc4_num + end if end if else if (nmodes == MAM7_nmodes) then bc_num = (aer(ii,kk,bc_accum)+aer(ii,kk,bc_pcarbon)) * bc_num_to_mass*1.0e-6_r8 ! #/cm^3 dst1_num = aer(ii,kk,num_finedust)*1.0e-6_r8 ! #/cm^3 - dst3_num = aer(ii,kk,num_coardust)*1.0e-6_r8 ! #/cm^3 + dst3_num = aer(ii,kk,num_coardust)*1.0e-6_r8 ! #/cm^3 end if !***************************************************************************** - ! calculate cloud borne aerosol - !***************************************************************************** - + ! calculate cloud borne aerosol + !***************************************************************************** + if (nmodes == MAM3_nmodes .or. nmodes == MAM4_nmodes .or. nmodes == MAM5_nmodes) then as_so4 = aer_cb(ii,kk,so4_accum) @@ -1076,12 +1067,13 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& else bc_num_imm = 0.0_r8 end if - + dmc_imm = aer_cb(ii,kk,dst_coarse) ssmc_imm = aer_cb(ii,kk,ncl_coarse) + so4_imm = aer_cb(ii,kk,so4_coarse) if (dmc_imm > 0._r8) then - dst3_num_imm = dmc_imm/(ssmc_imm+dmc_imm) * aer_cb(ii,kk,num_coarse)*1.0e-6_r8 ! #/cm^3 + dst3_num_imm = dmc_imm/(ssmc_imm+dmc_imm+so4_imm) * aer_cb(ii,kk,num_coarse)*1.0e-6_r8 ! #/cm^3 else dst3_num_imm = 0.0_r8 end if @@ -1105,16 +1097,16 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& total_interstial_aer_num(1) = bc_num total_interstial_aer_num(2) = dst1_num - total_interstial_aer_num(3) = dst3_num + total_interstial_aer_num(3) = dst3_num - total_cloudborne_aer_num(1) = bc_num_imm - total_cloudborne_aer_num(2) = dst1_num_imm + total_cloudborne_aer_num(1) = bc_num_imm + total_cloudborne_aer_num(2) = dst1_num_imm total_cloudborne_aer_num(3) = dst3_num_imm - - !***************************************************************************** + + !***************************************************************************** ! calculate mass mean radius - !***************************************************************************** - + !***************************************************************************** + if (nmodes == MAM3_nmodes .or. nmodes == MAM4_nmodes .or. nmodes == MAM5_nmodes) then if (nmodes == MAM3_nmodes) then @@ -1157,7 +1149,7 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& else r_bc = 0.067e-6_r8 ! from emission size end if - + if (aer(ii,kk,dst_finedust)*1.0e-3_r8 > 1.0e-30_r8 .and. dst1_num > 1.0e-3_r8) then r_dust_a1 = ( 3._r8/(4*pi*specdens_dust)*aer(ii,kk,dst_finedust)/(dst1_num*1.0e6_r8) )**(1._r8/3._r8) else @@ -1169,16 +1161,16 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& else r_dust_a3 = 1.576e-6_r8 end if - end if + end if hetraer(1) = r_bc hetraer(2) = r_dust_a1 hetraer(3) = r_dust_a3 !***************************************************************************** - ! calculate coated fraction + ! calculate coated fraction !***************************************************************************** - + if (nmodes == MAM3_nmodes .or. nmodes == MAM4_nmodes .or. nmodes == MAM5_nmodes) then fac_volsfc_bc = exp(2.5_r8*alnsg_mode_accum**2) @@ -1191,16 +1183,16 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& vol_core(2) = aer(ii,kk,dst_accum)/(specdens_dust*rhoair) - ! ratio1 = vol_shell/vol_core = + ! ratio1 = vol_shell/vol_core = ! actual hygroscopic-shell-volume/dust-core-volume ! ratio2 = 6.0_r8*dr_so4_monolayers_pcage/(dgncur_a*fac_volsfc_dust) - ! = (shell-volume corresponding to n_so4_monolayers_pcage)/core-volume + ! = (shell-volume corresponding to n_so4_monolayers_pcage)/core-volume ! The 6.0/(dgncur_a*fac_volsfc_dust) = (mode-surface-area/mode-volume) ! Note that vol_shell includes both so4, pom, AND soa as "equivalent so4", ! The soa_equivso4_factor accounts for the lower hygroscopicity of soa. ! ! Define xferfrac_pcage = min( 1.0, ratio1/ratio2) - ! But ratio1/ratio2 == tmp1/tmp2, and coding below avoids possible overflow + ! But ratio1/ratio2 == tmp1/tmp2, and coding below avoids possible overflow ! bc if (nmodes == MAM3_nmodes) then @@ -1255,10 +1247,10 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& vol_shell(3) = aer(ii,kk,so4_coardust)/(specdens_so4*rhoair) vol_core(3) = aer(ii,kk,dst_coardust)/(specdens_dust*rhoair) - tmp1 = vol_shell(3)*(r_dust_a3*2._r8)*fac_volsfc_dust_a3 + tmp1 = vol_shell(3)*(r_dust_a3*2._r8)*fac_volsfc_dust_a3 tmp2 = max(6.0_r8*dr_so4_monolayers_dust*vol_core(3), 0.0_r8) dstcoat(3) = tmp1/tmp2 - + end if if (dstcoat(1) > 1._r8) dstcoat(1) = 1._r8 @@ -1267,19 +1259,24 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& if (dstcoat(2) < 0.001_r8) dstcoat(2) = 0.001_r8 if (dstcoat(3) > 1._r8) dstcoat(3) = 1._r8 if (dstcoat(3) < 0.001_r8) dstcoat(3) = 0.001_r8 - + do i = 1, 3 total_aer_num(i) = total_interstial_aer_num(i) + total_cloudborne_aer_num(i) coated_aer_num(i) = total_interstial_aer_num(i)*dstcoat(i) uncoated_aer_num(i) = total_interstial_aer_num(i)*(1._r8-dstcoat(i)) end do - + if (nmodes == MAM4_nmodes .or. nmodes == MAM7_nmodes .or. nmodes == MAM5_nmodes) then - coated_aer_num(1) = (aer(ii,kk,bc_pcarbon)*bc_num_to_mass*1.0e-6_r8)*dstcoat(1)+ & - (aer(ii,kk,bc_accum)*bc_num_to_mass*1.0e-6_r8) - uncoated_aer_num(1) = (aer(ii,kk,bc_pcarbon)*bc_num_to_mass*1.0e-6_r8)*(1._r8-dstcoat(1)) + if (num_to_mass_in) then + coated_aer_num(1) = (aer(ii,kk,bc_pcarbon)*bc_num_to_mass*1.0e-6_r8)*dstcoat(1)+ & + (aer(ii,kk,bc_accum)*bc_num_to_mass*1.0e-6_r8) + uncoated_aer_num(1) = (aer(ii,kk,bc_pcarbon)*bc_num_to_mass*1.0e-6_r8)*(1._r8-dstcoat(1)) + else + coated_aer_num(1) = bc4_num*dstcoat(1) + bc_num + uncoated_aer_num(1) = bc4_num*(1._r8-dstcoat(1)) + end if end if - + if (nmodes == MAM3_nmodes .or. nmodes == MAM4_nmodes .or. nmodes == MAM5_nmodes) then dst1_scale = 0.488_r8 ! scaled for D>0.5-1 um from 0.1-1 um else if (nmodes == MAM7_nmodes) then @@ -1293,12 +1290,12 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& + total_interstial_aer_num(2)*dst1_scale + total_interstial_aer_num(3) !***************************************************************************** - ! prepare some variables for water activity + ! prepare some variables for water activity !***************************************************************************** - + if (nmodes == MAM3_nmodes .or. nmodes == MAM4_nmodes .or. nmodes == MAM5_nmodes) then - ! accumulation mode for dust_a1 - if (aer(ii,kk,num_accum) > 0._r8) then + ! accumulation mode for dust_a1 + if (aer(ii,kk,num_accum) > 0._r8) then awcam(2) = (dst1_num*1.0e6_r8)/aer(ii,kk,num_accum)* & ( aer(ii,kk,so4_accum) + aer(ii,kk,soa_accum) + & aer(ii,kk,pom_accum) + aer(ii,kk,bc_accum) )*1.0e9_r8 ! [mug m-3] @@ -1306,7 +1303,7 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& awcam(2) = 0._r8 end if - if (awcam(2) > 0._r8) then + if (awcam(2) > 0._r8) then awfacm(2) = ( aer(ii,kk,bc_accum) + aer(ii,kk,soa_accum) + aer(ii,kk,pom_accum) )/ & ( aer(ii,kk,soa_accum) + aer(ii,kk,pom_accum) + aer(ii,kk,so4_accum) + aer(ii,kk,bc_accum) ) else @@ -1356,13 +1353,13 @@ subroutine get_aer_num(ii, kk, ncnst, aer, aer_cb, rhoair,& if (aer(ii,kk,num_coardust) > 0._r8) then awcam(3) = (dst3_num*1.0e6_r8)/aer(ii,kk,num_coardust)* aer(ii,kk,so4_coardust)*1.0e9_r8 - else + else awcam(3) = 0._r8 end if awfacm(3) = 0._r8 end if - + end subroutine get_aer_num !==================================================================================================== diff --git a/src/physics/cam/microp_aero.F90 b/src/physics/cam/microp_aero.F90 index c65abd6157..226abf6ebb 100644 --- a/src/physics/cam/microp_aero.F90 +++ b/src/physics/cam/microp_aero.F90 @@ -42,7 +42,7 @@ module microp_aero use ndrop_bam, only: ndrop_bam_init, ndrop_bam_run, ndrop_bam_ccn use hetfrz_classnuc_cam, only: hetfrz_classnuc_cam_readnl, hetfrz_classnuc_cam_register, hetfrz_classnuc_cam_init, & - hetfrz_classnuc_cam_save_cbaero, hetfrz_classnuc_cam_calc + hetfrz_classnuc_cam_calc use cam_history, only: addfld, add_default, outfld use cam_logfile, only: iulog @@ -578,11 +578,6 @@ subroutine microp_aero_run ( & rndst(1:ncol,1:pver,3) = rn_dst3 rndst(1:ncol,1:pver,4) = rn_dst4 - ! save copy of cloud borne aerosols for use in heterogeneous freezing - if (use_hetfrz_classnuc) then - call hetfrz_classnuc_cam_save_cbaero(state1, pbuf) - end if - ! initialize time-varying parameters do k = top_lev, pver do i = 1, ncol diff --git a/src/physics/cam/nucleate_ice_cam.F90 b/src/physics/cam/nucleate_ice_cam.F90 index 4abd115826..922e871b72 100644 --- a/src/physics/cam/nucleate_ice_cam.F90 +++ b/src/physics/cam/nucleate_ice_cam.F90 @@ -482,11 +482,7 @@ subroutine nucleate_ice_cam_calc( & ni => state%q(:,:,numice_idx) pmid => state%pmid - do k = top_lev, pver - do i = 1, ncol - rho(i,k) = pmid(i,k)/(rair*t(i,k)) - end do - end do + rho(:ncol,:) = pmid(:ncol,:)/(rair*t(:ncol,:)) if (clim_modal_aero) then diff --git a/src/physics/cam/phys_control.F90 b/src/physics/cam/phys_control.F90 index 08962c816a..8d0cad7ee3 100644 --- a/src/physics/cam/phys_control.F90 +++ b/src/physics/cam/phys_control.F90 @@ -56,9 +56,8 @@ module phys_control logical :: history_aerosol = .false. ! output the MAM aerosol variables and tendencies logical :: history_aero_optics = .false. ! output the aerosol logical :: history_eddy = .false. ! output the eddy variables -logical :: history_budget = .false. ! output tendencies and state variables for CAM4 - ! temperature, water vapor, cloud ice and cloud - ! liquid budgets. +logical :: history_budget = .false. ! output tendencies and state variables for T, water vapor, + ! cloud ice and cloud liquid budgets logical :: convproc_do_aer = .false. ! switch for new convective scavenging treatment for modal aerosols integer :: history_budget_histfile_num = 1 ! output history file number for budget fields diff --git a/src/physics/cam/phys_grid.F90 b/src/physics/cam/phys_grid.F90 index 712421550d..ca1670e4c2 100644 --- a/src/physics/cam/phys_grid.F90 +++ b/src/physics/cam/phys_grid.F90 @@ -498,6 +498,9 @@ subroutine phys_grid_init( ) ! column surface area (from dynamics) real(r8), dimension(:), pointer :: area_d + ! column surface areawt (from dynamics) + real(r8), dimension(:), pointer :: areawt_d + ! column integration weight (from dynamics) real(r8), dimension(:), allocatable :: wght_d @@ -1147,7 +1150,6 @@ subroutine phys_grid_init( ) ! Note that if the dycore is using the same points as the physics grid, ! it will have already set up 'lat' and 'lon' axes for the physics grid ! However, these will be in the dynamics decomposition - if (unstructured) then lon_coord => horiz_coord_create('lon', 'ncol', num_global_phys_cols, & 'longitude', 'degrees_east', 1, size(lonvals), lonvals, & @@ -1188,13 +1190,13 @@ subroutine phys_grid_init( ) do i = 1, size(copy_attributes) call cam_grid_attribute_copy(copy_gridname, 'physgrid', copy_attributes(i)) end do - if ((.not. cam_grid_attr_exists('physgrid', 'area')) .and. unstructured) then ! Physgrid always needs an area attribute. If we did not inherit one ! from the dycore (i.e., physics and dynamics are on different grids), ! create that attribute here (unstructured grids only, physgrid is ! not supported for structured grids). allocate(area_d(size(grid_map, 2))) + allocate(areawt_d(size(grid_map, 2))) p = 0 do lcid = begchunk, endchunk ncols = lchunks(lcid)%ncols @@ -1203,16 +1205,21 @@ subroutine phys_grid_init( ) cid = lchunks(lcid)%cid do i = 1, chunks(cid)%ncols area_d(p + i) = lchunks(lcid)%area(i) + areawt_d(p + i) = lchunks(lcid)%wght(i) end do if (pcols > ncols) then ! Need to set these to detect unused columns area_d(p+ncols+1:p+pcols) = 0.0_r8 + areawt_d(p+ncols+1:p+pcols) = 0.0_r8 end if p = p + pcols end do call cam_grid_attribute_register('physgrid', 'area', & 'physics column areas', 'ncol', area_d, map=grid_map(3,:)) + call cam_grid_attribute_register('physgrid', 'areawt', & + 'physics column area wts', 'ncol', areawt_d, map=grid_map(3,:)) nullify(area_d) ! Belongs to attribute now + nullify(areawt_d) ! Belongs to attribute now end if ! Cleanup pointers (they belong to the grid now) nullify(grid_map) diff --git a/src/physics/cam/phys_grid_ctem.F90 b/src/physics/cam/phys_grid_ctem.F90 index e2d0cb5c71..6863799864 100644 --- a/src/physics/cam/phys_grid_ctem.F90 +++ b/src/physics/cam/phys_grid_ctem.F90 @@ -140,7 +140,7 @@ subroutine phys_grid_ctem_reg real(r8), parameter :: latrad0 = -pi*0.5_r8 real(r8), parameter :: fourpi = pi*4._r8 - integer, parameter :: ctem_zavg_phys_decomp = 201 ! Must be unique within CAM + integer, parameter :: ctem_zavg_phys_decomp = 333 ! Must be unique within CAM if (.not.do_tem_diags) return @@ -207,11 +207,15 @@ subroutine phys_grid_ctem_init if (.not.do_tem_diags) return - call addfld ('VTHzaphys',(/'lev'/), 'A', 'K m s-1','Meridional Heat Flux:', gridname='ctem_zavg_phys') - call addfld ('WTHzaphys',(/'lev'/), 'A', 'K m s-1','Vertical Heat Flux:', gridname='ctem_zavg_phys') - call addfld ('UVzaphys', (/'lev'/), 'A', 'm2 s-2', 'Meridional Flux of Zonal Momentum', gridname='ctem_zavg_phys') - call addfld ('UWzaphys', (/'lev'/), 'A', 'm2 s-2', 'Vertical Flux of Zonal Momentum', gridname='ctem_zavg_phys') - call addfld ('THphys', (/'lev'/), 'A', 'K', 'Potential temp', gridname='physgrid' ) + call addfld ('Uzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean zonal wind', gridname='ctem_zavg_phys' ) + call addfld ('Vzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean meridional wind', gridname='ctem_zavg_phys' ) + call addfld ('Wzm', (/'lev'/), 'A','m s-1', 'Zonal-Mean vertical wind', gridname='ctem_zavg_phys' ) + call addfld ('THzm', (/'lev'/), 'A','K', 'Zonal-Mean potential temp', gridname='ctem_zavg_phys' ) + call addfld ('VTHzm',(/'lev'/), 'A','K m s-1','Meridional Heat Flux:', gridname='ctem_zavg_phys') + call addfld ('WTHzm',(/'lev'/), 'A','K m s-1','Vertical Heat Flux:', gridname='ctem_zavg_phys') + call addfld ('UVzm', (/'lev'/), 'A','m2 s-2', 'Meridional Flux of Zonal Momentum', gridname='ctem_zavg_phys') + call addfld ('UWzm', (/'lev'/), 'A','m2 s-2', 'Vertical Flux of Zonal Momentum', gridname='ctem_zavg_phys') + call addfld ('THphys',(/'lev'/), 'A', 'K', 'Potential temp', gridname='physgrid' ) end subroutine phys_grid_ctem_init @@ -251,6 +255,11 @@ subroutine phys_grid_ctem_diags(phys_state) real(r8) :: vthza(nzalat,pver) real(r8) :: wthza(nzalat,pver) + real(r8) :: uza(nzalat,pver) + real(r8) :: vza(nzalat,pver) + real(r8) :: wza(nzalat,pver) + real(r8) :: thza(nzalat,pver) + real(r8) :: sheight(pcols,pver) ! pressure scale height (m) if (.not.do_calc()) return @@ -311,12 +320,26 @@ subroutine phys_grid_ctem_diags(phys_state) if (any(abs(vthza)>1.e20_r8)) call endrun(prefix//'bad values in vthza') if (any(abs(wthza)>1.e20_r8)) call endrun(prefix//'bad values in wthza') + call ZAobj%binAvg(uzm, uza) + call ZAobj%binAvg(vzm, vza) + call ZAobj%binAvg(wzm, wza) + call ZAobj%binAvg(thzm, thza) + + if (any(abs(uza)>1.e20_r8)) call endrun(prefix//'bad values in uza') + if (any(abs(vza)>1.e20_r8)) call endrun(prefix//'bad values in vza') + if (any(abs(wza)>1.e20_r8)) call endrun(prefix//'bad values in wza') + if (any(abs(thza)>1.e20_r8)) call endrun(prefix//'bad values in thza') + ! diagnostic output do j = 1,nzalat - call outfld('UVzaphys',uvza(j,:),1,j) - call outfld('UWzaphys',uwza(j,:),1,j) - call outfld('VTHzaphys',vthza(j,:),1,j) - call outfld('WTHzaphys',wthza(j,:),1,j) + call outfld('Uzm',uza(j,:),1,j) + call outfld('Vzm',vza(j,:),1,j) + call outfld('Wzm',wza(j,:),1,j) + call outfld('THzm',thza(j,:),1,j) + call outfld('UVzm',uvza(j,:),1,j) + call outfld('UWzm',uwza(j,:),1,j) + call outfld('VTHzm',vthza(j,:),1,j) + call outfld('WTHzm',wthza(j,:),1,j) end do contains diff --git a/src/physics/cam/physics_types.F90 b/src/physics/cam/physics_types.F90 index dcda2e8906..9b0c23d2ff 100644 --- a/src/physics/cam/physics_types.F90 +++ b/src/physics/cam/physics_types.F90 @@ -6,7 +6,7 @@ module physics_types use shr_kind_mod, only: r8 => shr_kind_r8 use ppgrid, only: pcols, pver use constituents, only: pcnst, qmin, cnst_name, cnst_get_ind - use geopotential, only: geopotential_dse, geopotential_t + use geopotential, only: geopotential_t use physconst, only: zvir, gravit, cpair, rair use air_composition, only: cpairv, rairv use phys_grid, only: get_ncols_p, get_rlon_all_p, get_rlat_all_p, get_gcol_all_p @@ -18,8 +18,6 @@ module physics_types implicit none private ! Make default type private to the module - logical, parameter :: adjust_te = .FALSE. - ! Public types: public physics_state @@ -210,10 +208,11 @@ subroutine physics_update(state, ptend, dt, tend) !----------------------------------------------------------------------- ! Update the state and or tendency structure with the parameterization tendencies !----------------------------------------------------------------------- - use scamMod, only: scm_crm_mode, single_column - use phys_control, only: phys_getopts - use cam_thermo, only: cam_thermo_update ! Routine which updates physconst variables (WACCM-X) - use qneg_module, only: qneg3 + use scamMod, only: scm_crm_mode, single_column + use phys_control, only: phys_getopts + use cam_thermo, only: cam_thermo_dry_air_update ! Routine which updates physconst variables (WACCM-X) + use air_composition, only: dry_air_species_num + use qneg_module , only: qneg3 !------------------------------Arguments-------------------------------- type(physics_ptend), intent(inout) :: ptend ! Parameterization tendencies @@ -377,9 +376,8 @@ subroutine physics_update(state, ptend, dt, tend) !------------------------------------------------------------------------ ! Get indices for molecular weights and call WACCM-X cam_thermo_update !------------------------------------------------------------------------ - if ( waccmx_is('ionosphere') .or. waccmx_is('neutral') ) then - call cam_thermo_update(state%q, state%t, state%lchnk, state%ncol, & - to_moist_factor=state%pdeldry(:ncol,:)/state%pdel(:ncol,:) ) + if (dry_air_species_num>0) then + call cam_thermo_dry_air_update(state%q, state%t, state%lchnk, state%ncol) endif !----------------------------------------------------------------------- @@ -426,7 +424,7 @@ subroutine physics_update(state, ptend, dt, tend) if (ptend%ls .or. ptend%lq(1)) then call geopotential_t ( & state%lnpint, state%lnpmid, state%pint , state%pmid , state%pdel , state%rpdel , & - state%t , state%q(:,:,1), rairv_loc(:,:), gravit , zvirv , & + state%t , state%q(:,:,:), rairv_loc(:,:), gravit , zvirv , & state%zi , state%zm , ncol ) ! update dry static energy for use in next process do k = ptend%top_level, ptend%bot_level @@ -1192,7 +1190,10 @@ subroutine physics_cnst_limit(state) end subroutine physics_cnst_limit !=============================================================================== - subroutine physics_dme_adjust(state, tend, qini, dt) + subroutine physics_dme_adjust(state, tend, qini, liqini, iceini, dt) + use air_composition, only: dry_air_species_num,thermodynamic_active_species_num + use air_composition, only: thermodynamic_active_species_idx + use dycore, only: dycore_is !----------------------------------------------------------------------- ! ! Purpose: Adjust the dry mass in each layer back to the value of physics input state @@ -1224,6 +1225,8 @@ subroutine physics_dme_adjust(state, tend, qini, dt) type(physics_state), intent(inout) :: state type(physics_tend ), intent(inout) :: tend real(r8), intent(in ) :: qini(pcols,pver) ! initial specific humidity + real(r8), intent(in ) :: liqini(pcols,pver) ! initial total liquid + real(r8), intent(in ) :: iceini(pcols,pver) ! initial total ice real(r8), intent(in ) :: dt ! model physics timestep ! !---------------------------Local workspace----------------------------- @@ -1238,16 +1241,18 @@ subroutine physics_dme_adjust(state, tend, qini, dt) real(r8) :: zvirv(pcols,pver) ! Local zvir array pointer + real(r8) :: tot_water (pcols,2) ! total water (initial, present) + real(r8) :: tot_water_chg(pcols) ! total water change + + real(r8),allocatable :: cpairv_loc(:,:) + integer :: m_cnst ! !----------------------------------------------------------------------- if (state%psetcols .ne. pcols) then call endrun('physics_dme_adjust: cannot pass in a state which has sub-columns') end if - if (adjust_te) then - call endrun('physics_dme_adjust: must update code based on the "correct" energy before turning on "adjust_te"') - end if lchnk = state%lchnk ncol = state%ncol @@ -1255,76 +1260,57 @@ subroutine physics_dme_adjust(state, tend, qini, dt) ! adjust dry mass in each layer back to input value, while conserving ! constituents, momentum, and total energy state%ps(:ncol) = state%pint(:ncol,1) - do k = 1, pver - ! adjusment factor is just change in water vapor - fdq(:ncol) = 1._r8 + state%q(:ncol,k,1) - qini(:ncol,k) - - ! adjust constituents to conserve mass in each layer - do m = 1, pcnst + ! + ! original code for backwards compatability with FV and EUL + ! + if (.not.(dycore_is('MPAS') .or. dycore_is('SE'))) then + do k = 1, pver + + ! adjusment factor is just change in water vapor + fdq(:ncol) = 1._r8 + state%q(:ncol,k,1) - qini(:ncol,k) + + ! adjust constituents to conserve mass in each layer + do m = 1, pcnst state%q(:ncol,k,m) = state%q(:ncol,k,m) / fdq(:ncol) - end do - - if (adjust_te) then - ! compute specific total energy of unadjusted state (J/kg) - te(:ncol) = state%s(:ncol,k) + 0.5_r8*(state%u(:ncol,k)**2 + state%v(:ncol,k)**2) - - ! recompute initial u,v from the new values and the tendencies - utmp(:ncol) = state%u(:ncol,k) - dt * tend%dudt(:ncol,k) - vtmp(:ncol) = state%v(:ncol,k) - dt * tend%dvdt(:ncol,k) - ! adjust specific total energy and specific momentum (velocity) to conserve each - te (:ncol) = te (:ncol) / fdq(:ncol) - state%u(:ncol,k) = state%u(:ncol,k ) / fdq(:ncol) - state%v(:ncol,k) = state%v(:ncol,k ) / fdq(:ncol) - ! compute adjusted u,v tendencies - tend%dudt(:ncol,k) = (state%u(:ncol,k) - utmp(:ncol)) / dt - tend%dvdt(:ncol,k) = (state%v(:ncol,k) - vtmp(:ncol)) / dt - - ! compute adjusted static energy - state%s(:ncol,k) = te(:ncol) - 0.5_r8*(state%u(:ncol,k)**2 + state%v(:ncol,k)**2) - end if - -! compute new total pressure variables - state%pdel (:ncol,k ) = state%pdel(:ncol,k ) * fdq(:ncol) - state%ps(:ncol) = state%ps(:ncol) + state%pdel(:ncol,k) - state%pint (:ncol,k+1) = state%pint(:ncol,k ) + state%pdel(:ncol,k) - state%lnpint(:ncol,k+1) = log(state%pint(:ncol,k+1)) - state%rpdel (:ncol,k ) = 1._r8/ state%pdel(:ncol,k ) - end do - + end do + ! compute new total pressure variables + state%pdel (:ncol,k ) = state%pdel(:ncol,k ) * fdq(:ncol) + state%ps(:ncol) = state%ps(:ncol) + state%pdel(:ncol,k) + state%pint (:ncol,k+1) = state%pint(:ncol,k ) + state%pdel(:ncol,k) + state%lnpint(:ncol,k+1) = log(state%pint(:ncol,k+1)) + state%rpdel (:ncol,k ) = 1._r8/ state%pdel(:ncol,k ) + end do + else + do k = 1, pver + tot_water(:ncol,1) = qini(:ncol,k) +liqini(:ncol,k)+iceini(:ncol,k) !initial total H2O + tot_water(:ncol,2) = 0.0_r8 + do m_cnst=dry_air_species_num+1,thermodynamic_active_species_num + m = thermodynamic_active_species_idx(m_cnst) + tot_water(:ncol,2) = tot_water(:ncol,2)+state%q(:ncol,k,m) + end do + fdq(:ncol) = 1._r8 + tot_water(:ncol,2) - tot_water(:ncol,1) + ! adjust constituents to conserve mass in each layer + do m = 1, pcnst + state%q(:ncol,k,m) = state%q(:ncol,k,m) / fdq(:ncol) + end do + ! compute new total pressure variables + state%pdel (:ncol,k ) = state%pdel(:ncol,k ) * fdq(:ncol) + state%ps(:ncol) = state%ps(:ncol) + state%pdel(:ncol,k) + state%pint (:ncol,k+1) = state%pint(:ncol,k ) + state%pdel(:ncol,k) + state%lnpint(:ncol,k+1) = log(state%pint(:ncol,k+1)) + state%rpdel (:ncol,k ) = 1._r8/ state%pdel(:ncol,k ) + !note that mid-level variables (e.g. pmid) are not recomputed + end do + endif if ( waccmx_is('ionosphere') .or. waccmx_is('neutral') ) then zvirv(:,:) = shr_const_rwv / rairv(:,:,state%lchnk) - 1._r8 else zvirv(:,:) = zvir endif -! compute new T,z from new s,q,dp - if (adjust_te) then - -! cpairv_loc needs to be allocated to a size which matches state and ptend -! If psetcols == pcols, cpairv is the correct size and just copy into cpairv_loc -! If psetcols > pcols and all cpairv match cpair, then assign the constant cpair - - allocate(cpairv_loc(state%psetcols,pver)) - if (state%psetcols == pcols) then - cpairv_loc(:,:) = cpairv(:,:,state%lchnk) - else if (state%psetcols > pcols .and. all(cpairv(:,:,:) == cpair)) then - cpairv_loc(:,:) = cpair - else - call endrun('physics_dme_adjust: cpairv is not allowed to vary when subcolumns are turned on') - end if - - call geopotential_dse(state%lnpint, state%lnpmid, state%pint, & - state%pmid , state%pdel , state%rpdel, & - state%s , state%q(:,:,1), state%phis , rairv(:,:,state%lchnk), & - gravit, cpairv_loc(:,:), zvirv, & - state%t , state%zi , state%zm , ncol) - - deallocate(cpairv_loc) - - end if - end subroutine physics_dme_adjust + !----------------------------------------------------------------------- !=============================================================================== @@ -1537,7 +1523,7 @@ end subroutine set_dry_to_wet subroutine physics_state_alloc(state,lchnk,psetcols) - use infnan, only : inf, assignment(=) + use infnan, only: inf, assignment(=) ! allocate the individual state components diff --git a/src/physics/cam/physpkg.F90 b/src/physics/cam/physpkg.F90 index c726eb490e..c33546b194 100644 --- a/src/physics/cam/physpkg.F90 +++ b/src/physics/cam/physpkg.F90 @@ -13,7 +13,7 @@ module physpkg use shr_kind_mod, only: r8 => shr_kind_r8 use spmd_utils, only: masterproc - use physconst, only: latvap, latice, rh2o + use physconst, only: latvap, latice use physics_types, only: physics_state, physics_tend, physics_state_set_grid, & physics_ptend, physics_tend_init, physics_update, & physics_type_alloc, physics_ptend_dealloc,& @@ -21,7 +21,7 @@ module physpkg use phys_grid, only: get_ncols_p use phys_gmean, only: gmean_mass use ppgrid, only: begchunk, endchunk, pcols, pver, pverp, psubcols - use constituents, only: pcnst, cnst_name, cnst_get_ind + use constituents, only: pcnst, cnst_get_ind use camsrfexch, only: cam_out_t, cam_in_t use cam_control_mod, only: ideal_phys, adiabatic @@ -74,6 +74,8 @@ module physpkg integer :: qini_idx = 0 integer :: cldliqini_idx = 0 integer :: cldiceini_idx = 0 + integer :: totliqini_idx = 0 + integer :: toticeini_idx = 0 integer :: prec_str_idx = 0 integer :: snow_str_idx = 0 @@ -109,11 +111,11 @@ subroutine phys_register use physics_buffer, only: pbuf_init_time, pbuf_cam_snapshot_register use physics_buffer, only: pbuf_add_field, dtype_r8, pbuf_register_subcol use shr_kind_mod, only: r8 => shr_kind_r8 - use spmd_utils, only: masterproc - use constituents, only: pcnst, cnst_add, cnst_chk_dim, cnst_name + use constituents, only: pcnst, cnst_add, cnst_chk_dim use cam_control_mod, only: moist_physics use chemistry, only: chem_register + use mo_lightning, only: lightning_register use cloud_fraction, only: cldfrc_register use rk_stratiform, only: rk_stratiform_register use microp_driver, only: microp_driver_register @@ -121,7 +123,7 @@ subroutine phys_register use macrop_driver, only: macrop_driver_register use clubb_intr, only: clubb_register_cam use conv_water, only: conv_water_register - use physconst, only: mwdry, cpair, mwh2o, cpwv + use physconst, only: mwh2o, cpwv use tracers, only: tracers_register use check_energy, only: check_energy_register use carma_intr, only: carma_register @@ -136,7 +138,6 @@ subroutine phys_register use flux_avg, only: flux_avg_register use iondrag, only: iondrag_register use waccmx_phys_intr, only: waccmx_phys_ion_elec_temp_reg - use string_utils, only: to_lower use prescribed_ozone, only: prescribed_ozone_register use prescribed_volcaero,only: prescribed_volcaero_register use prescribed_strataero,only: prescribed_strataero_register @@ -207,6 +208,8 @@ subroutine phys_register call pbuf_add_field('QINI', 'physpkg', dtype_r8, (/pcols,pver/), qini_idx) call pbuf_add_field('CLDLIQINI', 'physpkg', dtype_r8, (/pcols,pver/), cldliqini_idx) call pbuf_add_field('CLDICEINI', 'physpkg', dtype_r8, (/pcols,pver/), cldiceini_idx) + call pbuf_add_field('TOTLIQINI', 'physpkg', dtype_r8, (/pcols,pver/), totliqini_idx) + call pbuf_add_field('TOTICEINI', 'physpkg', dtype_r8, (/pcols,pver/), toticeini_idx) ! check energy package call check_energy_register @@ -267,6 +270,9 @@ subroutine phys_register ! register chemical constituents including aerosols ... call chem_register() + ! add prognostic lightning flash freq pbuf fld + call lightning_register() + ! co2 constituents call co2_register() @@ -359,7 +365,7 @@ end subroutine phys_register subroutine phys_inidat( cam_out, pbuf2d ) use cam_abortutils, only: endrun - use physics_buffer, only: pbuf_get_index, pbuf_get_field, physics_buffer_desc, pbuf_set_field, dyn_time_lvls + use physics_buffer, only: pbuf_get_index, physics_buffer_desc, pbuf_set_field, dyn_time_lvls use cam_initfiles, only: initial_file_get_id, topo_file_get_id @@ -375,11 +381,10 @@ subroutine phys_inidat( cam_out, pbuf2d ) type(cam_out_t), intent(inout) :: cam_out(begchunk:endchunk) type(physics_buffer_desc), pointer :: pbuf2d(:,:) - integer :: lchnk, m, n, i, k, ncol + integer :: lchnk, m, n, ncol type(file_desc_t), pointer :: fh_ini, fh_topo character(len=8) :: fieldname real(r8), pointer :: tptr(:,:), tptr_2(:,:), tptr3d(:,:,:), tptr3d_2(:,:,:) - real(r8), pointer :: qpert(:,:) character(len=11) :: subname='phys_inidat' ! subroutine name integer :: tpert_idx, qpert_idx, pblh_idx @@ -706,9 +711,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) !----------------------------------------------------------------------- use physics_buffer, only: physics_buffer_desc, pbuf_initialize, pbuf_get_index - use physconst, only: rair, cpair, gravit, stebol, tmelt, & - latvap, latice, rh2o, rhoh2o, pstd, zvir, & - karman, rhodair + use physconst, only: rair, cpair, gravit, zvir, karman use cam_thermo, only: cam_thermo_init use ref_pres, only: pref_edge, pref_mid @@ -716,6 +719,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use cam_control_mod, only: initial_run use check_energy, only: check_energy_init use chemistry, only: chem_init + use mo_lightning, only: lightning_init use prescribed_ozone, only: prescribed_ozone_init use prescribed_ghg, only: prescribed_ghg_init use prescribed_aero, only: prescribed_aero_init @@ -748,14 +752,13 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use pbl_utils, only: pbl_utils_init use vertical_diffusion, only: vertical_diffusion_init use phys_debug_util, only: phys_debug_init - use phys_debug, only: phys_debug_state_init use rad_constituents, only: rad_cnst_init use aer_rad_props, only: aer_rad_props_init use subcol, only: subcol_init use qbo, only: qbo_init use qneg_module, only: qneg_init use lunar_tides, only: lunar_tides_init - use iondrag, only: iondrag_init, do_waccm_ions + use iondrag, only: iondrag_init #if ( defined OFFLINE_DYN ) use metdata, only: metdata_phys_init #endif @@ -773,6 +776,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use cam_history, only: addfld, register_vector_field, add_default use phys_control, only: phys_getopts use phys_grid_ctem, only: phys_grid_ctem_init + use cam_budget, only: cam_budget_init ! Input/output arguments type(physics_state), pointer :: phys_state(:) @@ -790,7 +794,6 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) ! temperature, water vapor, cloud ! ice, cloud liquid, U, V integer :: history_budget_histfile_num ! output history file number for budget fields - !----------------------------------------------------------------------- call physics_type_alloc(phys_state, phys_tend, begchunk, endchunk, pcols) @@ -858,6 +861,9 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) ! Prognostic chemistry. call chem_init(phys_state,pbuf2d) + ! Lightning flash frq and NOx prod + call lightning_init( pbuf2d ) + ! Prescribed tracers call prescribed_ozone_init() call prescribed_ghg_init() @@ -973,6 +979,9 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) ! Initialize the snapshot capability call cam_snapshot_init(cam_in, cam_out, pbuf2d, begchunk) + ! Initialize the budget capability + call cam_budget_init() + ! addfld calls for U, V tendency budget variables that are output in ! tphysac, tphysbc call addfld ( 'UTEND_DCONV', (/ 'lev' /), 'A', 'm/s2', 'Zonal wind tendency by deep convection') @@ -1088,7 +1097,6 @@ subroutine phys_run1(phys_state, ztodt, phys_tend, pbuf2d, cam_in, cam_out) !---------------------------Local workspace----------------------------- ! integer :: c ! indices - integer :: ncol ! number of columns integer :: nstep ! current timestep number logical :: use_spcam type(physics_buffer_desc), pointer :: phys_buffer_chunk(:) @@ -1113,10 +1121,6 @@ subroutine phys_run1(phys_state, ztodt, phys_tend, pbuf2d, cam_in, cam_out) call check_energy_gmean(phys_state, pbuf2d, ztodt, nstep) call t_stopf ('chk_en_gmean') - call t_stopf ('physpkg_st1') - - call t_startf ('physpkg_st1') - call pbuf_allocate(pbuf2d, 'physpkg') call diag_allocate() @@ -1200,7 +1204,6 @@ subroutine phys_run2(phys_state, ztodt, phys_tend, pbuf2d, cam_out, & use physics_buffer, only: physics_buffer_desc, pbuf_get_chunk, pbuf_deallocate, pbuf_update_tim_idx use mo_lightning, only: lightning_no_prod use cam_diagnostics, only: diag_deallocate, diag_surf - use physconst, only: stebol, latvap use carma_intr, only: carma_accumulate_stats use spmd_utils, only: mpicom use iop_forcing, only: scam_use_iop_srf @@ -1251,9 +1254,9 @@ subroutine phys_run2(phys_state, ztodt, phys_tend, pbuf2d, cam_out, & ! call get_met_srf2( cam_in ) #endif - ! Set lightning production of NO + ! lightning flash freq and prod rate of NOx call t_startf ('lightning_no_prod') - call lightning_no_prod( phys_state, pbuf2d, cam_in ) + call lightning_no_prod( phys_state, pbuf2d, cam_in ) call t_stopf ('lightning_no_prod') call t_barrierf('sync_ac_physics', mpicom) @@ -1375,7 +1378,7 @@ subroutine tphysac (ztodt, cam_in, & use aero_model, only: aero_model_drydep use carma_intr, only: carma_emission_tend, carma_timestep_tend use carma_flags_mod, only: carma_do_aerosol, carma_do_emission - use check_energy, only: check_energy_chng, calc_te_and_aam_budgets + use check_energy, only: check_energy_chng, tot_energy_phys use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng use time_manager, only: get_nstep use cam_abortutils, only: endrun @@ -1389,14 +1392,17 @@ subroutine tphysac (ztodt, cam_in, & use perf_mod use flux_avg, only: flux_avg_run use unicon_cam, only: unicon_cam_org_diags - use cam_history, only: hist_fld_active, outfld + use cam_history, only: outfld use qneg_module, only: qneg4 use co2_cycle, only: co2_cycle_set_ptend use nudging, only: Nudge_Model,Nudge_ON,nudging_timestep_tend use cam_snapshot, only: cam_snapshot_all_outfld_tphysac use cam_snapshot_common,only: cam_snapshot_ptend_outfld use lunar_tides, only: lunar_tides_tend - + use cam_thermo, only: cam_thermo_water_update + use cam_budget, only: thermo_budget_history + use dyn_tests_utils, only: vc_dycore, vc_height, vc_dry_pressure + use air_composition, only: cpairv, cp_or_cv_dycore ! ! Arguments ! @@ -1416,30 +1422,24 @@ subroutine tphysac (ztodt, cam_in, & ! type(physics_ptend) :: ptend ! indivdual parameterization tendencies - integer :: nstep ! current timestep number - real(r8) :: zero(pcols) ! array of zeros + integer :: nstep ! current timestep number + real(r8) :: zero(pcols) ! array of zeros - integer :: lchnk ! chunk identifier - integer :: ncol ! number of atmospheric columns - integer i,k,m ! Longitude, level indices - integer :: yr, mon, day, tod ! components of a date - integer :: ixcldice, ixcldliq ! constituent indices for cloud liquid and ice water. + integer :: lchnk ! chunk identifier + integer :: ncol ! number of atmospheric columns + integer :: i,k ! Longitude, level indices integer :: ixq - logical :: labort ! abort flag + logical :: labort ! abort flag - real(r8) tvm(pcols,pver) ! virtual temperature - real(r8) prect(pcols) ! total precipitation real(r8) surfric(pcols) ! surface friction velocity real(r8) obklen(pcols) ! Obukhov length real(r8) :: fh2o(pcols) ! h2o flux to balance source from methane chemistry real(r8) :: flx_heat(pcols) ! Heat flux for check_energy_chng. - real(r8) :: tmp_q (pcols,pver) ! tmp space - real(r8) :: tmp_cldliq(pcols,pver) ! tmp space - real(r8) :: tmp_cldice(pcols,pver) ! tmp space real(r8) :: tmp_trac (pcols,pver,pcnst) ! tmp space real(r8) :: tmp_pdel (pcols,pver) ! tmp space real(r8) :: tmp_ps (pcols) ! tmp space + real(r8) :: scaling(pcols,pver) logical :: moist_mixing_ratio_dycore ! physics buffer fields for total energy and mass adjustment @@ -1449,6 +1449,8 @@ subroutine tphysac (ztodt, cam_in, & real(r8), pointer, dimension(:,:) :: qini real(r8), pointer, dimension(:,:) :: cldliqini real(r8), pointer, dimension(:,:) :: cldiceini + real(r8), pointer, dimension(:,:) :: totliqini + real(r8), pointer, dimension(:,:) :: toticeini real(r8), pointer, dimension(:,:) :: dtcore real(r8), pointer, dimension(:,:) :: dqcore real(r8), pointer, dimension(:,:) :: ducore @@ -1483,6 +1485,8 @@ subroutine tphysac (ztodt, cam_in, & call pbuf_get_field(pbuf, qini_idx, qini) call pbuf_get_field(pbuf, cldliqini_idx, cldliqini) call pbuf_get_field(pbuf, cldiceini_idx, cldiceini) + call pbuf_get_field(pbuf, totliqini_idx, totliqini) + call pbuf_get_field(pbuf, toticeini_idx, toticeini) ifld = pbuf_get_index('CLD') call pbuf_get_field(pbuf, ifld, cld, start=(/1,1,itim_old/),kount=(/pcols,pver,1/)) @@ -1823,8 +1827,8 @@ subroutine tphysac (ztodt, cam_in, & fh2o, surfric, obklen, flx_heat) end if - call calc_te_and_aam_budgets(state, 'phAP') - call calc_te_and_aam_budgets(state, 'dyAP',vc=vc_dycore) + call tot_energy_phys(state, 'phAP') + call tot_energy_phys(state, 'dyAP',vc=vc_dycore) !--------------------------------------------------------------------------------- ! Enforce charge neutrality after O+ change from ionos_tend @@ -1855,7 +1859,9 @@ subroutine tphysac (ztodt, cam_in, & !-------------- Energy budget checks vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ! Save total energy for global fixer in next timestep - + ! + ! This call must be after the last parameterization and call to physics_update + ! call pbuf_set_field(pbuf, teout_idx, state%te_cur(:,dyn_te_idx), (/1,itim_old/),(/pcols,1/)) if (shallow_scheme .eq. 'UNICON') then @@ -1874,62 +1880,73 @@ subroutine tphysac (ztodt, cam_in, & call unicon_cam_org_diags(state, pbuf) end if - moist_mixing_ratio_dycore = dycore_is('LR').or. dycore_is('FV3') ! ! FV: convert dry-type mixing ratios to moist here because physics_dme_adjust ! assumes moist. This is done in p_d_coupling for other dynamics. Bundy, Feb 2004. - if (moist_mixing_ratio_dycore) call set_dry_to_wet(state) ! Physics had dry, dynamics wants moist - - ! Scale dry mass and energy (does nothing if dycore is EUL or SLD) - call cnst_get_ind('CLDLIQ', ixcldliq) - call cnst_get_ind('CLDICE', ixcldice) - - tmp_q (:ncol,:pver) = state%q(:ncol,:pver,1) - tmp_cldliq(:ncol,:pver) = state%q(:ncol,:pver,ixcldliq) - tmp_cldice(:ncol,:pver) = state%q(:ncol,:pver,ixcldice) + moist_mixing_ratio_dycore = dycore_is('LR').or. dycore_is('FV3') + ! + ! update cp/cv for energy computation based in updated water variables + ! + call cam_thermo_water_update(state%q(:ncol,:,:), lchnk, ncol, vc_dycore,& + to_dry_factor=state%pdel(:ncol,:)/state%pdeldry(:ncol,:)) ! for dry mixing ratio dycore, physics_dme_adjust is called for energy diagnostic purposes only. ! So, save off tracers - if (.not.moist_mixing_ratio_dycore.and.& - (hist_fld_active('SE_phAM').or.hist_fld_active('KE_phAM').or.hist_fld_active('WV_phAM').or.& - hist_fld_active('WL_phAM').or.hist_fld_active('WI_phAM').or.hist_fld_active('MR_phAM').or.& - hist_fld_active('MO_phAM'))) then - tmp_trac(:ncol,:pver,:pcnst) = state%q(:ncol,:pver,:pcnst) - tmp_pdel(:ncol,:pver) = state%pdel(:ncol,:pver) - tmp_ps(:ncol) = state%ps(:ncol) - + if (.not.moist_mixing_ratio_dycore) then + ! + ! for dry-mixing ratio based dycores dme_adjust takes place in the dynamical core + ! + ! only compute dme_adjust for diagnostics purposes + ! + if (thermo_budget_history) then + tmp_trac(:ncol,:pver,:pcnst) = state%q(:ncol,:pver,:pcnst) + tmp_pdel(:ncol,:pver) = state%pdel(:ncol,:pver) + tmp_ps(:ncol) = state%ps(:ncol) + call physics_dme_adjust(state, tend, qini, totliqini, toticeini, ztodt) + call tot_energy_phys(state, 'phAM') + call tot_energy_phys(state, 'dyAM', vc=vc_dycore) + ! Restore pre-"physics_dme_adjust" tracers + state%q(:ncol,:pver,:pcnst) = tmp_trac(:ncol,:pver,:pcnst) + state%pdel(:ncol,:pver) = tmp_pdel(:ncol,:pver) + state%ps(:ncol) = tmp_ps(:ncol) + end if + else + ! + ! for moist-mixing ratio based dycores + ! + ! Note: this operation will NOT be reverted with set_wet_to_dry after set_dry_to_wet call + ! call set_dry_to_wet(state) - call physics_dme_adjust(state, tend, qini, ztodt) - - call calc_te_and_aam_budgets(state, 'phAM') - call calc_te_and_aam_budgets(state, 'dyAM',vc=vc_dycore) - ! Restore pre-"physics_dme_adjust" tracers - state%q(:ncol,:pver,:pcnst) = tmp_trac(:ncol,:pver,:pcnst) - state%pdel(:ncol,:pver) = tmp_pdel(:ncol,:pver) - state%ps(:ncol) = tmp_ps(:ncol) - end if - - if (moist_mixing_ratio_dycore) then - if (trim(cam_take_snapshot_before) == "physics_dme_adjust") then - call cam_snapshot_all_outfld_tphysac(cam_snapshot_before_num, state, tend, cam_in, cam_out, pbuf,& + call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& fh2o, surfric, obklen, flx_heat) end if - - call physics_dme_adjust(state, tend, qini, ztodt) - + call physics_dme_adjust(state, tend, qini, totliqini, toticeini, ztodt) if (trim(cam_take_snapshot_after) == "physics_dme_adjust") then - call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& - fh2o, surfric, obklen, flx_heat) + call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& + fh2o, surfric, obklen, flx_heat) end if - call calc_te_and_aam_budgets(state, 'phAM') - call calc_te_and_aam_budgets(state, 'dyAM',vc=vc_dycore) + call tot_energy_phys(state, 'phAM') + call tot_energy_phys(state, 'dyAM', vc=vc_dycore) endif -!!! REMOVE THIS CALL, SINCE ONLY Q IS BEING ADJUSTED. WON'T BALANCE ENERGY. TE IS SAVED BEFORE THIS -!!! call check_energy_chng(state, tend, "drymass", nstep, ztodt, zero, zero, zero, zero) + if (vc_dycore == vc_height.or.vc_dycore == vc_dry_pressure) then + ! + ! MPAS and SE specific scaling of temperature for enforcing energy consistency + ! (and to make sure that temperature dependent diagnostic tendencies + ! are computed correctly; e.g. dtcore) + ! + scaling(1:ncol,:) = cpairv(:ncol,:,lchnk)/cp_or_cv_dycore(:ncol,:,lchnk) + state%T(1:ncol,:) = state%temp_ini(1:ncol,:)+& + scaling(1:ncol,:)*(state%T(1:ncol,:)-state%temp_ini(1:ncol,:)) + tend%dtdt(:ncol,:) = scaling(:ncol,:)*tend%dtdt(:ncol,:) + ! + ! else: do nothing for dycores with energy consistent with CAM physics + ! + end if + ! store T, U, and V in buffer for use in computing dynamics T-tendency in next timestep do k = 1,pver @@ -1954,8 +1971,7 @@ subroutine tphysac (ztodt, cam_in, & endif endif - call diag_phys_tend_writeout (state, pbuf, tend, ztodt, tmp_q, tmp_cldliq, tmp_cldice, & - qini, cldliqini, cldiceini) + call diag_phys_tend_writeout (state, pbuf, tend, ztodt, qini, cldliqini, cldiceini) call clybry_fam_set( ncol, lchnk, map2chm, state%q, pbuf ) @@ -2004,18 +2020,20 @@ subroutine tphysbc (ztodt, state, & use physics_types, only: physics_state, physics_tend, physics_ptend, & physics_update, physics_ptend_init, physics_ptend_sum, & physics_state_check, physics_ptend_scale, & - phys_te_idx, dyn_te_idx + dyn_te_idx use cam_diagnostics, only: diag_conv_tend_ini, diag_phys_writeout, diag_conv, diag_export, diag_state_b4_phys_write use cam_diagnostics, only: diag_clip_tend_writeout use cam_history, only: outfld - use physconst, only: cpair, latvap + use physconst, only: latvap use constituents, only: pcnst, qmin, cnst_get_ind + use air_composition, only: thermodynamic_active_species_liq_num,thermodynamic_active_species_liq_idx + use air_composition, only: thermodynamic_active_species_ice_num,thermodynamic_active_species_ice_idx use convect_deep, only: convect_deep_tend, convect_deep_tend_2, deep_scheme_does_scav_trans use time_manager, only: is_first_step, get_nstep use convect_shallow, only: convect_shallow_tend use check_energy, only: check_energy_chng, check_energy_fix, check_energy_timestep_init use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng - use check_energy, only: calc_te_and_aam_budgets + use check_energy, only: tot_energy_phys use dycore, only: dycore_is use aero_model, only: aero_model_wetdep use carma_intr, only: carma_wetdep_tend, carma_timestep_tend @@ -2084,6 +2102,7 @@ subroutine tphysbc (ztodt, state, & integer :: i ! column indicex integer :: ixcldice, ixcldliq, ixq ! constituent indices for cloud liquid and ice water. + integer :: m, m_cnst ! for macro/micro co-substepping integer :: macmic_it ! iteration variables real(r8) :: cld_macmic_ztodt ! modified timestep @@ -2097,6 +2116,8 @@ subroutine tphysbc (ztodt, state, & real(r8), pointer, dimension(:,:) :: qini real(r8), pointer, dimension(:,:) :: cldliqini real(r8), pointer, dimension(:,:) :: cldiceini + real(r8), pointer, dimension(:,:) :: totliqini + real(r8), pointer, dimension(:,:) :: toticeini real(r8), pointer, dimension(:,:) :: dtcore real(r8), pointer, dimension(:,:) :: dqcore real(r8), pointer, dimension(:,:) :: ducore @@ -2145,8 +2166,6 @@ subroutine tphysbc (ztodt, state, & type(check_tracers_data):: tracerint ! energy integrals and cummulative boundary fluxes real(r8) :: zero_tracers(pcols,pcnst) - logical :: lq(pcnst) - !----------------------------------------------------------------------- call t_startf('bc_init') @@ -2172,6 +2191,8 @@ subroutine tphysbc (ztodt, state, & call pbuf_get_field(pbuf, qini_idx, qini) call pbuf_get_field(pbuf, cldliqini_idx, cldliqini) call pbuf_get_field(pbuf, cldiceini_idx, cldiceini) + call pbuf_get_field(pbuf, totliqini_idx, totliqini) + call pbuf_get_field(pbuf, toticeini_idx, toticeini) call pbuf_get_field(pbuf, dtcore_idx, dtcore, start=(/1,1,itim_old/), kount=(/pcols,pver,1/) ) call pbuf_get_field(pbuf, dqcore_idx, dqcore, start=(/1,1,itim_old/), kount=(/pcols,pver,1/) ) @@ -2217,16 +2238,16 @@ subroutine tphysbc (ztodt, state, & !=================================================== call t_startf('energy_fixer') - call calc_te_and_aam_budgets(state, 'phBF') - call calc_te_and_aam_budgets(state, 'dyBF',vc=vc_dycore) + call tot_energy_phys(state, 'phBF') + call tot_energy_phys(state, 'dyBF',vc=vc_dycore) if (.not.dycore_is('EUL')) then call check_energy_fix(state, ptend, nstep, flx_heat) call physics_update(state, ptend, ztodt, tend) call check_energy_chng(state, tend, "chkengyfix", nstep, ztodt, zero, zero, zero, flx_heat) call outfld( 'EFIX', flx_heat , pcols, lchnk ) end if - call calc_te_and_aam_budgets(state, 'phBP') - call calc_te_and_aam_budgets(state, 'dyBP',vc=vc_dycore) + call tot_energy_phys(state, 'phBP') + call tot_energy_phys(state, 'dyBP',vc=vc_dycore) ! Save state for convective tendency calculations. call diag_conv_tend_ini(state, pbuf) @@ -2237,6 +2258,18 @@ subroutine tphysbc (ztodt, state, & cldliqini(:ncol,:pver) = state%q(:ncol,:pver,ixcldliq) cldiceini(:ncol,:pver) = state%q(:ncol,:pver,ixcldice) + totliqini(:ncol,:pver) = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_liq_num + m = thermodynamic_active_species_liq_idx(m_cnst) + totliqini(:ncol,:pver) = totliqini(:ncol,:pver)+state%q(:ncol,:pver,m) + end do + toticeini(:ncol,:pver) = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_ice_num + m = thermodynamic_active_species_ice_idx(m_cnst) + toticeini(:ncol,:pver) = toticeini(:ncol,:pver)+state%q(:ncol,:pver,m) + end do + + call outfld('TEOUT', teout , pcols, lchnk ) call outfld('TEINP', state%te_ini(:,dyn_te_idx), pcols, lchnk ) call outfld('TEFIX', state%te_cur(:,dyn_te_idx), pcols, lchnk ) @@ -2859,7 +2892,6 @@ subroutine phys_timestep_init(phys_state, cam_in, cam_out, pbuf2d) ! datasets. ! !----------------------------------------------------------------------------------- - use shr_kind_mod, only: r8 => shr_kind_r8 use chemistry, only: chem_timestep_init use chem_surfvals, only: chem_surfvals_set use physics_types, only: physics_state diff --git a/src/physics/cam_dev/physpkg.F90 b/src/physics/cam_dev/physpkg.F90 index d2fe6f7ca0..7452f9e115 100644 --- a/src/physics/cam_dev/physpkg.F90 +++ b/src/physics/cam_dev/physpkg.F90 @@ -71,6 +71,8 @@ module physpkg integer :: qini_idx = 0 integer :: cldliqini_idx = 0 integer :: cldiceini_idx = 0 + integer :: totliqini_idx = 0 + integer :: toticeini_idx = 0 integer :: prec_str_idx = 0 integer :: snow_str_idx = 0 @@ -110,6 +112,7 @@ subroutine phys_register use cam_control_mod, only: moist_physics use chemistry, only: chem_register + use mo_lightning, only: lightning_register use cloud_fraction, only: cldfrc_register use microp_driver, only: microp_driver_register use microp_aero, only: microp_aero_register @@ -194,6 +197,8 @@ subroutine phys_register call pbuf_add_field('QINI', 'physpkg', dtype_r8, (/pcols,pver/), qini_idx) call pbuf_add_field('CLDLIQINI', 'physpkg', dtype_r8, (/pcols,pver/), cldliqini_idx) call pbuf_add_field('CLDICEINI', 'physpkg', dtype_r8, (/pcols,pver/), cldiceini_idx) + call pbuf_add_field('TOTLIQINI', 'physpkg', dtype_r8, (/pcols,pver/), totliqini_idx) + call pbuf_add_field('TOTICEINI', 'physpkg', dtype_r8, (/pcols,pver/), toticeini_idx) ! check energy package call check_energy_register @@ -253,6 +258,9 @@ subroutine phys_register ! register chemical constituents including aerosols ... call chem_register() + ! add prognostic lightning flash freq pbuf fld + call lightning_register() + ! co2 constituents call co2_register() @@ -699,6 +707,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use cam_control_mod, only: initial_run use check_energy, only: check_energy_init use chemistry, only: chem_init + use mo_lightning, only: lightning_init use prescribed_ozone, only: prescribed_ozone_init use prescribed_ghg, only: prescribed_ghg_init use prescribed_aero, only: prescribed_aero_init @@ -749,6 +758,8 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use nudging, only: Nudge_Model, nudging_init use cam_snapshot, only: cam_snapshot_init use cam_history, only: addfld, register_vector_field, add_default + use cam_budget, only: cam_budget_init + use phys_grid_ctem, only: phys_grid_ctem_init ! Input/output arguments type(physics_state), pointer :: phys_state(:) @@ -831,6 +842,9 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) ! Prognostic chemistry. call chem_init(phys_state,pbuf2d) + ! Lightning flash frq and NOx prod + call lightning_init( pbuf2d ) + ! Prescribed tracers call prescribed_ozone_init() call prescribed_ghg_init() @@ -928,9 +942,15 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) ! Initialize qneg3 and qneg4 call qneg_init() + ! Initialize phys TEM diagnostics + call phys_grid_ctem_init() + ! Initialize the snapshot capability call cam_snapshot_init(cam_in, cam_out, pbuf2d, begchunk) + ! Initialize the budget capability + call cam_budget_init() + ! addfld calls for U, V tendency budget variables that are output in ! tphysac, tphysbc call addfld ( 'UTEND_DCONV', (/ 'lev' /), 'A', 'm/s2', 'Zonal wind tendency by deep convection') @@ -1192,9 +1212,9 @@ subroutine phys_run2(phys_state, ztodt, phys_tend, pbuf2d, cam_out, & ! call get_met_srf2( cam_in ) #endif - ! Set lightning production of NO + ! lightning flash freq and prod rate of NOx call t_startf ('lightning_no_prod') - call lightning_no_prod( phys_state, pbuf2d, cam_in ) + call lightning_no_prod( phys_state, pbuf2d, cam_in ) call t_stopf ('lightning_no_prod') call t_barrierf('sync_ac_physics', mpicom) @@ -1248,6 +1268,8 @@ subroutine phys_final( phys_state, phys_tend, pbuf2d ) use carma_intr, only: carma_final use wv_saturation, only: wv_sat_final use microp_aero, only: microp_aero_final + use phys_grid_ctem, only: phys_grid_ctem_final + use nudging, only: Nudge_Model, nudging_final !----------------------------------------------------------------------- ! @@ -1270,6 +1292,8 @@ subroutine phys_final( phys_state, phys_tend, pbuf2d ) call carma_final call wv_sat_final call microp_aero_final() + call phys_grid_ctem_final() + if(Nudge_Model) call nudging_final() end subroutine phys_final @@ -1309,7 +1333,7 @@ subroutine tphysac (ztodt, cam_in, & use aoa_tracers, only: aoa_tracers_timestep_tend use physconst, only: rhoh2o use aero_model, only: aero_model_drydep - use check_energy, only: check_energy_chng, calc_te_and_aam_budgets + use check_energy, only: check_energy_chng, tot_energy_phys use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng use time_manager, only: get_nstep use cam_abortutils, only: endrun @@ -1352,6 +1376,10 @@ subroutine tphysac (ztodt, cam_in, & use carma_flags_mod, only: carma_do_aerosol, carma_do_emission, carma_do_detrain use carma_flags_mod, only: carma_do_cldice, carma_do_cldliq, carma_do_wetdep use dyn_tests_utils, only: vc_dycore + use cam_thermo, only: cam_thermo_water_update + use cam_budget, only: thermo_budget_history + use dyn_tests_utils, only: vc_dycore, vc_height, vc_dry_pressure + use air_composition, only: cpairv, cp_or_cv_dycore ! ! Arguments ! @@ -1437,12 +1465,10 @@ subroutine tphysac (ztodt, cam_in, & real(r8) obklen(pcols) ! Obukhov length real(r8) :: fh2o(pcols) ! h2o flux to balance source from methane chemistry real(r8) :: flx_heat(pcols) ! Heat flux for check_energy_chng. - real(r8) :: tmp_q (pcols,pver) ! tmp space - real(r8) :: tmp_cldliq(pcols,pver) ! tmp space - real(r8) :: tmp_cldice(pcols,pver) ! tmp space real(r8) :: tmp_trac (pcols,pver,pcnst) ! tmp space real(r8) :: tmp_pdel (pcols,pver) ! tmp space real(r8) :: tmp_ps (pcols) ! tmp space + real(r8) :: scaling(pcols,pver) logical :: moist_mixing_ratio_dycore ! physics buffer fields for total energy and mass adjustment @@ -1452,6 +1478,8 @@ subroutine tphysac (ztodt, cam_in, & real(r8), pointer, dimension(:,:) :: qini real(r8), pointer, dimension(:,:) :: cldliqini real(r8), pointer, dimension(:,:) :: cldiceini + real(r8), pointer, dimension(:,:) :: totliqini + real(r8), pointer, dimension(:,:) :: toticeini real(r8), pointer, dimension(:,:) :: dtcore real(r8), pointer, dimension(:,:) :: dqcore real(r8), pointer, dimension(:,:) :: ducore @@ -1487,6 +1515,8 @@ subroutine tphysac (ztodt, cam_in, & call pbuf_get_field(pbuf, qini_idx, qini) call pbuf_get_field(pbuf, cldliqini_idx, cldliqini) call pbuf_get_field(pbuf, cldiceini_idx, cldiceini) + call pbuf_get_field(pbuf, totliqini_idx, totliqini) + call pbuf_get_field(pbuf, toticeini_idx, toticeini) ifld = pbuf_get_index('CLD') call pbuf_get_field(pbuf, ifld, cld, start=(/1,1,itim_old/),kount=(/pcols,pver,1/)) @@ -2264,8 +2294,8 @@ subroutine tphysac (ztodt, cam_in, & call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) end if - call calc_te_and_aam_budgets(state, 'phAP') - call calc_te_and_aam_budgets(state, 'dyAP',vc=vc_dycore) + call tot_energy_phys(state, 'phAP') + call tot_energy_phys(state, 'dyAP',vc=vc_dycore) !--------------------------------------------------------------------------------- ! Enforce charge neutrality after O+ change from ionos_tend @@ -2295,61 +2325,77 @@ subroutine tphysac (ztodt, cam_in, & !-------------- Energy budget checks vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv ! Save total energy for global fixer in next timestep + ! + ! This call must be after the last parameterization and call to physics_update + ! call pbuf_set_field(pbuf, teout_idx, state%te_cur(:,dyn_te_idx), (/1,itim_old/),(/pcols,1/)) ! ! FV: convert dry-type mixing ratios to moist here because physics_dme_adjust ! assumes moist. This is done in p_d_coupling for other dynamics. Bundy, Feb 2004. moist_mixing_ratio_dycore = dycore_is('LR').or. dycore_is('FV3') - if (moist_mixing_ratio_dycore) call set_dry_to_wet(state) ! Physics had dry, dynamics wants moist - - ! Scale dry mass and energy (does nothing if dycore is EUL or SLD) - tmp_q (:ncol,:pver) = state%q(:ncol,:pver,ixq) - tmp_cldliq(:ncol,:pver) = state%q(:ncol,:pver,ixcldliq) - tmp_cldice(:ncol,:pver) = state%q(:ncol,:pver,ixcldice) + ! + ! update cp/cv for energy computation based in updated water variables + ! + call cam_thermo_water_update(state%q(:ncol,:,:), lchnk, ncol, vc_dycore,& + to_dry_factor=state%pdel(:ncol,:)/state%pdeldry(:ncol,:)) ! for dry mixing ratio dycore, physics_dme_adjust is called for energy diagnostic purposes only. ! So, save off tracers - if (.not.moist_mixing_ratio_dycore.and.& - (hist_fld_active('SE_phAM').or.hist_fld_active('KE_phAM').or.hist_fld_active('WV_phAM').or.& - hist_fld_active('WL_phAM').or.hist_fld_active('WI_phAM').or.hist_fld_active('MR_phAM').or.& - hist_fld_active('MO_phAM'))) then - tmp_trac(:ncol,:pver,:pcnst) = state%q(:ncol,:pver,:pcnst) - tmp_pdel(:ncol,:pver) = state%pdel(:ncol,:pver) - tmp_ps(:ncol) = state%ps(:ncol) - + if (.not.moist_mixing_ratio_dycore) then + ! + ! for dry-mixing ratio based dycores dme_adjust takes place in the dynamical core + ! + ! only compute dme_adjust for diagnostics purposes + ! + if (thermo_budget_history) then + tmp_trac(:ncol,:pver,:pcnst) = state%q(:ncol,:pver,:pcnst) + tmp_pdel(:ncol,:pver) = state%pdel(:ncol,:pver) + tmp_ps(:ncol) = state%ps(:ncol) + call physics_dme_adjust(state, tend, qini, totliqini, toticeini, ztodt) + call tot_energy_phys(state, 'phAM') + call tot_energy_phys(state, 'dyAM', vc=vc_dycore) + ! Restore pre-"physics_dme_adjust" tracers + state%q(:ncol,:pver,:pcnst) = tmp_trac(:ncol,:pver,:pcnst) + state%pdel(:ncol,:pver) = tmp_pdel(:ncol,:pver) + state%ps(:ncol) = tmp_ps(:ncol) + end if + else + ! + ! for moist-mixing ratio based dycores + ! + ! Note: this operation will NOT be reverted with set_wet_to_dry after set_dry_to_wet call + ! call set_dry_to_wet(state) - - call physics_dme_adjust(state, tend, qini, ztodt) - - call calc_te_and_aam_budgets(state, 'phAM') - call calc_te_and_aam_budgets(state, 'dyAM',vc=vc_dycore) - ! Restore pre-"physics_dme_adjust" tracers - state%q(:ncol,:pver,:pcnst) = tmp_trac(:ncol,:pver,:pcnst) - state%pdel(:ncol,:pver) = tmp_pdel(:ncol,:pver) - state%ps(:ncol) = tmp_ps(:ncol) - end if - - if (moist_mixing_ratio_dycore) then - if (trim(cam_take_snapshot_before) == "physics_dme_adjust") then call cam_snapshot_all_outfld_tphysac(cam_snapshot_before_num, state, tend, cam_in, cam_out, pbuf,& fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) end if - - call physics_dme_adjust(state, tend, qini, ztodt) - + call physics_dme_adjust(state, tend, qini, totliqini, toticeini, ztodt) if (trim(cam_take_snapshot_after) == "physics_dme_adjust") then - call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& - fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) + call cam_snapshot_all_outfld_tphysac(cam_snapshot_after_num, state, tend, cam_in, cam_out, pbuf,& + fh2o, surfric, obklen, flx_heat, cmfmc, dlf, det_s, det_ice, net_flx) end if - call calc_te_and_aam_budgets(state, 'phAM') - call calc_te_and_aam_budgets(state, 'dyAM',vc=vc_dycore) + call tot_energy_phys(state, 'phAM') + call tot_energy_phys(state, 'dyAM', vc=vc_dycore) endif -!!! REMOVE THIS CALL, SINCE ONLY Q IS BEING ADJUSTED. WON'T BALANCE ENERGY. TE IS SAVED BEFORE THIS -!!! call check_energy_chng(state, tend, "drymass", nstep, ztodt, zero, zero, zero, zero) + if (vc_dycore == vc_height.or.vc_dycore == vc_dry_pressure) then + ! + ! MPAS and SE specific scaling of temperature for enforcing energy consistency + ! (and to make sure that temperature dependent diagnostic tendencies + ! are computed correctly; e.g. dtcore) + ! + scaling(1:ncol,:) = cpairv(:ncol,:,lchnk)/cp_or_cv_dycore(:ncol,:,lchnk) + state%T(1:ncol,:) = state%temp_ini(1:ncol,:)+& + scaling(1:ncol,:)*(state%T(1:ncol,:)-state%temp_ini(1:ncol,:)) + tend%dtdt(:ncol,:) = scaling(:ncol,:)*tend%dtdt(:ncol,:) + ! + ! else: do nothing for dycores with energy consistent with CAM physics + ! + end if + ! store T, U, and V in buffer for use in computing dynamics T-tendency in next timestep do k = 1,pver @@ -2374,8 +2420,7 @@ subroutine tphysac (ztodt, cam_in, & endif endif - call diag_phys_tend_writeout (state, pbuf, tend, ztodt, tmp_q, tmp_cldliq, tmp_cldice, & - qini, cldliqini, cldiceini) + call diag_phys_tend_writeout (state, pbuf, tend, ztodt, qini, cldliqini, cldiceini) call clybry_fam_set( ncol, lchnk, map2chm, state%q, pbuf ) @@ -2419,12 +2464,14 @@ subroutine tphysbc (ztodt, state, & use cam_diagnostics, only: diag_conv_tend_ini, diag_conv, diag_export, diag_state_b4_phys_write use cam_history, only: outfld use constituents, only: qmin + use air_composition, only: thermodynamic_active_species_liq_num,thermodynamic_active_species_liq_idx + use air_composition, only: thermodynamic_active_species_ice_num,thermodynamic_active_species_ice_idx use convect_deep, only: convect_deep_tend use time_manager, only: is_first_step, get_nstep use convect_diagnostics,only: convect_diagnostics_calc use check_energy, only: check_energy_chng, check_energy_fix use check_energy, only: check_tracers_data, check_tracers_init - use check_energy, only: calc_te_and_aam_budgets + use check_energy, only: tot_energy_phys use dycore, only: dycore_is use radiation, only: radiation_tend use perf_mod @@ -2474,6 +2521,7 @@ subroutine tphysbc (ztodt, state, & integer :: i ! column indicex integer :: ixcldice, ixcldliq, ixq ! constituent indices for cloud liquid and ice water. + integer :: m, m_cnst ! physics buffer fields to compute tendencies for stratiform package integer itim_old, ifld @@ -2484,6 +2532,8 @@ subroutine tphysbc (ztodt, state, & real(r8), pointer, dimension(:,:) :: qini real(r8), pointer, dimension(:,:) :: cldliqini real(r8), pointer, dimension(:,:) :: cldiceini + real(r8), pointer, dimension(:,:) :: totliqini + real(r8), pointer, dimension(:,:) :: toticeini real(r8), pointer, dimension(:,:) :: dtcore real(r8), pointer, dimension(:,:) :: dqcore real(r8), pointer, dimension(:,:) :: ducore @@ -2548,6 +2598,8 @@ subroutine tphysbc (ztodt, state, & call pbuf_get_field(pbuf, qini_idx, qini) call pbuf_get_field(pbuf, cldliqini_idx, cldliqini) call pbuf_get_field(pbuf, cldiceini_idx, cldiceini) + call pbuf_get_field(pbuf, totliqini_idx, totliqini) + call pbuf_get_field(pbuf, toticeini_idx, toticeini) call pbuf_get_field(pbuf, dtcore_idx, dtcore, start=(/1,1,itim_old/), kount=(/pcols,pver,1/) ) call pbuf_get_field(pbuf, dqcore_idx, dqcore, start=(/1,1,itim_old/), kount=(/pcols,pver,1/) ) @@ -2594,8 +2646,8 @@ subroutine tphysbc (ztodt, state, & !=================================================== call t_startf('energy_fixer') - call calc_te_and_aam_budgets(state, 'phBF') - call calc_te_and_aam_budgets(state, 'dyBF',vc=vc_dycore) + call tot_energy_phys(state, 'phBF') + call tot_energy_phys(state, 'dyBF',vc=vc_dycore) if (.not.dycore_is('EUL')) then call check_energy_fix(state, ptend, nstep, flx_heat) @@ -2604,8 +2656,8 @@ subroutine tphysbc (ztodt, state, & call outfld( 'EFIX', flx_heat , pcols, lchnk ) end if - call calc_te_and_aam_budgets(state, 'phBP') - call calc_te_and_aam_budgets(state, 'dyBP',vc=vc_dycore) + call tot_energy_phys(state, 'phBP') + call tot_energy_phys(state, 'dyBP',vc=vc_dycore) ! Save state for convective tendency calculations. call diag_conv_tend_ini(state, pbuf) @@ -2616,6 +2668,18 @@ subroutine tphysbc (ztodt, state, & cldliqini(:ncol,:pver) = state%q(:ncol,:pver,ixcldliq) cldiceini(:ncol,:pver) = state%q(:ncol,:pver,ixcldice) + totliqini(:ncol,:pver) = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_liq_num + m = thermodynamic_active_species_liq_idx(m_cnst) + totliqini(:ncol,:pver) = totliqini(:ncol,:pver)+state%q(:ncol,:pver,m) + end do + toticeini(:ncol,:pver) = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_ice_num + m = thermodynamic_active_species_ice_idx(m_cnst) + toticeini(:ncol,:pver) = toticeini(:ncol,:pver)+state%q(:ncol,:pver,m) + end do + + call outfld('TEOUT', teout , pcols, lchnk ) call outfld('TEINP', state%te_ini(:,dyn_te_idx), pcols, lchnk ) call outfld('TEFIX', state%te_cur(:,dyn_te_idx), pcols, lchnk ) @@ -2828,6 +2892,7 @@ subroutine phys_timestep_init(phys_state, cam_in, cam_out, pbuf2d) use iop_forcing, only: scam_use_iop_srf use nudging, only: Nudge_Model, nudging_timestep_init use waccmx_phys_intr, only: waccmx_phys_ion_elec_temp_timestep_init + use phys_grid_ctem, only: phys_grid_ctem_diags implicit none @@ -2895,6 +2960,9 @@ subroutine phys_timestep_init(phys_state, cam_in, cam_out, pbuf2d) !---------------------------------- if(Nudge_Model) call nudging_timestep_init(phys_state) + ! Update TEM diagnostics + call phys_grid_ctem_diags(phys_state) + end subroutine phys_timestep_init end module physpkg diff --git a/src/physics/simple/physpkg.F90 b/src/physics/simple/physpkg.F90 index 353c245318..9c1e4c61bf 100644 --- a/src/physics/simple/physpkg.F90 +++ b/src/physics/simple/physpkg.F90 @@ -47,6 +47,8 @@ module physpkg integer :: qini_idx = 0 integer :: cldliqini_idx = 0 integer :: cldiceini_idx = 0 + integer :: totliqini_idx = 0 + integer :: toticeini_idx = 0 logical :: state_debug_checks ! Debug physics_state. @@ -117,6 +119,8 @@ subroutine phys_register if (moist_physics) then call pbuf_add_field('CLDLIQINI', 'physpkg', dtype_r8, (/pcols,pver/), cldliqini_idx) call pbuf_add_field('CLDICEINI', 'physpkg', dtype_r8, (/pcols,pver/), cldiceini_idx) + call pbuf_add_field('TOTLIQINI', 'physpkg', dtype_r8, (/pcols,pver/), totliqini_idx) + call pbuf_add_field('TOTICEINI', 'physpkg', dtype_r8, (/pcols,pver/), toticeini_idx) end if ! check energy package @@ -198,6 +202,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) use phys_debug_util, only: phys_debug_init use qneg_module, only: qneg_init use cam_snapshot, only: cam_snapshot_init + use cam_budget, only: cam_budget_init ! Input/output arguments type(physics_state), pointer :: phys_state(:) @@ -267,6 +272,9 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_in, cam_out ) ! Initialize the snapshot capability call cam_snapshot_init(cam_in, cam_out, pbuf2d, begchunk) + ! Initialize energy budgets + call cam_budget_init() + end subroutine phys_init !====================================================================================== @@ -469,9 +477,12 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) use cam_diagnostics, only: diag_phys_tend_writeout, diag_surf use tj2016_cam, only: thatcher_jablonowski_sfc_pbl_hs_tend use dycore, only: dycore_is - use check_energy, only: calc_te_and_aam_budgets + use check_energy, only: tot_energy_phys use cam_history, only: hist_fld_active - + use cam_thermo, only: cam_thermo_water_update + use cam_budget, only: thermo_budget_history + use dyn_tests_utils, only: vc_dycore, vc_height, vc_dry_pressure + use air_composition, only: cpairv, cp_or_cv_dycore ! Arguments ! real(r8), intent(in) :: ztodt ! Two times model timestep (2 delta-t) @@ -492,20 +503,24 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) real(r8), pointer :: qini(:,:) real(r8), pointer :: cldliqini(:,:) real(r8), pointer :: cldiceini(:,:) + real(r8), pointer :: totliqini(:,:) + real(r8), pointer :: toticeini(:,:) integer :: ixcldliq integer :: ixcldice integer :: k - integer :: ncol + integer :: ncol, lchnk integer :: itim_old logical :: moist_mixing_ratio_dycore real(r8) :: tmp_trac (pcols,pver,pcnst) ! tmp space real(r8) :: tmp_pdel (pcols,pver) ! tmp space real(r8) :: tmp_ps (pcols) ! tmp space + real(r8) :: scaling(pcols,pver) !-------------------------------------------------------------------------- ! number of active atmospheric columns ncol = state%ncol + lchnk = state%lchnk ! Associate pointers with physics buffer fields itim_old = pbuf_old_tim_idx() @@ -518,11 +533,17 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) if (moist_physics) then call pbuf_get_field(pbuf, cldliqini_idx, cldliqini) call pbuf_get_field(pbuf, cldiceini_idx, cldiceini) + call pbuf_get_field(pbuf, totliqini_idx, totliqini) + call pbuf_get_field(pbuf, toticeini_idx, toticeini) else allocate(cldliqini(pcols, pver)) cldliqini = 0.0_r8 allocate(cldiceini(pcols, pver)) cldiceini = 0.0_r8 + allocate(totliqini(pcols, pver)) + totliqini = 0.0_r8 + allocate(toticeini(pcols, pver)) + toticeini = 0.0_r8 end if !========================= @@ -534,17 +555,19 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) call physics_update(state, ptend, ztodt, tend) end if - call calc_te_and_aam_budgets(state, 'phAP') - call calc_te_and_aam_budgets(state, 'dyAP',vc=vc_dycore) + call tot_energy_phys(state, 'phAP') + call tot_energy_phys(state, 'dyAP',vc=vc_dycore) ! FV: convert dry-type mixing ratios to moist here because ! physics_dme_adjust assumes moist. This is done in p_d_coupling for ! other dynamics. Bundy, Feb 2004. ! moist_mixing_ratio_dycore = dycore_is('LR').or. dycore_is('FV3') - if (moist_physics .and. moist_mixing_ratio_dycore) then - call set_dry_to_wet(state) ! Physics had dry, dynamics wants moist - end if + ! + ! update cp/cv for energy computation based in updated water variables + ! + call cam_thermo_water_update(state%q(:ncol,:,:), lchnk, ncol, vc_dycore,& + to_dry_factor=state%pdel(:ncol,:)/state%pdeldry(:ncol,:)) if (moist_physics) then ! Scale dry mass and energy (does nothing if dycore is EUL or SLD) @@ -561,44 +584,59 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) else tmp_cldice(:ncol,:pver) = 0.0_r8 end if - - ! for dry mixing ratio dycore, physics_dme_adjust is called for energy diagnostic purposes only. + ! + ! for dry mixing ratio dycore, physics_dme_adjust is called for energy diagnostic purposes only. ! So, save off tracers - if (.not.moist_mixing_ratio_dycore.and.& - (hist_fld_active('SE_phAM').or.hist_fld_active('KE_phAM').or.hist_fld_active('WV_phAM').or.& - hist_fld_active('WL_phAM').or.hist_fld_active('WI_phAM').or.hist_fld_active('MR_phAM').or.& - hist_fld_active('MO_phAM'))) then - tmp_trac(:ncol,:pver,:pcnst) = state%q(:ncol,:pver,:pcnst) - tmp_pdel(:ncol,:pver) = state%pdel(:ncol,:pver) - tmp_ps(:ncol) = state%ps(:ncol) + if (.not.moist_mixing_ratio_dycore) then + ! + ! for dry-mixing ratio based dycores dme_adjust takes place in the dynamical core + ! + ! only compute dme_adjust for diagnostics purposes + ! + if (thermo_budget_history) then + tmp_trac(:ncol,:pver,:pcnst) = state%q(:ncol,:pver,:pcnst) + tmp_pdel(:ncol,:pver) = state%pdel(:ncol,:pver) + tmp_ps(:ncol) = state%ps(:ncol) + call physics_dme_adjust(state, tend, qini, totliqini, toticeini, ztodt) + call tot_energy_phys(state, 'phAM') + call tot_energy_phys(state, 'dyAM', vc=vc_dycore) + ! Restore pre-"physics_dme_adjust" tracers + state%q(:ncol,:pver,:pcnst) = tmp_trac(:ncol,:pver,:pcnst) + state%pdel(:ncol,:pver) = tmp_pdel(:ncol,:pver) + state%ps(:ncol) = tmp_ps(:ncol) + end if + else ! - ! pint, lnpint,rpdel are altered by dme_adjust but not used for tendencies in dynamics of SE - ! we do not reset them to pre-dme_adjust values + ! for moist-mixing ratio based dycores + ! + ! Note: this operation will NOT be reverted with set_wet_to_dry after set_dry_to_wet call ! call set_dry_to_wet(state) - - call physics_dme_adjust(state, tend, qini, ztodt) - - call calc_te_and_aam_budgets(state, 'phAM') - call calc_te_and_aam_budgets(state, 'dyAM',vc=vc_dycore) - ! Restore pre-"physics_dme_adjust" tracers - state%q(:ncol,:pver,:pcnst) = tmp_trac(:ncol,:pver,:pcnst) - state%pdel(:ncol,:pver) = tmp_pdel(:ncol,:pver) - state%ps(:ncol) = tmp_ps(:ncol) - end if - - if (moist_mixing_ratio_dycore) then - call physics_dme_adjust(state, tend, qini, ztodt) - call calc_te_and_aam_budgets(state, 'phAM') - call calc_te_and_aam_budgets(state, 'dyAM',vc=vc_dycore) + call physics_dme_adjust(state, tend, qini, totliqini, toticeini, ztodt) + call tot_energy_phys(state, 'phAM') + call tot_energy_phys(state, 'dyAM', vc=vc_dycore) + endif + if (vc_dycore == vc_height.or.vc_dycore == vc_dry_pressure) then + ! + ! MPAS and SE specific scaling of temperature for enforcing energy consistency + ! (and to make sure that temperature dependent diagnostic tendencies + ! are computed correctly; e.g. dtcore) + ! + scaling(1:ncol,:) = cpairv(:ncol,:,lchnk)/cp_or_cv_dycore(:ncol,:,lchnk) + state%T(1:ncol,:) = state%temp_ini(1:ncol,:)+& + scaling(1:ncol,:)*(state%T(1:ncol,:)-state%temp_ini(1:ncol,:)) + tend%dtdt(:ncol,:) = scaling(:ncol,:)*tend%dtdt(:ncol,:) + ! + ! else: do nothing for dycores with energy consistent with CAM physics + ! end if - + else tmp_q (:ncol,:pver) = 0.0_r8 tmp_cldliq(:ncol,:pver) = 0.0_r8 tmp_cldice(:ncol,:pver) = 0.0_r8 - call calc_te_and_aam_budgets(state, 'phAM') - call calc_te_and_aam_budgets(state, 'dyAM',vc=vc_dycore) + call tot_energy_phys(state, 'phAM') + call tot_energy_phys(state, 'dyAM',vc=vc_dycore) end if ! store T in buffer for use in computing dynamics T-tendency in next timestep @@ -609,13 +647,15 @@ subroutine tphysac (ztodt, cam_in, cam_out, state, tend, pbuf) end do call diag_phys_tend_writeout (state, pbuf, tend, ztodt, & - tmp_q, tmp_cldliq, tmp_cldice, qini, cldliqini, cldiceini) + qini, cldliqini, cldiceini) call diag_surf(cam_in, cam_out, state, pbuf) if (.not. moist_physics) then deallocate(cldliqini) deallocate(cldiceini) + deallocate(totliqini) + deallocate(toticeini) end if end subroutine tphysac @@ -647,7 +687,7 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) use time_manager, only: get_nstep use check_energy, only: check_energy_chng, check_energy_fix, check_energy_timestep_init use check_energy, only: check_tracers_data, check_tracers_init, check_tracers_chng - use check_energy, only: calc_te_and_aam_budgets + use check_energy, only: tot_energy_phys use chemistry, only: chem_is_active, chem_timestep_tend use held_suarez_cam, only: held_suarez_tend use kessler_cam, only: kessler_tend @@ -656,6 +696,8 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) use cam_snapshot_common,only: cam_snapshot_all_outfld use cam_snapshot_common,only: cam_snapshot_ptend_outfld use physics_types, only: dyn_te_idx + use air_composition, only: thermodynamic_active_species_liq_num,thermodynamic_active_species_liq_idx + use air_composition, only: thermodynamic_active_species_ice_num,thermodynamic_active_species_ice_idx ! Arguments real(r8), intent(in) :: ztodt ! model time increment @@ -676,12 +718,15 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) integer :: itim_old integer :: ixcldliq integer :: ixcldice + integer :: m, m_cnst ! physics buffer fields for total energy and mass adjustment real(r8), pointer :: teout(:) real(r8), pointer :: qini(:,:) real(r8), pointer :: cldliqini(:,:) real(r8), pointer :: cldiceini(:,:) + real(r8), pointer :: totliqini(:,:) + real(r8), pointer :: toticeini(:,:) real(r8), pointer :: dtcore(:,:) real(r8) :: zero(pcols) ! array of zeros @@ -709,6 +754,8 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) if (moist_physics) then call pbuf_get_field(pbuf, cldliqini_idx, cldliqini) call pbuf_get_field(pbuf, cldiceini_idx, cldiceini) + call pbuf_get_field(pbuf, totliqini_idx, totliqini) + call pbuf_get_field(pbuf, toticeini_idx, toticeini) end if ! Set accumulated physics tendencies to 0 @@ -733,8 +780,8 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) !=================================================== ! Global mean total energy fixer and AAM diagnostics !=================================================== - call calc_te_and_aam_budgets(state, 'phBF') - call calc_te_and_aam_budgets(state, 'dyBF',vc=vc_dycore) + call tot_energy_phys(state, 'phBF') + call tot_energy_phys(state, 'dyBF',vc=vc_dycore) call t_startf('energy_fixer') @@ -747,8 +794,8 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) call t_stopf('energy_fixer') - call calc_te_and_aam_budgets(state, 'phBP') - call calc_te_and_aam_budgets(state, 'dyBP',vc=vc_dycore) + call tot_energy_phys(state, 'phBP') + call tot_energy_phys(state, 'dyBP',vc=vc_dycore) ! Save state for convective tendency calculations. call diag_conv_tend_ini(state, pbuf) @@ -764,8 +811,17 @@ subroutine tphysbc (ztodt, state, tend, pbuf, cam_out, cam_in ) if (ixcldice > 0) then cldiceini(:ncol,:pver) = state%q(:ncol,:pver,ixcldice) end if + totliqini(:ncol,:pver) = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_liq_num + m = thermodynamic_active_species_liq_idx(m_cnst) + totliqini(:ncol,:pver) = totliqini(:ncol,:pver)+state%q(:ncol,:pver,m) + end do + toticeini(:ncol,:pver) = 0.0_r8 + do m_cnst=1,thermodynamic_active_species_ice_num + m = thermodynamic_active_species_ice_idx(m_cnst) + toticeini(:ncol,:pver) = toticeini(:ncol,:pver)+state%q(:ncol,:pver,m) + end do end if - call outfld('TEOUT', teout , pcols, lchnk ) call outfld('TEINP', state%te_ini(:,dyn_te_idx), pcols, lchnk ) call outfld('TEFIX', state%te_cur(:,dyn_te_idx), pcols, lchnk ) diff --git a/src/utils/air_composition.F90 b/src/utils/air_composition.F90 index 367f52811a..6046ffebf1 100644 --- a/src/utils/air_composition.F90 +++ b/src/utils/air_composition.F90 @@ -1,4 +1,5 @@ -! air_composition module defines major species of the atmosphere and manages the physical properties that are dependent on the composition of air +! air_composition module defines major species of the atmosphere and manages +! the physical properties that are dependent on the composition of air module air_composition use shr_kind_mod, only: r8 => shr_kind_r8 @@ -10,7 +11,9 @@ module air_composition public :: air_composition_readnl public :: air_composition_init - public :: air_composition_update + public :: dry_air_composition_update + public :: water_composition_update + ! get_cp_dry: (generalized) heat capacity for dry air public :: get_cp_dry ! get_cp: (generalized) heat capacity @@ -102,7 +105,9 @@ module air_composition real(r8), public, protected, allocatable :: cappav(:,:,:) ! mbarv: composition dependent atmosphere mean mass real(r8), public, protected, allocatable :: mbarv(:,:,:) - + ! cp_or_cv_dycore: enthalpy or internal energy scaling factor for + ! energy consistency + real(r8), public, protected, allocatable :: cp_or_cv_dycore(:,:,:) ! ! Interfaces for public routines interface get_cp_dry @@ -230,7 +235,6 @@ subroutine air_composition_init() use physconst, only: r_universal, cpair, rair, cpwv, rh2o, cpliq, cpice, mwdry use constituents, only: cnst_get_ind, cnst_mw use ppgrid, only: pcols, pver, begchunk, endchunk - integer :: icnst, ix, isize, ierr, idx integer :: liq_num, ice_num integer :: liq_idx(water_species_in_air_num) @@ -330,6 +334,10 @@ subroutine air_composition_init() if (ierr /= 0) then call endrun(errstr//"mbarv") end if + allocate(cp_or_cv_dycore(pcols,pver,begchunk:endchunk), stat=ierr) + if (ierr /= 0) then + call endrun(errstr//"cp_or_cv_dycore") + end if thermodynamic_active_species_idx = -HUGE(1) thermodynamic_active_species_idx_dycore = -HUGE(1) @@ -620,27 +628,63 @@ end subroutine air_composition_init !=========================================================================== !----------------------------------------------------------------------- - ! air_composition_update: Update the physics "constants" that vary + ! dry_air_composition_update: Update the physics "constants" that vary !------------------------------------------------------------------------- !=========================================================================== - subroutine air_composition_update(mmr, lchnk, ncol, to_moist_factor) - - real(r8), intent(in) :: mmr(:,:,:) ! constituents array + subroutine dry_air_composition_update(mmr, lchnk, ncol, to_dry_factor) + use cam_abortutils, only: endrun + !(mmr = dry mixing ratio, if not, use to_dry_factor to convert!) + real(r8), intent(in) :: mmr(:,:,:) ! mixing ratios for species dependent dry air integer, intent(in) :: lchnk ! Chunk number integer, intent(in) :: ncol ! number of columns - real(r8), optional, intent(in) :: to_moist_factor(:,:) + real(r8), optional, intent(in) :: to_dry_factor(:,:) call get_R_dry(mmr(:ncol, :, :), thermodynamic_active_species_idx, & - rairv(:ncol, :, lchnk), fact=to_moist_factor) - call get_cp_dry(mmr(:ncol,:,:), thermodynamic_active_species_idx, & - cpairv(:ncol,:,lchnk), fact=to_moist_factor) - call get_mbarv(mmr(:ncol,:,:), thermodynamic_active_species_idx, & - mbarv(:ncol,:,lchnk), fact=to_moist_factor) - + rairv(:ncol, :, lchnk), fact=to_dry_factor) + call get_cp_dry(mmr(:ncol,:,:), thermodynamic_active_species_idx, & + cpairv(:ncol,:,lchnk), fact=to_dry_factor) + call get_mbarv(mmr(:ncol,:,:), thermodynamic_active_species_idx, & + mbarv(:ncol,:,lchnk), fact=to_dry_factor) cappav(:ncol,:,lchnk) = rairv(:ncol,:,lchnk) / cpairv(:ncol,:,lchnk) + end subroutine dry_air_composition_update - end subroutine air_composition_update + !=========================================================================== + !--------------------------------------------------------------------------- + ! water_composition_update: Update generalized cp or cv depending on dycore + !--------------------------------------------------------------------------- + !=========================================================================== + + subroutine water_composition_update(mmr, lchnk, ncol, vcoord, to_dry_factor) + use cam_abortutils, only: endrun + use string_utils, only: int2str + use dyn_tests_utils, only: vc_height, vc_moist_pressure, vc_dry_pressure + real(r8), intent(in) :: mmr(:,:,:) ! constituents array + integer, intent(in) :: lchnk ! Chunk number + integer, intent(in) :: ncol ! number of columns + integer, intent(in) :: vcoord + real(r8), optional, intent(in) :: to_dry_factor(:,:) + + character(len=*), parameter :: subname = 'water_composition_update' + + if (vcoord==vc_dry_pressure) then + call get_cp(mmr(:ncol,:,:),.false.,cp_or_cv_dycore(:ncol,:,lchnk), factor=to_dry_factor, & + active_species_idx_dycore=thermodynamic_active_species_idx,cpdry=cpairv(:ncol,:,lchnk)) + else if (vcoord==vc_height) then + call get_R(mmr(:ncol,:,:), thermodynamic_active_species_idx, & + cp_or_cv_dycore(:ncol,:,lchnk), fact=to_dry_factor, Rdry=rairv(:ncol,:,lchnk)) + ! + ! internal energy coefficient for MPAS + ! (equation 92 in Eldred et al. 2023; https://rmets.onlinelibrary.wiley.com/doi/epdf/10.1002/qj.4353) + ! + cp_or_cv_dycore(:ncol,:,lchnk)=cp_or_cv_dycore(:ncol,:,lchnk)*& + (cpairv(:ncol,:,lchnk)-rairv(:ncol,:,lchnk)) /rairv(:ncol,:,lchnk) + else if (vcoord==vc_moist_pressure) then + ! no update needed for moist pressure vcoord + else + call endrun(subname//" vertical coordinate not supported; vcoord="// int2str(vcoord)) + end if + end subroutine water_composition_update !=========================================================================== !*************************************************************************** @@ -750,29 +794,35 @@ end subroutine get_cp_dry_2hd ! !*************************************************************************** ! - subroutine get_cp_1hd(tracer, inv_cp, cp, dp_dry, active_species_idx_dycore) + subroutine get_cp_1hd(tracer, inv_cp, cp, factor, active_species_idx_dycore, cpdry) use cam_abortutils, only: endrun use string_utils, only: int2str ! Dummy arguments - ! tracedr: Tracer array + ! tracer: Tracer array + ! + ! factor not present then tracer must be dry mixing ratio + ! if factor present tracer*factor must be dry mixing ratio + ! real(r8), intent(in) :: tracer(:,:,:) - real(r8), optional, intent(in) :: dp_dry(:,:) ! inv_cp: output inverse cp instead of cp logical, intent(in) :: inv_cp real(r8), intent(out) :: cp(:,:) + ! dp: if provided then tracer is mass not mixing ratio + real(r8), optional, intent(in) :: factor(:,:) ! active_species_idx_dycore: array of indices for index of ! thermodynamic active species in dycore tracer array ! (if different from physics index) integer, optional, intent(in) :: active_species_idx_dycore(:) + real(r8),optional, intent(in) :: cpdry(:,:) - ! Local variables + ! LOCAL VARIABLES integer :: qdx, itrac real(r8) :: sum_species(SIZE(cp, 1), SIZE(cp, 2)) real(r8) :: sum_cp(SIZE(cp, 1), SIZE(cp, 2)) - real(r8) :: factor(SIZE(cp, 1), SIZE(cp, 2)) + real(r8) :: factor_local(SIZE(cp, 1), SIZE(cp, 2)) integer :: idx_local(thermodynamic_active_species_num) - character(len=*), parameter :: subname = 'get_cp_1hd: ' + character(LEN=*), parameter :: subname = 'get_cp_1hd: ' if (present(active_species_idx_dycore)) then if (SIZE(active_species_idx_dycore) /= & @@ -786,51 +836,57 @@ subroutine get_cp_1hd(tracer, inv_cp, cp, dp_dry, active_species_idx_dycore) idx_local = thermodynamic_active_species_idx end if - if (present(dp_dry)) then - factor = 1.0_r8 / dp_dry + if (present(factor)) then + factor_local = factor else - factor = 1.0_r8 + factor_local = 1.0_r8 end if + sum_species = 1.0_r8 ! all dry air species sum to 1 do qdx = dry_air_species_num + 1, thermodynamic_active_species_num - itrac = idx_local(qdx) - sum_species(:,:) = sum_species(:,:) + & - (tracer(:,:,itrac) * factor(:,:)) + itrac = idx_local(qdx) + sum_species(:,:) = sum_species(:,:) + (tracer(:,:,itrac) * factor_local(:,:)) end do if (dry_air_species_num == 0) then sum_cp = thermodynamic_active_species_cp(0) + else if (present(cpdry)) then + ! + ! if cpdry is known don't recompute + ! + sum_cp = cpdry else - call get_cp_dry(tracer, idx_local, sum_cp, fact=factor) + call get_cp_dry(tracer, idx_local, sum_cp, fact=factor_local) end if do qdx = dry_air_species_num + 1, thermodynamic_active_species_num - itrac = idx_local(qdx) - sum_cp(:,:) = sum_cp(:,:) + & - (thermodynamic_active_species_cp(qdx) * tracer(:,:,itrac) * & - factor(:,:)) + itrac = idx_local(qdx) + sum_cp(:,:) = sum_cp(:,:)+ & + thermodynamic_active_species_cp(qdx) * tracer(:,:,itrac)* factor_local(:,:) end do if (inv_cp) then - cp = sum_species / sum_cp + cp = sum_species / sum_cp else - cp = sum_cp / sum_species + cp = sum_cp / sum_species end if - - end subroutine get_cp_1hd + end subroutine get_cp_1hd !=========================================================================== - subroutine get_cp_2hd(tracer, inv_cp, cp, dp_dry, active_species_idx_dycore) + subroutine get_cp_2hd(tracer, inv_cp, cp, factor, active_species_idx_dycore, cpdry) ! Version of get_cp for arrays that have a second horizontal index use cam_abortutils, only: endrun use string_utils, only: int2str ! Dummy arguments ! tracer: Tracer array + ! real(r8), intent(in) :: tracer(:,:,:,:) - real(r8), optional, intent(in) :: dp_dry(:,:,:) ! inv_cp: output inverse cp instead of cp logical, intent(in) :: inv_cp real(r8), intent(out) :: cp(:,:,:) + real(r8), optional, intent(in) :: factor(:,:,:) + real(r8), optional, intent(in) :: cpdry(:,:,:) + ! active_species_idx_dycore: array of indicies for index of ! thermodynamic active species in dycore tracer array ! (if different from physics index) @@ -842,11 +898,17 @@ subroutine get_cp_2hd(tracer, inv_cp, cp, dp_dry, active_species_idx_dycore) character(len=*), parameter :: subname = 'get_cp_2hd: ' do jdx = 1, SIZE(cp, 2) - if (present(dp_dry)) then - call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :), & - dp_dry=dp_dry(:, jdx, :), active_species_idx_dycore=active_species_idx_dycore) + if (present(factor).and.present(cpdry)) then + call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),& + factor=factor(:, jdx, :), active_species_idx_dycore=active_species_idx_dycore, cpdry=cpdry(:,jdx,:)) + else if (present(factor)) then + call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),& + factor=factor(:, jdx, :), active_species_idx_dycore=active_species_idx_dycore) + else if (present(cpdry)) then + call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),& + active_species_idx_dycore=active_species_idx_dycore, cpdry=cpdry(:,jdx,:)) else - call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :), & + call get_cp(tracer(:, jdx, :, :), inv_cp, cp(:, jdx, :),& active_species_idx_dycore=active_species_idx_dycore) end if end do @@ -955,9 +1017,10 @@ end subroutine get_R_dry_2hd ! !*************************************************************************** ! - subroutine get_R_1hd(tracer, active_species_idx, R, fact) + subroutine get_R_1hd(tracer, active_species_idx, R, fact, Rdry) use cam_abortutils, only: endrun use string_utils, only: int2str + use physconst, only: rair ! Dummy arguments ! tracer: !tracer array @@ -968,6 +1031,7 @@ subroutine get_R_1hd(tracer, active_species_idx, R, fact) real(r8), intent(out) :: R(:, :) ! fact: optional factor for converting tracer to dry mixing ratio real(r8), optional, intent(in) :: fact(:, :) + real(r8), optional, intent(in) :: Rdry(:, :) ! Local variables integer :: qdx, itrac @@ -986,12 +1050,19 @@ subroutine get_R_1hd(tracer, active_species_idx, R, fact) call endrun(subname//"SIZE mismatch in dimension 2 "// & int2str(SIZE(fact, 2))//' /= '//int2str(SIZE(factor, 2))) end if - call get_R_dry(tracer, active_species_idx, R, fact=fact) factor = fact(:,:) else - call get_R_dry(tracer, active_species_idx, R) factor = 1.0_r8 end if + + if (dry_air_species_num == 0) then + R = rair + else if (present(Rdry)) then + R = Rdry + else + call get_R_dry(tracer, active_species_idx, R, fact=factor) + end if + idx_local = active_species_idx sum_species = 1.0_r8 ! all dry air species sum to 1 do qdx = dry_air_species_num + 1, thermodynamic_active_species_num @@ -1046,7 +1117,7 @@ end subroutine get_R_2hd !************************************************************************************************************************* ! subroutine get_mbarv_1hd(tracer, active_species_idx, mbarv_in, fact) - use physconst, only: mwdry, rair, cpair + use physconst, only: mwdry real(r8), intent(in) :: tracer(:,:,:) !tracer array integer, intent(in) :: active_species_idx(:) !index of active species in tracer real(r8), intent(out) :: mbarv_in(:,:) !molecular weight of dry air diff --git a/src/utils/cam_grid_support.F90 b/src/utils/cam_grid_support.F90 index 30ffe78576..d86c829e77 100644 --- a/src/utils/cam_grid_support.F90 +++ b/src/utils/cam_grid_support.F90 @@ -314,6 +314,8 @@ end subroutine print_attr_spec public :: cam_grid_is_zonal ! Functions for dealing with patch masks public :: cam_grid_compute_patch + ! Functions for dealing with grid areas + public :: cam_grid_get_areawt interface cam_grid_attribute_register module procedure add_cam_grid_attribute_0d_int @@ -1616,6 +1618,59 @@ function cam_grid_get_lonvals(id) result(lonvals) end if end function cam_grid_get_lonvals + function cam_grid_get_areawt(id) result(wtvals) + + ! Dummy argument + integer, intent(in) :: id + real(r8), pointer :: wtvals(:) + + ! Local variables + character(len=max_chars) :: wtname + integer :: gridind + class(cam_grid_attribute_t), pointer :: attrptr + character(len=120) :: errormsg + + nullify(attrptr) + gridind = get_cam_grid_index(id) + if (gridind > 0) then + select case(cam_grids(gridind)%name) + case('GLL') + wtname='area_weight_gll' + case('EUL') + wtname='gw' + case('FV') + wtname='gw' + case('INI') + wtname='area_weight_ini' + case('physgrid') + wtname='areawt' + case('FVM') + wtname='area_weight_fvm' + case('mpas_cell') + wtname='area_weight_mpas' + case default + call endrun('cam_grid_get_areawt: Invalid gridname:'//trim(cam_grids(gridind)%name)) + end select + + call find_cam_grid_attr(gridind, trim(wtname), attrptr) + if (.not.associated(attrptr)) then + write(errormsg, '(4a)') & + 'cam_grid_get_areawt: error retrieving weight attribute ', trim(wtname), & + ' for cam grid ', cam_grids(gridind)%name + call endrun(errormsg) + else + call attrptr%print_attr() + select type(attrptr) + type is (cam_grid_attribute_1d_r8_t) + wtvals => attrptr%values + class default + call endrun('cam_grid_get_areawt: wt attribute is not a real datatype') + end select + end if + end if + + end function cam_grid_get_areawt + ! Find the longitude and latitude of a range of map entries ! beg and end are the range of the first source index. blk is a block or chunk index subroutine cam_grid_get_coords(id, beg, end, blk, lon, lat) @@ -2125,7 +2180,6 @@ subroutine write_cam_grid_attr_0d_int(attr, File) type(file_desc_t), intent(inout) :: File ! PIO file Handle ! Local variables - character(len=120) :: errormsg integer :: attrtype integer(imap) :: attrlen integer :: ierr @@ -2172,7 +2226,6 @@ subroutine write_cam_grid_attr_0d_char(attr, File) type(file_desc_t), intent(inout) :: File ! PIO file Handle ! Local variables - character(len=120) :: errormsg integer :: attrtype integer(imap) :: attrlen integer :: ierr @@ -2335,7 +2388,6 @@ end subroutine cam_grid_attribute_copy !--------------------------------------------------------------------------- subroutine cam_grid_write_attr(File, grid_id, header_info) use pio, only: file_desc_t, PIO_BCAST_ERROR, pio_seterrorhandling - use pio, only: pio_inq_dimid ! Dummy arguments type(file_desc_t), intent(inout) :: File ! PIO file Handle @@ -2414,14 +2466,13 @@ subroutine cam_grid_write_attr(File, grid_id, header_info) end subroutine cam_grid_write_attr subroutine write_cam_grid_val_0d_int(attr, File) - use pio, only: file_desc_t, pio_inq_varid, pio_put_var + use pio, only: file_desc_t, pio_put_var ! Dummy arguments class(cam_grid_attribute_0d_int_t), intent(inout) :: attr type(file_desc_t), intent(inout) :: File ! Local variables - character(len=120) :: errormsg integer :: ierr ! We only write this var if it is a variable @@ -2448,7 +2499,7 @@ end subroutine write_cam_grid_val_0d_char subroutine write_cam_grid_val_1d_int(attr, File) use pio, only: file_desc_t, pio_put_var, pio_int, & - pio_inq_varid, pio_write_darray, io_desc_t, pio_freedecomp + pio_write_darray, io_desc_t, pio_freedecomp use cam_pio_utils, only: cam_pio_newdecomp ! Dummy arguments @@ -2456,7 +2507,6 @@ subroutine write_cam_grid_val_1d_int(attr, File) type(file_desc_t), intent(inout) :: File ! Local variables - character(len=120) :: errormsg integer :: ierr type(io_desc_t), pointer :: iodesc @@ -2486,7 +2536,7 @@ end subroutine write_cam_grid_val_1d_int subroutine write_cam_grid_val_1d_r8(attr, File) use pio, only: file_desc_t, pio_put_var, pio_double, & - pio_inq_varid, pio_write_darray, io_desc_t, pio_freedecomp + pio_write_darray, io_desc_t, pio_freedecomp use cam_pio_utils, only: cam_pio_newdecomp ! Dummy arguments @@ -2494,7 +2544,6 @@ subroutine write_cam_grid_val_1d_r8(attr, File) type(file_desc_t), intent(inout) :: File ! Local variables - character(len=120) :: errormsg integer :: ierr type(io_desc_t), pointer :: iodesc @@ -2999,7 +3048,7 @@ subroutine cam_grid_find_dimids(this, File, dimids) integer, intent(out) :: dimids(:) ! Local vaariables - integer :: dsize, ierr + integer :: ierr integer :: err_handling character(len=max_hcoordname_len) :: dimname1, dimname2 @@ -3880,8 +3929,6 @@ subroutine cam_grid_patch_get_decomp(this, field_lens, file_lens, dtype, & end subroutine cam_grid_patch_get_decomp subroutine cam_grid_patch_compact(this, collected_output) - use spmd_utils, only: mpi_sum, mpi_integer, mpicom - use shr_mpi_mod, only: shr_mpi_chkerr ! Dummy arguments class(cam_grid_patch_t) :: this diff --git a/src/utils/cam_thermo.F90 b/src/utils/cam_thermo.F90 index eaea52f328..f65649c4ef 100644 --- a/src/utils/cam_thermo.F90 +++ b/src/utils/cam_thermo.F90 @@ -7,7 +7,6 @@ module cam_thermo use air_composition, only: thermodynamic_active_species_idx use air_composition, only: thermodynamic_active_species_idx_dycore use air_composition, only: thermodynamic_active_species_cp - use air_composition, only: thermodynamic_active_species_cv use air_composition, only: thermodynamic_active_species_R use air_composition, only: thermodynamic_active_species_mwi use air_composition, only: thermodynamic_active_species_kv @@ -18,6 +17,7 @@ module cam_thermo use air_composition, only: thermodynamic_active_species_liq_idx_dycore use air_composition, only: thermodynamic_active_species_ice_idx use air_composition, only: thermodynamic_active_species_ice_idx_dycore + use air_composition, only: dry_air_species_num use air_composition, only: enthalpy_reference_state use air_composition, only: mmro2, mmrn2, o2_mwi, n2_mwi, mbar @@ -33,8 +33,10 @@ module cam_thermo ! cam_thermo_init: Initialize constituent dependent properties public :: cam_thermo_init - ! cam_thermo_update: Update constituent dependent properties - public :: cam_thermo_update + ! cam_thermo_dry_air_update: Update dry air composition dependent properties + public :: cam_thermo_dry_air_update + ! cam_thermo_water_update: Update water dependent properties + public :: cam_thermo_water_update ! get_enthalpy: enthalpy quantity = dp*cp*T public :: get_enthalpy ! get_virtual_temp: virtual temperature @@ -170,6 +172,38 @@ module cam_thermo ! 2-d interface is not needed (but can easily be added) end interface get_hydrostatic_energy + integer, public, parameter :: thermo_budget_num_vars = 10 + integer, public, parameter :: wvidx = 1 + integer, public, parameter :: wlidx = 2 + integer, public, parameter :: wiidx = 3 + integer, public, parameter :: seidx = 4 ! enthalpy or internal energy (W/m2) index + integer, public, parameter :: poidx = 5 ! surface potential or potential energy index + integer, public, parameter :: keidx = 6 ! kinetic energy index + integer, public, parameter :: mridx = 7 + integer, public, parameter :: moidx = 8 + integer, public, parameter :: ttidx = 9 + integer, public, parameter :: teidx = 10 + character (len = 2) ,public, dimension(thermo_budget_num_vars) :: thermo_budget_vars = & + (/"WV" ,"WL" ,"WI" ,"SE" ,"PO" ,"KE" ,"MR" ,"MO" ,"TT" ,"TE" /) + character (len = 46) ,public, dimension(thermo_budget_num_vars) :: thermo_budget_vars_descriptor = (/& + "Total column water vapor ",& + "Total column liquid water ",& + "Total column frozen water ",& + "Total column enthalpy or internal energy ",& + "Total column srf potential or potential energy",& + "Total column kinetic energy ",& + "Total column wind axial angular momentum ",& + "Total column mass axial angular momentum ",& + "Total column test_tracer ",& + "Total column energy (ke + se + po) "/) + + character (len = 14), public, dimension(thermo_budget_num_vars) :: & + thermo_budget_vars_unit = (/& + "kg/m2 ","kg/m2 ","kg/m2 ","J/m2 ",& + "J/m2 ","J/m2 ","kg*m2/s*rad2 ","kg*m2/s*rad2 ",& + "kg/m2 ","J/m2 "/) + logical ,public, dimension(thermo_budget_num_vars) :: thermo_budget_vars_massv = (/& + .true.,.true.,.true.,.false.,.false.,.false.,.false.,.false.,.true.,.false./) CONTAINS !=========================================================================== @@ -177,7 +211,6 @@ module cam_thermo subroutine cam_thermo_init() use shr_infnan_mod, only: assignment(=), shr_infnan_qnan use ppgrid, only: pcols, pver, pverp, begchunk, endchunk - use physconst, only: cpair, rair, mwdry integer :: ierr character(len=*), parameter :: subname = "cam_thermo_init" @@ -202,48 +235,65 @@ subroutine cam_thermo_init() kmcnd(:pcols, :pver, begchunk:endchunk) = shr_infnan_qnan end subroutine cam_thermo_init - - !=========================================================================== - + ! !*************************************************************************** ! - ! cam_thermo_update: update species dependent constants for physics + ! cam_thermo_dry_air_update: update dry air species dependent constants for physics ! !*************************************************************************** ! - subroutine cam_thermo_update(mmr, T, lchnk, ncol, to_moist_factor) - use air_composition, only: air_composition_update + subroutine cam_thermo_dry_air_update(mmr, T, lchnk, ncol, to_dry_factor) + use air_composition, only: dry_air_composition_update use string_utils, only: int2str - !----------------------------------------------------------------------- - ! Update the physics "constants" that vary - !------------------------------------------------------------------------- - !------------------------------Arguments---------------------------------- - + !(mmr = dry mixing ratio, if not use to_dry_factor to convert) real(r8), intent(in) :: mmr(:,:,:) ! constituents array real(r8), intent(in) :: T(:,:) ! temperature integer, intent(in) :: lchnk ! Chunk number integer, intent(in) :: ncol ! number of columns - real(r8), optional, intent(in) :: to_moist_factor(:,:) + real(r8), optional, intent(in) :: to_dry_factor(:,:)!if mmr moist convert ! !---------------------------Local storage------------------------------- real(r8):: sponge_factor(SIZE(mmr, 2)) character(len=*), parameter :: subname = 'cam_thermo_update: ' - - if (present(to_moist_factor)) then - if (SIZE(to_moist_factor, 1) /= ncol) then - call endrun(subname//'DIM 1 of to_moist_factor is'//int2str(SIZE(to_moist_factor,1))//'but should be'//int2str(ncol)) - end if + if (present(to_dry_factor)) then + if (SIZE(to_dry_factor, 1) /= ncol) then + call endrun(subname//'DIM 1 of to_dry_factor is'//int2str(SIZE(to_dry_factor,1))//'but should be'//int2str(ncol)) + end if end if - sponge_factor = 1.0_r8 - call air_composition_update(mmr, lchnk, ncol, to_moist_factor=to_moist_factor) + sponge_factor = 1.0_r8 + call dry_air_composition_update(mmr, lchnk, ncol, to_dry_factor=to_dry_factor) call get_molecular_diff_coef(T(:ncol,:), .true., sponge_factor, kmvis(:ncol,:,lchnk), & - kmcnd(:ncol,:,lchnk), tracer=mmr(:ncol,:,:), fact=to_moist_factor, & + kmcnd(:ncol,:,lchnk), tracer=mmr(:ncol,:,:), fact=to_dry_factor, & active_species_idx_dycore=thermodynamic_active_species_idx) + end subroutine cam_thermo_dry_air_update + ! + !*************************************************************************** + ! + ! cam_thermo_water+update: update water species dependent constants for physics + ! + !*************************************************************************** + ! + subroutine cam_thermo_water_update(mmr, lchnk, ncol, vcoord, to_dry_factor) + use air_composition, only: water_composition_update + !----------------------------------------------------------------------- + ! Update the physics "constants" that vary + !------------------------------------------------------------------------- + + !------------------------------Arguments---------------------------------- + + real(r8), intent(in) :: mmr(:,:,:) ! constituents array + integer, intent(in) :: lchnk ! Chunk number + integer, intent(in) :: ncol ! number of columns + integer, intent(in) :: vcoord + real(r8), optional, intent(in) :: to_dry_factor(:,:) + ! + logical :: lcp - end subroutine cam_thermo_update + call water_composition_update(mmr, lchnk, ncol, vcoord, to_dry_factor=to_dry_factor) + end subroutine cam_thermo_water_update !=========================================================================== @@ -687,7 +737,6 @@ subroutine get_pmid_from_dpdry_1hd(tracer, mixing_ratio, active_species_idx, dp_ real(r8) :: dp_local(SIZE(tracer, 1), SIZE(tracer, 2)) ! local pressure level thickness real(r8) :: pint_local(SIZE(tracer, 1), SIZE(tracer, 2) + 1)! local interface pressure - integer :: kdx call get_dp(tracer, mixing_ratio, active_species_idx, dp_dry, dp_local) @@ -1258,7 +1307,8 @@ subroutine get_molecular_diff_coef_1hd(temp, get_at_interfaces, sponge_factor, k real(r8), intent(in) :: temp(:,:) ! temperature logical, intent(in) :: get_at_interfaces ! true: compute kmvis and kmcnd at interfaces ! false: compute kmvis and kmcnd at mid-levels - real(r8), intent(in) :: sponge_factor(:) ! multiply kmvis and kmcnd with sponge_factor (for sponge layer) + real(r8), intent(in) :: sponge_factor(:) ! multiply kmvis and kmcnd with sponge_factor + ! (for sponge layer) real(r8), intent(out) :: kmvis(:,:) real(r8), intent(out) :: kmcnd(:,:) real(r8), intent(in) :: tracer(:,:,:) ! tracer array @@ -1334,7 +1384,8 @@ subroutine get_molecular_diff_coef_1hd(temp, get_at_interfaces, sponge_factor, k residual = 1.0_r8 do icnst = 1, dry_air_species_num ispecies = idx_local(icnst) - mm = 0.5_r8 * (tracer(idx, kdx, ispecies) * factor(idx, kdx) + tracer(idx, kdx - 1, ispecies) * factor(idx, kdx-1)) + mm = 0.5_r8 * (tracer(idx, kdx, ispecies) * factor(idx, kdx) + & + tracer(idx, kdx - 1, ispecies) * factor(idx, kdx-1)) kmvis(idx, kdx) = kmvis(idx, kdx) + thermodynamic_active_species_kv(icnst) * & thermodynamic_active_species_mwi(icnst) * mm kmcnd(idx, kdx) = kmcnd(idx, kdx) + thermodynamic_active_species_kc(icnst) * & @@ -1396,7 +1447,8 @@ subroutine get_molecular_diff_coef_2hd(temp, get_at_interfaces, sponge_factor, k real(r8), intent(in) :: temp(:,:,:) ! temperature logical, intent(in) :: get_at_interfaces ! true: compute kmvis and kmcnd at interfaces ! false: compute kmvis and kmcnd at mid-levels - real(r8), intent(in) :: sponge_factor(:) ! multiply kmvis and kmcnd with sponge_factor (for sponge layer) + real(r8), intent(in) :: sponge_factor(:) ! multiply kmvis and kmcnd with sponge_factor + ! (for sponge layer) real(r8), intent(out) :: kmvis(:,:,:) real(r8), intent(out) :: kmcnd(:,:,:) real(r8), intent(in) :: tracer(:,:,:,:) ! tracer array @@ -1523,20 +1575,23 @@ end subroutine cam_thermo_calc_kappav_2hd ! !*************************************************************************** ! - subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & - vcoord, ps, phis, z_mid, dycore_idx, qidx, te, se, ke, & - wv, H2O, liq, ice) + subroutine get_hydrostatic_energy_1hd(tracer, moist_mixing_ratio, pdel_in, & + cp_or_cv, U, V, T, vcoord, ptop, phis, z_mid, dycore_idx, qidx, & + te, se, po, ke, wv, H2O, liq, ice) use cam_logfile, only: iulog use dyn_tests_utils, only: vc_height, vc_moist_pressure, vc_dry_pressure use air_composition, only: wv_idx - use physconst, only: gravit, latvap, latice + use physconst, only: rga, latvap, latice ! Dummy arguments ! tracer: tracer mixing ratio + ! + ! note - if pdeldry passed to subroutine then tracer mixing ratio must be dry real(r8), intent(in) :: tracer(:,:,:) + logical, intent(in) :: moist_mixing_ratio ! pdel: pressure level thickness - real(r8), intent(in) :: pdel(:,:) + real(r8), intent(in) :: pdel_in(:,:) ! cp_or_cv: dry air heat capacity under constant pressure or ! constant volume (depends on vcoord) real(r8), intent(in) :: cp_or_cv(:,:) @@ -1544,7 +1599,7 @@ subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & real(r8), intent(in) :: V(:,:) real(r8), intent(in) :: T(:,:) integer, intent(in) :: vcoord ! vertical coordinate - real(r8), intent(in), optional :: ps(:) + real(r8), intent(in), optional :: ptop(:) real(r8), intent(in), optional :: phis(:) real(r8), intent(in), optional :: z_mid(:,:) ! dycore_idx: use dycore index for thermodynamic active species @@ -1557,8 +1612,12 @@ subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & real(r8), intent(out), optional :: te (:) ! KE: vertically integrated kinetic energy real(r8), intent(out), optional :: ke (:) - ! SE: vertically integrated internal+geopotential energy + ! SE: vertically integrated enthalpy (pressure coordinate) + ! or internal energy (z coordinate) real(r8), intent(out), optional :: se (:) + ! PO: vertically integrated PHIS term (pressure coordinate) + ! or potential energy (z coordinate) + real(r8), intent(out), optional :: po (:) ! WV: vertically integrated water vapor real(r8), intent(out), optional :: wv (:) ! liq: vertically integrated liquid @@ -1568,10 +1627,12 @@ subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & ! Local variables real(r8) :: ke_vint(SIZE(tracer, 1)) ! Vertical integral of KE - real(r8) :: se_vint(SIZE(tracer, 1)) ! Vertical integral of SE + real(r8) :: se_vint(SIZE(tracer, 1)) ! Vertical integral of enthalpy or internal energy + real(r8) :: po_vint(SIZE(tracer, 1)) ! Vertical integral of PHIS or potential energy real(r8) :: wv_vint(SIZE(tracer, 1)) ! Vertical integral of wv real(r8) :: liq_vint(SIZE(tracer, 1)) ! Vertical integral of liq real(r8) :: ice_vint(SIZE(tracer, 1)) ! Vertical integral of ice + real(r8) :: pdel(SIZE(tracer, 1),SIZE(tracer, 2)) !moist pressure level thickness real(r8) :: latsub ! latent heat of sublimation integer :: ierr @@ -1618,51 +1679,56 @@ subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & wvidx = wv_idx end if + if (moist_mixing_ratio) then + pdel = pdel_in + else + pdel = pdel_in + do qdx = dry_air_species_num+1, thermodynamic_active_species_num + pdel(:,:) = pdel(:,:) + pdel_in(:, :)*tracer(:,:,species_idx(qdx)) + end do + end if + + ke_vint = 0._r8 + se_vint = 0._r8 select case (vcoord) case(vc_moist_pressure, vc_dry_pressure) - if ((.not. present(ps)) .or. (.not. present(phis))) then - write(iulog, *) subname, ' ps and phis must be present for ', & + if (.not. present(ptop).or. (.not. present(phis))) then + write(iulog, *) subname, ' ptop and phis must be present for ', & 'moist/dry pressure vertical coordinate' - call endrun(subname//': ps and phis must be present for '// & + call endrun(subname//': ptop and phis must be present for '// & 'moist/dry pressure vertical coordinate') end if - ke_vint = 0._r8 - se_vint = 0._r8 - wv_vint = 0._r8 + po_vint = ptop do kdx = 1, SIZE(tracer, 2) do idx = 1, SIZE(tracer, 1) ke_vint(idx) = ke_vint(idx) + (pdel(idx, kdx) * & - 0.5_r8 * (U(idx, kdx)**2 + V(idx, kdx)**2) / gravit) + 0.5_r8 * (U(idx, kdx)**2 + V(idx, kdx)**2)) * rga se_vint(idx) = se_vint(idx) + (T(idx, kdx) * & - cp_or_cv(idx, kdx) * pdel(idx, kdx) / gravit) - wv_vint(idx) = wv_vint(idx) + (tracer(idx, kdx, wvidx) * & - pdel(idx, kdx) / gravit) + cp_or_cv(idx, kdx) * pdel(idx, kdx) * rga) + po_vint(idx) = po_vint(idx)+pdel(idx, kdx) + end do end do do idx = 1, SIZE(tracer, 1) - se_vint(idx) = se_vint(idx) + (phis(idx) * ps(idx) / gravit) + po_vint(idx) = (phis(idx) * po_vint(idx) * rga) end do case(vc_height) - if (.not. present(z_mid)) then - write(iulog, *) subname, & - ' z_mid must be present for height vertical coordinate' - call endrun(subname//': z_mid must be present for height '// & - 'vertical coordinate') + if (.not. present(phis)) then + write(iulog, *) subname, ' phis must be present for ', & + 'heigt-based vertical coordinate' + call endrun(subname//': phis must be present for '// & + 'height-based vertical coordinate') end if - ke_vint = 0._r8 - se_vint = 0._r8 - wv_vint = 0._r8 + po_vint = 0._r8 do kdx = 1, SIZE(tracer, 2) do idx = 1, SIZE(tracer, 1) ke_vint(idx) = ke_vint(idx) + (pdel(idx, kdx) * & - 0.5_r8 * (U(idx, kdx)**2 + V(idx, kdx)**2) / gravit) + 0.5_r8 * (U(idx, kdx)**2 + V(idx, kdx)**2) * rga) se_vint(idx) = se_vint(idx) + (T(idx, kdx) * & - cp_or_cv(idx, kdx) * pdel(idx, kdx) / gravit) + cp_or_cv(idx, kdx) * pdel(idx, kdx) * rga) ! z_mid is height above ground - se_vint(idx) = se_vint(idx) + (z_mid(idx, kdx) + & - phis(idx) / gravit) * pdel(idx, kdx) - wv_vint(idx) = wv_vint(idx) + (tracer(idx, kdx, wvidx) * & - pdel(idx, kdx) / gravit) + po_vint(idx) = po_vint(idx) + (z_mid(idx, kdx) + & + phis(idx) * rga) * pdel(idx, kdx) end do end do case default @@ -1670,26 +1736,39 @@ subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & call endrun(subname//': vertical coordinate not supported') end select if (present(te)) then - te = se_vint + ke_vint + te = se_vint + po_vint+ ke_vint end if if (present(se)) then se = se_vint end if + if (present(po)) then + po = po_vint + end if if (present(ke)) then ke = ke_vint end if - if (present(wv)) then - wv = wv_vint - end if ! ! vertical integral of total liquid water ! + if (.not.moist_mixing_ratio) then + pdel = pdel_in! set pseudo density to dry + end if + + wv_vint = 0._r8 + do kdx = 1, SIZE(tracer, 2) + do idx = 1, SIZE(tracer, 1) + wv_vint(idx) = wv_vint(idx) + (tracer(idx, kdx, wvidx) * & + pdel(idx, kdx) * rga) + end do + end do + if (present(wv)) wv = wv_vint + liq_vint = 0._r8 do qdx = 1, thermodynamic_active_species_liq_num do kdx = 1, SIZE(tracer, 2) do idx = 1, SIZE(tracer, 1) - liq_vint(idx) = liq_vint(idx) + (pdel(idx, kdx) * & - tracer(idx, kdx, species_liq_idx(qdx)) / gravit) + liq_vint(idx) = liq_vint(idx) + (pdel(idx, kdx) * & + tracer(idx, kdx, species_liq_idx(qdx)) * rga) end do end do end do @@ -1703,7 +1782,7 @@ subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & do kdx = 1, SIZE(tracer, 2) do idx = 1, SIZE(tracer, 1) ice_vint(idx) = ice_vint(idx) + (pdel(idx, kdx) * & - tracer(idx, kdx, species_ice_idx(qdx)) / gravit) + tracer(idx, kdx, species_ice_idx(qdx)) * rga) end do end do end do @@ -1731,9 +1810,6 @@ subroutine get_hydrostatic_energy_1hd(tracer, pdel, cp_or_cv, U, V, T, & end select end if deallocate(species_idx, species_liq_idx, species_ice_idx) - - end subroutine get_hydrostatic_energy_1hd - - !=========================================================================== + end subroutine get_hydrostatic_energy_1hd end module cam_thermo diff --git a/src/utils/zonal_mean_mod.F90 b/src/utils/zonal_mean_mod.F90 index 3c41a4b4ec..25e3f8564a 100644 --- a/src/utils/zonal_mean_mod.F90 +++ b/src/utils/zonal_mean_mod.F90 @@ -1318,105 +1318,32 @@ subroutine Invert_Matrix(I_Mat,Nbas,O_InvMat) ! ! Invert_Matrix: Given the NbasxNbas matrix, calculate and return ! the inverse of the matrix. + ! + ! Implemented with the LAPACK DGESV routine. + ! !==================================================================== - real(r8),parameter:: TINY = 1.e-20_r8 ! ! Passed Variables !------------------ - real(r8),intent(in ):: I_Mat (:,:) - integer ,intent(in ):: Nbas - real(r8),intent(out):: O_InvMat(:,:) + real(r8), intent(inout) :: I_Mat(:,:) ! input matrix contains P*L*U + ! decomposition on output + integer, intent(in) :: Nbas + real(r8), intent(out) :: O_InvMat(:,:) ! ! Local Values !------------- - real(r8),allocatable:: Mwrk(:,:),Rscl(:) - integer ,allocatable:: Indx(:) - real(r8):: Psgn,Mmax,Mval,Sval - integer :: ii,jj,kk,ndx,i2,ii_max, astat + integer, allocatable :: Indx(:) ! pivot indices + integer :: astat, ii character(len=*), parameter :: subname = 'Invert_Matrix' + character(len=80) :: msg + + external DGESV ! Allocate work space !--------------------- - allocate(Mwrk(Nbas,Nbas), stat=astat) - call handle_allocate_error(astat, subname, 'Mwrk') - allocate(Rscl(Nbas), stat=astat) - call handle_allocate_error(astat, subname, 'Rscl') allocate(Indx(Nbas), stat=astat) call handle_allocate_error(astat, subname, 'Indx') - ! Copy the Input matrix so it can be decomposed - !------------------------------------------------- - Mwrk(1:Nbas,1:Nbas) = I_Mat(1:Nbas,1:Nbas) - - ! Initailize Row scales - !---------------------- - Psgn = 1._r8 - do ii=1,Nbas - Mmax = 0._r8 - do jj=1,Nbas - if(abs(Mwrk(ii,jj))>Mmax) Mmax = abs(Mwrk(ii,jj)) - end do - if(Mmax==0._r8) then - call endrun('Invert_Matrix: Singular Matrix') - endif - Rscl(ii) = 1._r8/Mmax - end do - - ! Decompose the matrix - !----------------------- - do jj=1,Nbas - - if(jj>1) then - do ii=1,(jj-1) - Sval = Mwrk(ii,jj) - if(ii>1) then - do kk=1,(ii-1) - Sval = Sval - Mwrk(ii,kk)*Mwrk(kk,jj) - end do - Mwrk(ii,jj) = Sval - endif - end do - endif - - Mmax = 0._r8 - do ii=jj,Nbas - Sval = Mwrk(ii,jj) - if(jj>1) then - do kk=1,(jj-1) - Sval = Sval - Mwrk(ii,kk)*Mwrk(kk,jj) - end do - Mwrk(ii,jj) = Sval - endif - Mval = Rscl(ii)*abs(Sval) - if(Mval>=Mmax) then - ii_max = ii - Mmax = Mval - endif - end do - - if(jj/=ii_max) then - do kk=1,Nbas - Mval = Mwrk(ii_max,kk) - Mwrk(ii_max,kk) = Mwrk(jj,kk) - Mwrk(jj,kk) = Mval - end do - Psgn = -Psgn - Rscl(ii_max) = Rscl(jj) - endif - - Indx(jj) = ii_max - if(jj/=Nbas) then - if(Mwrk(jj,jj)==0._r8) Mwrk(jj,jj) = TINY - Mval = 1._r8/Mwrk(jj,jj) - do ii=(jj+1),Nbas - Mwrk(ii,jj) = Mwrk(ii,jj)*Mval - end do - endif - - end do ! jj=1,Nbas - - if(Mwrk(Nbas,Nbas)==0._r8) Mwrk(Nbas,Nbas) = TINY - ! Initialize the inverse array with the identity matrix !------------------------------------------------------- O_InvMat(:,:) = 0._r8 @@ -1424,41 +1351,15 @@ subroutine Invert_Matrix(I_Mat,Nbas,O_InvMat) O_InvMat(ii,ii) = 1._r8 end do - ! Back substitution to construct the inverse - !--------------------------------------------- - do kk=1,Nbas - - i2 = 0 - do ii=11,Nbas - ndx = Indx(ii) - Sval = O_InvMat(ndx,kk) - O_InvMat(ndx,kk) = O_InvMat(ii,kk) - if(i2/=0) then - do jj=i2,(ii-1) - Sval = Sval - Mwrk(ii,jj)*O_InvMat(jj,kk) - end do - elseif(Sval/=0._r8) then - i2 = ii - endif - O_InvMat(ii,kk) = Sval - end do + call DGESV(Nbas, Nbas, I_Mat, Nbas, Indx, O_InvMat, Nbas, astat) - do ii=Nbas,1,-1 - Sval = O_InvMat(ii,kk) - if(ii 0) then + call endrun(subname//': DGESV error return: matrix is singular') + end if - ! Clean up this mess - !--------------------- - deallocate(Mwrk) - deallocate(Rscl) deallocate(Indx) end subroutine Invert_Matrix diff --git a/test/system/archive_baseline.sh b/test/system/archive_baseline.sh index adab681a88..8a19a4cf45 100755 --- a/test/system/archive_baseline.sh +++ b/test/system/archive_baseline.sh @@ -122,7 +122,7 @@ if [ -n "$CESM_TESTDIR" ]; then cp -r $CESM_TESTDIR/baselines/. $root_baselinedir/$cam_tag else echo "Using bless_test_results to archive baselines." - ../../cime/scripts/Tools/bless_test_results -p -t '' -c '' -r $CESM_TESTDIR --baseline-root $root_baselinedir -b $cam_tag -f -s + ../../cime/CIME/Tools/bless_test_results -p -t '' -c '' -r $CESM_TESTDIR --baseline-root $root_baselinedir -b $cam_tag -f -s fi echo " "