diff --git a/models/atm/cam/bld/build-namelist b/models/atm/cam/bld/build-namelist
index c81855cdfbd6..64acc8a16413 100755
--- a/models/atm/cam/bld/build-namelist
+++ b/models/atm/cam/bld/build-namelist
@@ -2462,10 +2462,16 @@ add_default($nl, 'srf_flux_avg', 'eddy_scheme'=>$eddy_scheme);
# Microphysics scheme
add_default($nl, 'use_subcol_microp');
add_default($nl, 'microp_scheme');
+add_default($nl, 'micro_do_icesupersat');
add_default($nl, 'macrop_scheme');
if ($cfg->get('microphys') =~ /^mg/) {
add_default($nl, 'micro_mg_version');
add_default($nl, 'micro_mg_sub_version');
+ add_default($nl, 'micro_mg_num_steps');
+ add_default($nl, 'nucleate_ice_subgrid');
+ add_default($nl, 'cld_macmic_num_steps');
+ add_default($nl, 'micro_mg_precip_frac_method');
+ add_default($nl, 'micro_mg_berg_eff_factor');
}
add_default($nl, 'micro_mg_dcs');
@@ -2512,11 +2518,34 @@ else {
# CLUBB_SGS
add_default($nl, 'do_clubb_sgs');
-add_default($nl, 'clubb_history');
-add_default($nl, 'clubb_rad_history');
+my $clubb_sgs = $nl->get_value('do_clubb_sgs');
+if ($clubb_sgs =~ /$TRUE/io) {
+ my $clubb_do_adv = $cfg->get('clubb_do_adv');
+ if($clubb_do_adv == '1') {
+ add_default($nl, 'clubb_do_adv', 'val'=>'.true.');
+ }
+ my $clubb_do_deep = $cfg->get('clubb_do_deep');
+ if($clubb_do_deep == '1') {
+ add_default($nl, 'clubb_do_deep', 'val'=>'.true.');
+ }
+ add_default($nl, 'clubb_history');
+ add_default($nl, 'clubb_rad_history');
+
+ # Check compatibility of clubb_do_deep (if set) with deep_scheme
+ my $clubb_do_deep = $nl->get_value('clubb_do_deep');
+ if (defined $clubb_do_deep) {
+ my $deep_scheme = $nl->get_value('deep_scheme');
+ if ($deep_scheme ne "'CLUBB_SGS'" && $clubb_do_deep == /$TRUE/io) {
+ die "$ProgName - ERROR: clubb_do_deep = .true. but incompatible deep_scheme=$deep_scheme and needs to be 'CLUBB_SGS'\n";
+ }
+ }
-if ($nl->get_value('clubb_history') =~ "true" && $nl->get_value('atm_nthreads') != 1) {
- die "$ProgName - ERROR: clubb_history = .true. with multiple threads is not supported. \n";
+ add_default($nl, 'clubb_expldiff');
+ add_default($nl, 'clubb_rainevap_turb');
+ add_default($nl, 'clubb_cloudtop_cooling');
+ add_default($nl, 'clubb_timestep');
+ add_default($nl, 'clubb_rnevap_effic');
+ add_default($nl, 'clubb_stabcorrect');
}
#in-cloud scav tuning for cloud-borne aerosol
@@ -2564,6 +2593,13 @@ add_default($nl, 'cldfrc_premit');
add_default($nl, 'cldfrc_premib');
add_default($nl, 'cldfrc_iceopt');
add_default($nl, 'cldfrc_icecrit');
+add_default($nl, 'cldfrc2m_rhmini');
+add_default($nl, 'cldfrc2m_rhmaxi');
+
+my $cldfrc_rhminp = $nl->get_value('cldfrc_rhminp');
+if ($cldfrc_rhminp and !($cfg->get('microphys') eq 'rk')) {
+ die "$ProgName - ERROR: cldfrc_rhminp is valid only for RK microphysics scheme\n";
+}
# condensate to rain autoconversion coefficients
add_default($nl, 'zmconv_c0_lnd');
@@ -3000,7 +3036,8 @@ if ($cfg->get('dyn') =~ /se/) {
statefreq se_partmethod se_topology se_ftype
integration nu nu_div nu_p nu_q nu_top se_phys_tscale
interpolate_analysis interp_nlat interp_nlon vert_remap_q_alg
- interp_type interp_gridtype se_limiter_option qsplit rsplit tstep_type);
+ interp_type interp_gridtype se_limiter_option qsplit rsplit tstep_type
+ hypervis_scaling mesh_file);
foreach my $var (@vars) {
add_default($nl, $var);
@@ -3015,6 +3052,7 @@ add_default($nl, 'history_aero_optics');
add_default($nl, 'history_budget');
add_default($nl, 'history_eddy');
add_default($nl, 'history_waccm');
+add_default($nl, 'history_clubb');
# The history output for the AMWG variability diagnostics assumes that auxilliary history
# files h1, h2, and h3 contain daily, 6-hrly, and 3-hrly output respectively. If this output
diff --git a/models/atm/cam/bld/config_files/definition.xml b/models/atm/cam/bld/config_files/definition.xml
index 72038ad26fab..e18051ce6f61 100644
--- a/models/atm/cam/bld/config_files/definition.xml
+++ b/models/atm/cam/bld/config_files/definition.xml
@@ -38,8 +38,8 @@ Option to turn on waccmx thermosphere/ionosphere extension: 0 => no, 1 => yes
Physics package: cam3, cam4, cam5, ideal (Held-Suarez forcings), adiabatic.
-
-Microphysics package: rk (Rasch and Kristjansson), mg1 (Morrison and Gettelman two moment scheme CAM5.1), mg1.5 (Morrison and Gettelman second version development).
+
+Microphysics package: rk (Rasch and Kristjansson), mg1 (Morrison and Gettelman two moment scheme CAM5.1), mg1.5 (Morrison and Gettelman second version development), mg2 ((Morrison and Gettelman second version).
Macrophysics package: RK, Park, CLUBB_SGS.
@@ -47,6 +47,15 @@ Macrophysics package: RK, Park, CLUBB_SGS.
Switch to turn on/off CLUBB_SGS package: 0 => no, 1 => yes
+
+Switch to turn on UNICON package: 0 => off, 1 => on
+
+
+Switch to turn on/off CLUBB_SGS using clubb to calculate deep: 0 => no, 1 => yes
+
+
+Switch to turn on/off advecting CLUBB moments: 0 => no, 1 => yes
+
PBL package: uw (University of Washington), hb (Holtslag and Boville), hbr
(Holtslag, Boville, and Rasch), clubb_sgs.
diff --git a/models/atm/cam/bld/config_files/horiz_grid.xml b/models/atm/cam/bld/config_files/horiz_grid.xml
index f13774722ece..1220a5e0bebc 100644
--- a/models/atm/cam/bld/config_files/horiz_grid.xml
+++ b/models/atm/cam/bld/config_files/horiz_grid.xml
@@ -38,5 +38,9 @@
+
+
+
+
diff --git a/models/atm/cam/bld/configure b/models/atm/cam/bld/configure
index a55235c4e52a..cd7e76e258cc 100755
--- a/models/atm/cam/bld/configure
+++ b/models/atm/cam/bld/configure
@@ -123,6 +123,8 @@ OPTIONS
trop_mam3 | trop_mam7 | super_fast_llnl | super_fast_llnl_mam3 |
trop_strat_soa | trop_strat_mam3 | trop_strat_mam7 | none ]. Default: trop_mam3.
-clubb_sgs Turns on CLUBB_SGS
+ -clubb_opts Comma separated list of CLUBB options to turn on/off. By default they are all off. Current
+ options are: clubb_do_adv(Advect CLUBB moments), clubb_do_deep(CLUBB does the deep convection)
-co2_cycle This option is meant to be used with the -ccsm_seq option. It modifies the
CAM configuration by increasing the number of advected constituents by 4.
-comp_intf Specify the component interfaces [mct | esmf] (default: mct).
@@ -136,7 +138,7 @@ OPTIONS
se grids.
-max_n_rad_cnst Maximum number of constituents that are either radiatively
active, or in any single diagnostic list for the radiation.
- -microphys Specify the microphysics option [mg1 | mg1.5 | rk].
+ -microphys Specify the microphysics option [mg1 | mg1.5 | mg2 | rk].
-nadv Set total number of advected species to .
-nadv_tt Set number of advected test tracers .
-nlev Set number of levels to .
@@ -856,6 +858,12 @@ if ($co2_cycle and $print>=2) { print "co2_cycle option: ON$eol"; }
# Micro-physics package
# The default for the current physics package is:
my $microphys_pkg = 'mg1';
+
+#Set the default microphysics package for CLUBB to mg2
+if (defined $opts{'clubb_sgs'}) {
+ $microphys_pkg = 'mg2';
+}
+
# But if the physics package is adiabatic, ideal, cam3, cam4, change the default
if ($phys_pkg =~ m/^ideal$|^adiabatic$|^cam[34]$/) {
$microphys_pkg = 'rk';
@@ -916,6 +924,20 @@ if ($clubb_sgs and $microphys_pkg !~ m/^mg/) {
EOF
}
+#-----------------------------------------------------------------------------------------------
+# Break apart CLUBB options into separate fields
+
+if (defined $opts{'clubb_opts'}) {
+ my @clubb_temp_opts = split /,/, $opts{'clubb_opts'};
+ foreach (@clubb_temp_opts) {
+ $cfg_ref->set("$_", '1');
+ }
+}
+my $clubb_do_deep = $cfg_ref->get('clubb_do_deep');
+my $clubb_do_adv = $cfg_ref->get('clubb_do_adv');
+if ($print>=2) { print "clubb_do_deep=',$clubb_do_deep,$eol"; }
+if ($print>=2) { print "clubb_do_adv=',$clubb_do_adv,$eol"; }
+
#-----------------------------------------------------------------------------------------------
# Macro-physics package
# The default for the current physics package is:
@@ -1434,10 +1456,19 @@ else {
$nadv += 2;
if ($print>=2) { print "Advected constituents added by $microphys_pkg microphysics: 2$eol"; }
}
- elsif ($microphys_pkg =~ /^mg/) {
+ elsif ($microphys_pkg =~ /^mg1/) {
$nadv += 4;
if ($print>=2) { print "Advected constituents added by $microphys_pkg microphysics: 4$eol"; }
}
+ elsif ($microphys_pkg =~/^mg2/) {
+ $nadv += 8;
+ if ($print>=2) { print "Advected constituents added by $microphys_pkg microphysics: 8$eol"; }
+ }
+
+ if ($clubb_do_adv) {
+ $nadv += 9;
+ if ($print>=2) { print "Advected constituents added by $microphys_pkg microphysics: 8$eol"; }
+ }
# co2_cycle
if ($co2_cycle) {
@@ -1960,6 +1991,10 @@ if ($clubb_sgs == 1) {
$cfg_cppdefs .= " -DCLUBB_REAL_TYPE=dp";
}
+if ($clubb_do_deep == 1) {
+ $cfg_cppdefs .= ' -DCLUBBND_CAM';
+}
+
#-----------------------------------------------------------------------------------------------
# External libraries ###########################################################################
#-----------------------------------------------------------------------------------------------
diff --git a/models/atm/cam/bld/namelist_files/namelist_defaults_cam.xml b/models/atm/cam/bld/namelist_files/namelist_defaults_cam.xml
index d715c4a5dd3c..7ff11c50534c 100644
--- a/models/atm/cam/bld/namelist_files/namelist_defaults_cam.xml
+++ b/models/atm/cam/bld/namelist_files/namelist_defaults_cam.xml
@@ -21,6 +21,10 @@
1800
900
600
+600
+900
+600
+600
3600
@@ -144,7 +148,28 @@
atm/cam/inic/homme/cami_1850-01-01_ne240np4_L26_c110314.nc
atm/cam/inic/homme/cami_0000-09-01_ne240np4_L26_c061106.nc
-atm/cam/inic/homme/cami-mam3_0000-01-ne240np4_L30_c111004.nc
+atm/cam/inic/homme/cami-mam3_0000-01-ne240np4_L30_c111004.nc
+
+atm/cam/inic/homme/cami-mam3_0000-01-01_arm30x8_L30_c130424.nc
+atm/cam/inic/homme/cami_0003-01-01_arm30x8_L26_ape_c000000.nc
+
+atm/cam/inic/homme/cami-mam3_0000-01-01_arm_x8v3_lowcon_np4_L30_c000000.nc
+atm/cam/inic/homme/cami_0003-01-01_arm_x8v3_lowcon_np4_L26_ape_c000000.nc
+
+
+
+atm/cam/inic/homme/cami-mam3_0000-01-01_conusx4v1np4_L30_c141106.nc
+atm/cam/inic/homme/cami_0003-01-01_conusx4v1np4_L30_ape_c000000.nc
+
+
+
+atm/cam/inic/homme/cami-mam3_0000-01-01_svalbardx8v1np4_L30_c141107.nc
+atm/cam/inic/homme/cami_0003-01-01_svalbardx8v1np4_L30_ape_c000000.nc
+
+
+
+atm/cam/inic/homme/cami-mam3_0000-01-01_sooberingoax4x8v1np4_L30_c141110.nc
+atm/cam/inic/homme/cami_0003-01-01_sooberingoax4x8v1np4_L30_ape_c000000.nc
atm/cam/inic/homme/cami_0000-01-01_ne5np8_L26_ape_c061102.nc
atm/cam/inic/homme/cami_0000-01-01_ne16np4_L26_ape_c071213.nc
@@ -178,6 +203,10 @@
atm/cam/topo/USGS-gtopo30_ne120np4_16xdel2-PFC-consistentSGH.nc
atm/cam/topo/USGS_gtopo30_0.23x0.31_smooth1000-50_ne240np4_c061107.nc
+atm/cam/inic/homme/USGS-gtopo30_arm_x8v3_lowcon_tensor12xconsistentSGH.nc
+atm/cam/topo/USGS-gtopo30_0.9x1.25_remap_conusx4v1_c051027.nc
+atm/cam/topo/USGS-gtopo30_0.9x1.25_remap_svalbardx8v1_c051027.nc
+atm/cam/topo/USGS-gtopo30_0.9x1.25_remap_sooberingoax4x8v1_c051027.nc
@@ -621,6 +650,10 @@
atm/cam/chem/trop_mam/atmsrf_ne60np4_110920.nc
atm/cam/chem/trop_mam/atmsrf_ne120np4_110920.nc
atm/cam/chem/trop_mam/atmsrf_ne240np4_110920.nc
+atm/cam/chem/trop_mam/atmsrf_armx8v3.nc
+atm/cam/chem/trop_mam/atmsrf_conusx4v1.nc
+atm/cam/chem/trop_mam/atmsrf_svalbardx8v1.nc
+atm/cam/chem/trop_mam/atmsrf_sooberingoax4x8v1.nc
atm/cam/chem/trop_mozart/dvel/depvel_monthly.nc
@@ -700,6 +733,15 @@
.false.
.true.
+
+ .false.
+ .true.
+ .false.
+ .false.
+ .true.
+ .false.
+ 300.0D0
+ 1.2D0
.false.
@@ -707,21 +749,48 @@
-RK
-MG
+ RK
+ MG
MG
+ MG
+
+ 1
+ 0
+ 1
+ 400.D-6
+
+ 1
+ 5
+ 2
+ 250.D-6
+
+ 2
+ 0
+ 2
+ 1
+ 150.D-6
+ 195.D-6
+ 195.D-6
+
+ max_overlap
+ in_cloud
-1
-0
+ 1.0D0
+ 0.1D0
-1
-5
+ .false.
+
+ 1
+ 6
.false.
- 400.0D-6
- 400.0D-6
- 250.0D-6
+
+1.0D0
+1.2D0
+1.2D0
+1.2D0
+1.0D0
none
@@ -776,6 +845,8 @@
1.0D0
0.6D0
+1.0D0
+3.0D0
.false.
@@ -798,6 +869,8 @@
ZM
+CLUBB_SGS
+UNICON
diag_TKE
@@ -806,6 +879,7 @@
CLUBB_SGS
UW
+UNICON
Hack
Hack
CLUBB_SGS
@@ -824,6 +898,7 @@
0.900D0
0.910D0
+ 0.950D0
0.8975D0
0.9125D0
0.8875D0
@@ -901,9 +976,15 @@
0.70D0
0.70D0
+ 0.80D0
+ 0.85D0
+
+ 1.1D0
+ 1.0D0
+
5.0e-6
- 9.5e-6
+ 9.5e-6
45.0e-6
45.0e-6
45.0e-6
@@ -958,6 +1039,7 @@
0.0030D0
0.0059D0
0.0035D0
+ 0.0075D0
0.0035D0
0.0035D0
0.0020D0
@@ -982,6 +1064,7 @@
1.0E-6
1.0E-6
+ .false.
@@ -1038,6 +1121,7 @@
.false.
.false.
.true.
+ .true.
@@ -1049,6 +1133,12 @@
480
"explicit"
+/dev/null
+atm/cam/inic/homme/arm_x8v3_lowcon.g
+atm/cam/inic/homme/conusx4v1.g
+atm/cam/inic/homme/svalbardx8v1.g
+atm/cam/inic/homme/sooberingoax4x8v1.g
+
2.5e5
1.0e5
@@ -1060,6 +1150,11 @@
1.0e13
1.1e12
+ 8.0e-8
+ 8.0e-8
+ 8.0e-8
+ 8.0e-8
+
-1.0
@@ -1070,7 +1165,10 @@
1.0e14
1.0e13
1.1e12
-
+ 8.0e-8
+ 8.0e-8
+ 8.0e-8
+ 8.0e-8
2.5e15
5.0e16
@@ -1079,6 +1177,10 @@
2.5e14
2.5e13
2.5e12
+ 20.0e-8
+ 20.0e-8
+ 20.0e-8
+ 20.0e-8
2
@@ -1090,6 +1192,10 @@
4
4
1
+ 8
+ 7
+ 8
+ 8
1
@@ -1112,6 +1218,10 @@
4
4
5
+ 5
+ 4
+ 5
+ 5
5
5
@@ -1120,6 +1230,17 @@
20
25
+ 0
+ 3.2
+ 3.2
+ 3.2
+ 3.2
+
+ 0
+ 0
+ 0
+ 0
+
0
@@ -1188,7 +1309,11 @@
ccsm4_init/b40.1850.track1.1deg.006/0863-01-01/b40.1850.track1.1deg.006.clm2.r.0863-01-01-00000.nc
ccsm4_init/b40.1850.track1.2deg.003/year_401/b40.1850.track1.2deg.003.clm2.r.0401-01-01-00000.nc
lnd/clm2/initdata/clmi.BCN.1850-01-01_48x96_gx3v7_simyr1850_c110421.nc
-lnd/clm2/initdata/clmi.BCN.2000-01-01_ne30np4_gx1v6_simyr2000_c110328.nc
+lnd/clm2/initdata/clmi.BCN.2000-01-01_ne30np4_gx1v6_simyr2000_c110328.nc
+lnd/clm2/initdata/clmi.armx8v3.1850-01-01.nc
+lnd/clm2/initdata/clmi.conusx4v1.2000-01-01_c141106.nc
+lnd/clm2/initdata/clmi.svalbardx8v1.1850-01-01.nc
+lnd/clm2/initdata/clmi.sooberingoax4x8v1.1850-01-01_c141110.nc
diff --git a/models/atm/cam/bld/namelist_files/namelist_definition.xml b/models/atm/cam/bld/namelist_files/namelist_definition.xml
index 0200bbe675f8..ec6cdb2355ef 100644
--- a/models/atm/cam/bld/namelist_files/namelist_definition.xml
+++ b/models/atm/cam/bld/namelist_files/namelist_definition.xml
@@ -53,6 +53,218 @@
This is an optional attribute that is mainly useful for variables
that have only a small number of allowed values.
-->
+
+
+
+ Toggle Model Nudging ON/OFF.
+ Default: FALSE
+
+
+
+ Full pathname of analyses data to use for nudging.
+ Default: none
+
+
+
+ Template for Nudging analyses file names.
+ Default: none
+
+
+
+ Number of analyses files per day.
+ Default: none
+
+
+
+ Number of time to update model data per day.
+ Default: none
+
+
+
+ Profile index for U nudging.
+ Default: none
+
+
+
+ Coeffcient for U nudging.
+ Default: none
+
+
+
+ Profile index for V nudging.
+ Default: none
+
+
+
+ Coeffcient for V nudging.
+ Default: none
+
+
+
+ Profile index for T nudging.
+ Default: none
+
+
+
+ Coeffcient for T nudging.
+ Default: none
+
+
+
+ Profile index for Q nudging.
+ Default: none
+
+
+
+ Coeffcient for Q nudging.
+ Default: none
+
+
+
+ Profile index for PS nudging.
+ Default: none
+
+
+
+ Coeffcient for PS nudging.
+ Default: none
+
+
+
+ Year at which Nudging Begins.
+ Default: none
+
+
+
+ Month at which Nudging Begins.
+ Default: none
+
+
+
+ Day at which Nudging Begins.
+ Default: none
+
+
+
+ Year at which Nudging Ends.
+ Default: none
+
+
+
+ Month at which Nudging Ends.
+ Default: none
+
+
+
+ Day at which Nudging Ends.
+ Default: none
+
+
+
+ LOW Coeffcient for Horizontal Window.
+ Default: none
+
+
+
+ HIGH Coeffcient for Horizontal Window.
+ Default: none
+
+
+
+ LAT0 of Horizonalt Window.
+ Default: none
+
+
+
+ Width of LAT Window.
+ Default: none
+
+
+
+ Steepness of LAT Window.
+ Default: none
+
+
+
+ LON0 of Horizontal Window.
+ Default: none
+
+
+
+ Width of LON Window.
+ Default: none
+
+
+
+ Steepness of LON Window.
+ Default: none
+
+
+
+ LOW Coeffcient for Vertical Window.
+ Default: none
+
+
+
+ HIGH Coeffcient for Vertical Window.
+ Default: none
+
+
+
+ HIGH Level Index for Verical Window.
+ Default: none
+
+
+
+ Steepness of HIGH end of Vertical Window.
+ Default: none
+
+
+
+ LOW Level Index for Verical Window.
+ Default: none
+
+
+
+ Steepness of LOW end of Vertical Window.
+ Default: none
+
+
@@ -1586,6 +1798,14 @@ This default logical is set in cospsimulator_intr.F90
Default: FALSE
+
+
+
+Number of macrophysics/microphysics substeps.
+Default: 1
+
+
@@ -1661,6 +1881,24 @@ cloud liquid (cldliq).
Default: .true.
+
+Number of substeps over MG microphysics.
+Default: 1
+
+
+
+Type of precipitation fraction.
+Default: max_overlap
+
+
+
+Efficiency factor for berg
+Default: 1
+
+
Switch to control whether MG microphysics performs a uniform calculation or not
@@ -1675,12 +1913,42 @@ Default: set by build-namelist
-
prescribed aerosol bulk sulfur scale factor
Default: 2
+
+Switch to turn on heterogeneous freezing code.
+Default: .false.
+
+
+
+Add diagnostic output for heterogeneous freezing code.
+Default: .false.
+
+
+
+Switch to turn on treatment of pre-existing ice in the ice nucleation code.
+Default: .false.
+
+
+
+Add diagnostics for pre-existing ice option in ice nucleation code to history output.
+Default: .false.
+
+
+
+Subgrid scaling factor for relative humidity in ice nucleation code.
+Default: set by build-namelist
+
+
@@ -1734,6 +2002,17 @@ Minimum rh for high stable clouds.
Default: set by build-namelist
+
+Minimum rh for high stable clouds poleward of 60 degrees.
+**This is valid only for RK microphysis scheme**
+Default: set to cldfrc_rhminh
+
+
+
+Maximum pressure level (mbars) where the cldfrc_rhminp setting is applied.
+Default: 300. mbar
+
+
parameter for shallow convection cloud fraction.
@@ -1783,6 +2062,18 @@ Critical RH for ice clouds (Wilson & Ballard scheme).
Default: 0.93
+
+Minimum rh for ice cloud fraction > 0.
+Default: set by build-namelist
+
+
+
+rhi at which ice cloud fraction = 1.
+Default: set by build-namelist
+
+
@@ -1808,6 +2099,12 @@ Relaxation time in ZM deep convection scheme.
Default: set by build-namelist
+
+Trigger and memory option in ZM deep convection scheme.
+Default: FALSE
+
+
+ group="phys_ctl_nl" valid_values="ZM,UNICON,CLUBB_SGS,off" >
Type of deep convection scheme employed. 'ZM' for Zhang-McFarlane;
'off' for none.
-Default: 'ZM'
+Default: 'ZM' unless using 'UNICON'
Type of macrophysics scheme employed. 'park' for Park
(1998); 'RK' for Rasch and Kristjansson (1998); 'CLUBB_SGS' clubb.
-Default: 'park'
+Default: set by build-namelist
+ group="phys_ctl_nl" valid_values="Hack,UW,CLUBB_SGS,UNICON" >
Type of shallow convection scheme employed. 'Hack' for Hack shallow convection;
'UW' for original McCaa UW pbl scheme, modified by Sungsu Park; 'CLUBB_SGS'
-for CLUBB_SGS.
+for CLUBB_SGS; or UNICON which doesn't distinquish shallow and deep.
Default: set by build-namelist (depends on eddy_scheme).
@@ -1956,6 +2253,12 @@ vertical diffusion routine.
Default: set by build-namelist
+
+Apply ice supersaturation adjustment code
+Default: .false.
+
+
Maximum master length scale designed to address issues in diag_TKE outside the
@@ -2019,6 +2322,55 @@ diffusion solver routine.
Default: set by build-namelist
+
+Apply cloud top radiative cooling parameterization
+Default: .false.
+
+
+
+Include effects of precip evaporation on turbulent moments
+Default: .false.
+
+
+
+Explicit diffusion on temperature and moisture when CLUBB is on
+Default: .false.
+
+
+
+CLUBB do explicit diffusion with a stability correction
+Default: .false.
+
+
+
+
+CLUBB timestep.
+Default: set by build-namelist
+
+
+
+Rain evaporation efficiency factor.
+Default: set by build-namelist
+
+
+
+Switch for CLUBB_ADV
+Default: FALSE
+
+
+
+Switch for CLUBBND_CAM
+Default: FALSE
+
+
+
+Switch for diagnostics specific to CLUBB.
+Default: .true.
+
+
@@ -4528,6 +4886,33 @@ Only "cube" is supported in CAM.
Default: Set by build-namelist.
+
+baseline ne for scalar hypervis tuning
+Default: Set by build-namelist.
+
+
+
+Exodus format grid file
+Default: Set by build-namelist.
+
+
+
+Default: Set by build-namelist.
+
+
+
+Default: Set by build-namelist.
+
+
+
+Default: Set by build-namelist.
+
+
0
+ real(r8), intent(in) :: T0(pcols,pver) ! Temperature [K]
+ real(r8), intent(in) :: p(pcols,pver) ! Pressure at the layer mid-point [Pa]
+ real(r8), intent(in) :: clrw_old(pcols,pver) ! Clear sky fraction at the previous time step for liquid stratus process
+ real(r8), intent(in) :: clri_old(pcols,pver) ! Clear sky fraction at the previous time step for ice stratus process
+ real(r8), pointer :: tke(:,:) ! (pcols,pverp) TKE from the PBL scheme
+ real(r8), pointer :: qtl_flx(:,:) ! (pcols,pverp) overbar(w'qtl') from PBL scheme where qtl = qv + ql
+ real(r8), pointer :: qti_flx(:,:) ! (pcols,pverp) overbar(w'qti') from PBL scheme where qti = qv + qi
+ real(r8), pointer :: cmfr_det(:,:) ! (pcols,pver) Detrained mass flux from the convection scheme
+ real(r8), pointer :: qlr_det(:,:) ! (pcols,pver) Detrained ql from the convection scheme
+ real(r8), pointer :: qir_det(:,:) ! (pcols,pver) Detrained qi from the convection scheme
+
+ real(r8), intent(out) :: rhmini_arr(pcols,pver)
+ real(r8), intent(out) :: rhminl_arr(pcols,pver)
+ real(r8), intent(out) :: rhminl_adj_land_arr(pcols,pver)
+ real(r8), intent(out) :: rhminh_arr(pcols,pver)
+ real(r8), intent(out) :: d_rhmin_liq_PBL(pcols,pver)
+ real(r8), intent(out) :: d_rhmin_ice_PBL(pcols,pver)
+ real(r8), intent(out) :: d_rhmin_liq_det(pcols,pver)
+ real(r8), intent(out) :: d_rhmin_ice_det(pcols,pver)
+
+ ! local variables
+
+ integer :: i, k
+
+ real(r8) :: esat_tmp(pcols) ! Dummy for saturation vapor pressure calc.
+ real(r8) :: qsat_tmp(pcols) ! Saturation water vapor specific humidity [kg/kg]
+ real(r8) :: sig_tmp
+ !---------------------------------------------------------------------------------------------------
+
+
+
+ ! ---------------------------------- !
+ ! Calc critical RH for ice stratus !
+ ! ---------------------------------- !
+
+ rhmini_arr(:,:) = rhmini_const
+
+ if (i_rhmini > 0) then
+
+ ! Compute the drop of critical RH by convective detrainment of cloud condensate
+
+ do k = top_lev, pver
+ do i = 1, ncol
+ d_rhmin_ice_det(i,k) = tau_deti*(gravit/dp(i,k))*cmfr_det(i,k)*clri_old(i,k)*qir_det(i,k)*3.6e6_r8
+ d_rhmin_ice_det(i,k) = max(0._r8,min(0.5_r8,d_rhmin_ice_det(i,k)))
+ end do
+ end do
+
+ if (i_rhmini == 1) then
+ rhmini_arr(:ncol,:) = rhmini_const - d_rhmin_ice_det(:ncol,:)
+ end if
+
+ end if
+
+ if (i_rhmini == 2) then
+
+ ! Compute the drop of critical RH by the variability induced by PBL turbulence
+
+ do k = top_lev, pver
+ call qsat_ice(T0(1:ncol,k), p(1:ncol,k), esat_tmp(1:ncol), qsat_tmp(1:ncol))
+
+ do i = 1, ncol
+ sig_tmp = 0.5_r8 * ( qti_flx(i,k) / sqrt(max(qsmall,tke(i,k))) + &
+ qti_flx(i,k+1) / sqrt(max(qsmall,tke(i,k+1))) )
+ d_rhmin_ice_PBL(i,k) = c_aniso*sig_tmp/max(qsmall,qsat_tmp(i))
+ d_rhmin_ice_PBL(i,k) = max(0._r8,min(0.5_r8,d_rhmin_ice_PBL(i,k)))
+
+ rhmini_arr(i,k) = 1._r8 - d_rhmin_ice_PBL(i,k) - d_rhmin_ice_det(i,k)
+ end do
+ end do
+ end if
+
+ if (i_rhmini > 0) then
+ do k = top_lev, pver
+ do i = 1, ncol
+ rhmini_arr(i,k) = max(0._r8,min(rhmaxi,rhmini_arr(i,k)))
+ end do
+ end do
+ end if
+
+ ! ------------------------------------- !
+ ! Choose critical RH for liquid stratus !
+ ! ------------------------------------- !
+
+ rhminl_arr(:,:) = rhminl_const
+ rhminl_adj_land_arr(:,:) = rhminl_adj_land_const
+ rhminh_arr(:,:) = rhminh_const
+
+ if (i_rhminl > 0) then
+
+ ! Compute the drop of critical RH by convective detrainment of cloud condensate
+
+ do k = top_lev, pver
+ do i = 1, ncol
+ d_rhmin_liq_det(i,k) = tau_detw*(gravit/dp(i,k))*cmfr_det(i,k)*clrw_old(i,k)*qlr_det(i,k)*3.6e6_r8
+ d_rhmin_liq_det(i,k) = max(0._r8,min(0.5_r8,d_rhmin_liq_det(i,k)))
+ end do
+ end do
+
+ if (i_rhminl == 1) then
+ rhminl_arr(:ncol,top_lev:) = rhminl_const - d_rhmin_liq_det(:ncol,top_lev:)
+ rhminh_arr(:ncol,top_lev:) = rhminh_const - d_rhmin_liq_det(:ncol,top_lev:)
+ end if
+
+ end if
+
+ if (i_rhminl == 2) then
+
+ ! Compute the drop of critical RH by the variability induced by PBL turbulence
+
+ do k = top_lev, pver
+ call qsat_water(T0(1:ncol,k), p(1:ncol,k), esat_tmp(1:ncol), qsat_tmp(1:ncol))
+
+ do i = 1, ncol
+ sig_tmp = 0.5_r8 * ( qtl_flx(i,k) / sqrt(max(qsmall,tke(i,k))) + &
+ qtl_flx(i,k+1) / sqrt(max(qsmall,tke(i,k+1))) )
+ d_rhmin_liq_PBL(i,k) = c_aniso*sig_tmp/max(qsmall,qsat_tmp(i))
+ d_rhmin_liq_PBL(i,k) = max(0._r8,min(0.5_r8,d_rhmin_liq_PBL(i,k)))
+
+ rhminl_arr(i,k) = 1._r8 - d_rhmin_liq_PBL(i,k) - d_rhmin_liq_det(i,k)
+ rhminl_adj_land_arr(i,k) = 0._r8
+ rhminh_arr(i,k) = rhminl_arr(i,k)
+ end do
+ end do
+ end if
+
+ if (i_rhminl > 0) then
+ do k = top_lev, pver
+ do i = 1, ncol
+ rhminl_arr(i,k) = max(rhminl_adj_land_arr(i,k),min(1._r8,rhminl_arr(i,k)))
+ rhminh_arr(i,k) = max(0._r8,min(1._r8,rhminh_arr(i,k)))
+ end do
+ end do
+ end if
+
+end subroutine rhcrit_calc
+
+!=======================================================================================================
subroutine instratus_condensate( lchnk, ncol, k, &
p_in, T0_in, qv0_in, ql0_in, qi0_in, &
+ ni0_in, &
a_dc_in, ql_dc_in, qi_dc_in, &
a_sc_in, ql_sc_in, qi_sc_in, &
landfrac, snowh, &
+ rhmini_in, rhminl_in, rhminl_adj_land_in, rhminh_in, &
T_out, qv_out, ql_out, qi_out, &
al_st_out, ai_st_out, ql_st_out, qi_st_out )
@@ -1173,10 +1418,6 @@ subroutine instratus_condensate( lchnk, ncol, k, &
! whenever stratus exists in the equilibrium state !
! ------------------------------------------------------- !
- use time_manager, only: is_first_step, get_nstep
-
- implicit none
-
integer, intent(in) :: lchnk ! Chunk identifier
integer, intent(in) :: ncol ! Number of atmospheric columns
integer, intent(in) :: k ! Layer index
@@ -1186,6 +1427,7 @@ subroutine instratus_condensate( lchnk, ncol, k, &
real(r8), intent(in) :: qv0_in(pcols) ! Grid-mean water vapor [kg/kg]
real(r8), intent(in) :: ql0_in(pcols) ! Grid-mean LWC [kg/kg]
real(r8), intent(in) :: qi0_in(pcols) ! Grid-mean IWC [kg/kg]
+ real(r8), intent(in) :: ni0_in(pcols)
real(r8), intent(in) :: a_dc_in(pcols) ! Deep cumulus cloud fraction
real(r8), intent(in) :: ql_dc_in(pcols) ! In-deep cumulus LWC [kg/kg]
@@ -1197,6 +1439,11 @@ subroutine instratus_condensate( lchnk, ncol, k, &
real(r8), intent(in) :: landfrac(pcols) ! Land fraction
real(r8), intent(in) :: snowh(pcols) ! Snow depth (liquid water equivalent)
+ real(r8), intent(in) :: rhmini_in(pcols)
+ real(r8), intent(in) :: rhminl_in(pcols)
+ real(r8), intent(in) :: rhminl_adj_land_in(pcols)
+ real(r8), intent(in) :: rhminh_in(pcols)
+
real(r8), intent(out) :: T_out(pcols) ! Temperature [K]
real(r8), intent(out) :: qv_out(pcols) ! Grid-mean water vapor [kg/kg]
real(r8), intent(out) :: ql_out(pcols) ! Grid-mean LWC [kg/kg]
@@ -1267,6 +1514,11 @@ subroutine instratus_condensate( lchnk, ncol, k, &
real(r8) Tmax
integer caseid
+ real(r8) rhmini
+ real(r8) rhminl
+ real(r8) rhminl_adj_land
+ real(r8) rhminh
+
! ---------------- !
! Main Computation !
! ---------------- !
@@ -1275,11 +1527,14 @@ subroutine instratus_condensate( lchnk, ncol, k, &
esat_in(1:ncol), qsat_in(1:ncol))
U0_in(:ncol) = qv0_in(:ncol)/qsat_in(:ncol)
if( CAMstfrac ) then
- call astG_RHU(U0_in(:),p_in(:),qv0_in(:),landfrac(:),snowh(:),al0_st_nc_in(:),G0_nc_in(:),ncol)
+ call astG_RHU(U0_in(:),p_in(:),qv0_in(:),landfrac(:),snowh(:),al0_st_nc_in(:),G0_nc_in(:),ncol,&
+ rhminl_in(:), rhminl_adj_land_in(:), rhminh_in(:))
else
- call astG_PDF(U0_in(:),p_in(:),qv0_in(:),landfrac(:),snowh(:),al0_st_nc_in(:),G0_nc_in(:),ncol)
+ call astG_PDF(U0_in(:),p_in(:),qv0_in(:),landfrac(:),snowh(:),al0_st_nc_in(:),G0_nc_in(:),ncol,&
+ rhminl_in(:), rhminl_adj_land_in(:), rhminh_in(:))
endif
- call aist_vector(qv0_in(:),T0_in(:),p_in(:),qi0_in(:),landfrac(:),snowh(:),ai0_st_nc_in(:),ncol)
+ call aist_vector(qv0_in(:),T0_in(:),p_in(:),qi0_in(:),ni0_in(:),landfrac(:),snowh(:),ai0_st_nc_in(:),ncol,&
+ rhmaxi, rhmini_in(:), rhminl_in(:), rhminl_adj_land_in(:), rhminh_in(:))
do i = 1, ncol
@@ -1309,6 +1564,11 @@ subroutine instratus_condensate( lchnk, ncol, k, &
es = esat_in(i)
qs = qsat_in(i)
+
+ rhmini = rhmini_in(i)
+ rhminl = rhminl_in(i)
+ rhminl_adj_land = rhminl_adj_land_in(i)
+ rhminh = rhminh_in(i)
idxmod = 0
caseid = -1
@@ -1327,11 +1587,14 @@ subroutine instratus_condensate( lchnk, ncol, k, &
U0 = (qv0/qsat0)
U0_nc = U0
if( CAMstfrac ) then
- call astG_RHU_single(U0_nc,p,qv0,landfrac(i),snowh(i),al0_st_nc,G0_nc)
+ call astG_RHU_single(U0_nc, p, qv0, landfrac(i), snowh(i), al0_st_nc, G0_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
else
- call astG_PDF_single(U0_nc,p,qv0,landfrac(i),snowh(i),al0_st_nc,G0_nc)
+ call astG_PDF_single(U0_nc, p, qv0, landfrac(i), snowh(i), al0_st_nc, G0_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
endif
- call aist_single(qv0,T0,p,qi0,landfrac(i),snowh(i),ai0_st_nc)
+ call aist_single(qv0,T0,p,qi0,landfrac(i),snowh(i),ai0_st_nc,&
+ rhmaxi, rhmini, rhminl, rhminl_adj_land, rhminh)
ai0_st = (1._r8-a_dc-a_sc)*ai0_st_nc
al0_st = (1._r8-a_dc-a_sc)*al0_st_nc
a0_st = max(ai0_st,al0_st)
@@ -1383,9 +1646,11 @@ subroutine instratus_condensate( lchnk, ncol, k, &
U = qv/qs
U_nc = U
if( CAMstfrac ) then
- call astG_RHU_single(U_nc,p,qv,landfrac(i),snowh(i),al_st_nc,G_nc)
+ call astG_RHU_single(U_nc, p, qv, landfrac(i), snowh(i), al_st_nc, G_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
else
- call astG_PDF_single(U_nc,p,qv,landfrac(i),snowh(i),al_st_nc,G_nc)
+ call astG_PDF_single(U_nc, p, qv, landfrac(i), snowh(i), al_st_nc, G_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
endif
al_st = (1._r8-a_dc-a_sc)*al_st_nc
caseid = 0
@@ -1407,6 +1672,7 @@ subroutine instratus_condensate( lchnk, ncol, k, &
a_dc, ql_dc, qi_dc, &
a_sc, ql_sc, qi_sc, ai0_st, &
qlst_max, Tmin, Tmax, landfrac(i), snowh(i), &
+ rhminl, rhminl_adj_land, rhminh, &
T, qv, ql, qi )
idxmod = 1
caseid = 2
@@ -1426,6 +1692,7 @@ subroutine instratus_condensate( lchnk, ncol, k, &
a_dc, ql_dc, qi_dc, &
a_sc, ql_sc, qi_sc, ai0_st, &
qlst_min, Tmin, Tmax, landfrac(i), snowh(i), &
+ rhminl, rhminl_adj_land, rhminh, &
T, qv, ql, qi )
idxmod = 1
caseid = 3
@@ -1446,6 +1713,7 @@ subroutine instratus_condensate( lchnk, ncol, k, &
a_dc, ql_dc, qi_dc, &
a_sc, ql_sc, qi_sc, ai0_st, &
qlst_max, Tmin, Tmax, landfrac(i), snowh(i), &
+ rhminl, rhminl_adj_land, rhminh, &
T, qv, ql, qi )
idxmod = 1
caseid = 4
@@ -1461,6 +1729,7 @@ subroutine instratus_condensate( lchnk, ncol, k, &
a_dc, ql_dc, qi_dc, &
a_sc, ql_sc, qi_sc, ai0_st, &
qlst_min, Tmin, Tmax, landfrac(i), snowh(i), &
+ rhminl, rhminl_adj_land, rhminh, &
T, qv, ql, qi )
idxmod = 1
caseid = 5
@@ -1492,15 +1761,18 @@ subroutine instratus_condensate( lchnk, ncol, k, &
qi = qi0
if( idxmod .eq. 1 ) then
- call aist_single(qv,T,p,qi,landfrac(i),snowh(i),ai_st_nc)
+ call aist_single(qv,T,p,qi,landfrac(i),snowh(i),ai_st_nc,&
+ rhmaxi, rhmini, rhminl, rhminl_adj_land, rhminh)
ai_st = (1._r8-a_dc-a_sc)*ai_st_nc
call qsat_water(T, p, es, qs)
U = (qv/qs)
U_nc = U
if( CAMstfrac ) then
- call astG_RHU_single(U_nc,p,qv,landfrac(i),snowh(i),al_st_nc,G_nc)
+ call astG_RHU_single(U_nc, p, qv, landfrac(i), snowh(i), al_st_nc, G_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
else
- call astG_PDF_single(U_nc,p,qv,landfrac(i),snowh(i),al_st_nc,G_nc)
+ call astG_PDF_single(U_nc, p, qv, landfrac(i), snowh(i), al_st_nc, G_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
endif
al_st = (1._r8-a_dc-a_sc)*al_st_nc
else
@@ -1555,6 +1827,7 @@ subroutine instratus_core( lchnk, icol, k, p, &
a_dc, ql_dc, qi_dc, &
a_sc, ql_sc, qi_sc, ai_st, &
qcst_crit, Tmin, Tmax, landfrac, snowh, &
+ rhminl, rhminl_adj_land, rhminh, &
T, qv, ql, qi )
! ------------------------------------------------------ !
@@ -1563,10 +1836,6 @@ subroutine instratus_core( lchnk, icol, k, p, &
! is satisfied. !
! ------------------------------------------------------ !
- use time_manager, only: is_first_step, get_nstep
-
- implicit none
-
integer, intent(in) :: lchnk ! Chunk identifier
integer, intent(in) :: icol ! Number of atmospheric columns
integer, intent(in) :: k ! Layer index
@@ -1592,6 +1861,10 @@ subroutine instratus_core( lchnk, icol, k, p, &
real(r8), intent(in) :: landfrac ! Land fraction
real(r8), intent(in) :: snowh ! Snow depth (liquid water equivalent)
+ real(r8), intent(in) :: rhminl
+ real(r8), intent(in) :: rhminl_adj_land
+ real(r8), intent(in) :: rhminh
+
real(r8), intent(out) :: T ! Temperature [K]
real(r8), intent(out) :: qv ! Grid-mean water vapor [kg/kg]
real(r8), intent(out) :: ql ! Grid-mean LWC [kg/kg]
@@ -1641,15 +1914,18 @@ subroutine instratus_core( lchnk, icol, k, p, &
call funcd_instratus( x1, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
a_dc, ql_dc, qi_dc, a_sc, ql_sc, qi_sc, ai_st, &
qcst_crit, landfrac, snowh, &
+ rhminl, rhminl_adj_land, rhminh, &
fl, df, qc_nc, fice, al_st )
call funcd_instratus( x2, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
a_dc, ql_dc, qi_dc, a_sc, ql_sc, qi_sc, ai_st, &
qcst_crit, landfrac, snowh, &
+ rhminl, rhminl_adj_land, rhminh, &
fh, df, qc_nc, fice, al_st )
if((fl > 0._r8 .and. fh > 0._r8) .or. (fl < 0._r8 .and. fh < 0._r8)) then
call funcd_instratus( T0, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
a_dc, ql_dc, qi_dc, a_sc, ql_sc, qi_sc, ai_st, &
qcst_crit, landfrac, snowh, &
+ rhminl, rhminl_adj_land, rhminh, &
fl, df, qc_nc, fice, al_st )
rtsafe = T0
goto 10
@@ -1673,6 +1949,7 @@ subroutine instratus_core( lchnk, icol, k, p, &
call funcd_instratus( rtsafe, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
a_dc, ql_dc, qi_dc, a_sc, ql_sc, qi_sc, ai_st, &
qcst_crit, landfrac, snowh, &
+ rhminl, rhminl_adj_land, rhminh, &
f, df, qc_nc, fice, al_st )
do j = 1, 20
if(((rtsafe-xh)*df-f)*((rtsafe-xl)*df-f) > 0._r8 .or. abs(2.0_r8*f) > abs(dxold*df) ) then
@@ -1691,6 +1968,7 @@ subroutine instratus_core( lchnk, icol, k, p, &
call funcd_instratus( rtsafe, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
a_dc, ql_dc, qi_dc, a_sc, ql_sc, qi_sc, ai_st, &
qcst_crit, landfrac, snowh, &
+ rhminl, rhminl_adj_land, rhminh, &
f, df, qc_nc, fice, al_st )
! Sep.21.2010. Sungsu modified to enhance convergence and guarantee 'qlst_min < qlst < qlst_max'.
if( qcst_crit < 0.5_r8 * ( qlst_min + qlst_max ) ) then
@@ -1732,6 +2010,7 @@ end subroutine instratus_core
subroutine funcd_instratus( T, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
a_dc, ql_dc, qi_dc, a_sc, ql_sc, qi_sc, ai_st, &
qcst_crit, landfrac, snowh, &
+ rhminl, rhminl_adj_land, rhminh, &
f, fg, qc_nc, fice, al_st )
! --------------------------------------------------- !
@@ -1764,6 +2043,10 @@ subroutine funcd_instratus( T, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
real(r8), intent(in) :: landfrac ! Land fraction
real(r8), intent(in) :: snowh ! Snow depth (liquid water equivalent)
+ real(r8), intent(in) :: rhminl
+ real(r8), intent(in) :: rhminl_adj_land
+ real(r8), intent(in) :: rhminh
+
real(r8), intent(out) :: f ! Value of minimization function at T
real(r8), intent(out) :: fg ! Gradient of minimization function
real(r8), intent(out) :: qc_nc !
@@ -1802,9 +2085,11 @@ subroutine funcd_instratus( T, p, T0, qv0, ql0, qi0, fice0, muQ0, qc_nc0, &
U = (qv/qs)
U_nc = U
if( CAMstfrac ) then
- call astG_RHU_single(U_nc,p,qv,landfrac,snowh,al_st_nc,G_nc)
+ call astG_RHU_single(U_nc, p, qv, landfrac, snowh, al_st_nc, G_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
else
- call astG_PDF_single(U_nc,p,qv,landfrac,snowh,al_st_nc,G_nc)
+ call astG_PDF_single(U_nc, p, qv, landfrac, snowh, al_st_nc, G_nc, &
+ rhminl_in=rhminl, rhminl_adj_land_in=rhminl_adj_land, rhminh_in=rhminh)
endif
al_st = (1._r8-a_dc-a_sc)*al_st_nc
dUdt = -(alpha*dqcncdt+beta)
@@ -1832,10 +2117,6 @@ subroutine gridmean_RH( lchnk, icol, k, p, T, qv, ql, qi, &
! verison for MG not for RK. !
! ------------------------------------------------------------- !
- use time_manager, only: is_first_step, get_nstep
-
- implicit none
-
integer, intent(in) :: lchnk ! Chunk identifier
integer, intent(in) :: icol ! Number of atmospheric columns
integer, intent(in) :: k ! Layer index
@@ -2002,875 +2283,6 @@ subroutine positive_moisture( ncol, dt, qvmin, qlmin, qimin, dp, &
end subroutine positive_moisture
- ! ----------------- !
- ! End of subroutine !
- ! ----------------- !
-
- subroutine astG_PDF_single( U, p, qv, landfrac, snowh, a, Ga, orhmin )
-
- ! --------------------------------------------------------- !
- ! Compute 'stratus fraction(a)' and Gs=(dU/da) from the !
- ! analytical formulation of triangular PDF. !
- ! Here, 'dV' is the ratio of 'half-width of PDF / qs(p,T)', !
- ! so using constant 'dV' assume that width is proportional !
- ! to the saturation specific humidity. !
- ! dV ~ 0.1. !
- ! cldrh : RH of in-stratus( = 1 if no supersaturation) !
- ! Note that if U > 1, Ga = 1.e10 instead of Ga = 0, that is !
- ! G is discontinuous across U = 1. In fact, it does not !
- ! matter whether Ga = 1.e10 or 0 at a = 1: I derived that !
- ! they will produce the same results. !
- ! --------------------------------------------------------- !
-
- implicit none
-
- real(r8), intent(in) :: U ! Relative humidity
- real(r8), intent(in) :: p ! Pressure [Pa]
- real(r8), intent(in) :: qv ! Grid-mean water vapor specific humidity [kg/kg]
- real(r8), intent(in) :: landfrac ! Land fraction
- real(r8), intent(in) :: snowh ! Snow depth (liquid water equivalent)
-
- real(r8), intent(out) :: a ! Stratus fraction
- real(r8), intent(out) :: Ga ! dU/da
- real(r8), optional, intent(out) :: orhmin ! Critical RH
-
- ! Local variables
- integer :: i ! Loop indexes
- real(r8) dV ! Width of triangular PDF
- real(r8) cldrh ! RH of stratus cloud
- real(r8) rhmin ! Critical RH
- real(r8) rhwght
-
- ! Statement functions
- logical land
- land = nint(landfrac) == 1
-
- ! ---------- !
- ! Parameters !
- ! ---------- !
-
- cldrh = 1.0_r8
-
- ! ---------------- !
- ! Main computation !
- ! ---------------- !
-
- if( p .ge. premib ) then
-
- if( land .and. (snowh.le.0.000001_r8) ) then
- rhmin = rhminl - rhminl_adj_land
- else
- rhmin = rhminl
- endif
-
- dV = cldrh - rhmin
-
- if( U .ge. 1._r8 ) then
- a = 1._r8
- Ga = 1.e10_r8
- elseif( U .gt. (cldrh-dV/6._r8) .and. U .lt. 1._r8 ) then
- a = 1._r8 - (-3._r8/sqrt(2._r8)*(U-cldrh)/dV)**(2._r8/3._r8)
- Ga = dV/sqrt(2._r8)*sqrt(1._r8-a)
- elseif( U .gt. (cldrh-dV) .and. U .le. (cldrh-dV/6._r8) ) then
- a = 4._r8*(cos((1._r8/3._r8)*(acos((3._r8/2._r8/sqrt(2._r8))* &
- (1._r8+(U-cldrh)/dV))-2._r8*3.141592_r8)))**2._r8
- Ga = dV/sqrt(2._r8)*(1._r8/sqrt(a)-sqrt(a))
- elseif( U .le. (cldrh-dV) ) then
- a = 0._r8
- Ga = 1.e10_r8
- endif
-
- if( freeze_dry ) then
- a = a *max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- Ga = Ga/max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- endif
-
- elseif( p .lt. premit ) then
-
- rhmin = rhminh
- dV = cldrh - rhmin
-
- if( U .ge. 1._r8 ) then
- a = 1._r8
- Ga = 1.e10_r8
- elseif( U .gt. (cldrh-dV/6._r8) .and. U .lt. 1._r8 ) then
- a = 1._r8 - (-3._r8/sqrt(2._r8)*(U-cldrh)/dV)**(2._r8/3._r8)
- Ga = dV/sqrt(2._r8)*sqrt(1._r8-a)
- elseif( U .gt. (cldrh-dV) .and. U .le. (cldrh-dV/6._r8) ) then
- a = 4._r8*(cos((1._r8/3._r8)*(acos((3._r8/2._r8/sqrt(2._r8))* &
- (1._r8+(U-cldrh)/dV))-2._r8*3.141592_r8)))**2._r8
- Ga = dV/sqrt(2._r8)*(1._r8/sqrt(a)-sqrt(a))
- elseif( U .le. (cldrh-dV) ) then
- a = 0._r8
- Ga = 1.e10_r8
- endif
-
- else
-
- rhwght = (premib-(max(p,premit)))/(premib-premit)
-
- ! if( land .and. (snowh.le.0.000001_r8) ) then
- ! rhmin = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_r8-rhwght)
- ! else
- rhmin = rhminh*rhwght + rhminl*(1.0_r8-rhwght)
- ! endif
-
- dV = cldrh - rhmin
-
- if( U .ge. 1._r8 ) then
- a = 1._r8
- Ga = 1.e10_r8
- elseif( U .gt. (cldrh-dV/6._r8) .and. U .lt. 1._r8 ) then
- a = 1._r8 - (-3._r8/sqrt(2._r8)*(U-cldrh)/dV)**(2._r8/3._r8)
- Ga = dV/sqrt(2._r8)*sqrt(1._r8-a)
- elseif( U .gt. (cldrh-dV) .and. U .le. (cldrh-dV/6._r8) ) then
- a = 4._r8*(cos((1._r8/3._r8)*(acos((3._r8/2._r8/sqrt(2._r8))* &
- (1._r8+(U-cldrh)/dV))-2._r8*3.141592_r8)))**2._r8
- Ga = dV/sqrt(2._r8)*(1._r8/sqrt(a)-sqrt(a))
- elseif( U .le. (cldrh-dV) ) then
- a = 0._r8
- Ga = 1.e10_r8
- endif
-
- endif
-
- if (present(orhmin)) orhmin = rhmin
-
- return
- end subroutine astG_PDF_single
-
- ! ----------------- !
- ! End of subroutine !
- ! ----------------- !
-
- subroutine astG_PDF( U_in, p_in, qv_in, landfrac_in, snowh_in, a_out, Ga_out, ncol )
-
- ! --------------------------------------------------------- !
- ! Compute 'stratus fraction(a)' and Gs=(dU/da) from the !
- ! analytical formulation of triangular PDF. !
- ! Here, 'dV' is the ratio of 'half-width of PDF / qs(p,T)', !
- ! so using constant 'dV' assume that width is proportional !
- ! to the saturation specific humidity. !
- ! dV ~ 0.1. !
- ! cldrh : RH of in-stratus( = 1 if no supersaturation) !
- ! Note that if U > 1, Ga = 1.e10 instead of Ga = 0, that is !
- ! G is discontinuous across U = 1. In fact, it does not !
- ! matter whether Ga = 1.e10 or 0 at a = 1: I derived that !
- ! they will produce the same results. !
- ! --------------------------------------------------------- !
-
- implicit none
-
- integer, intent(in) :: ncol
- real(r8), intent(in) :: U_in(pcols) ! Relative humidity
- real(r8), intent(in) :: p_in(pcols) ! Pressure [Pa]
- real(r8), intent(in) :: qv_in(pcols) ! Grid-mean water vapor specific humidity [kg/kg]
- real(r8), intent(in) :: landfrac_in(pcols) ! Land fraction
- real(r8), intent(in) :: snowh_in(pcols) ! Snow depth (liquid water equivalent)
-
- real(r8), intent(out) :: a_out(pcols) ! Stratus fraction
- real(r8), intent(out) :: Ga_out(pcols) ! dU/da
-
- real(r8) :: U ! Relative humidity
- real(r8) :: p ! Pressure [Pa]
- real(r8) :: qv ! Grid-mean water vapor specific humidity [kg/kg]
- real(r8) :: landfrac ! Land fraction
- real(r8) :: snowh ! Snow depth (liquid water equivalent)
-
- real(r8) :: a ! Stratus fraction
- real(r8) :: Ga ! dU/da
-
- ! Local variables
- integer :: i ! Loop indexes
- real(r8) dV ! Width of triangular PDF
- real(r8) cldrh ! RH of stratus cloud
- real(r8) rhmin ! Critical RH
- real(r8) rhwght
-
- ! Statement functions
- logical land
- land(i) = nint(landfrac_in(i)) == 1
-
- ! ---------- !
- ! Parameters !
- ! ---------- !
-
- cldrh = 1.0_r8
-
- ! ---------------- !
- ! Main computation !
- ! ---------------- !
-
- a_out(:) = 0._r8
- Ga_out(:) = 0._r8
-
- do i = 1, ncol
-
- U = U_in(i)
- p = p_in(i)
- qv = qv_in(i)
- landfrac = landfrac_in(i)
- snowh = snowh_in(i)
-
- if( p .ge. premib ) then
-
- if( land(i) .and. (snowh.le.0.000001_r8) ) then
- rhmin = rhminl - rhminl_adj_land
- else
- rhmin = rhminl
- endif
-
- dV = cldrh - rhmin
-
- if( U .ge. 1._r8 ) then
- a = 1._r8
- Ga = 1.e10_r8
- elseif( U .gt. (cldrh-dV/6._r8) .and. U .lt. 1._r8 ) then
- a = 1._r8 - (-3._r8/sqrt(2._r8)*(U-cldrh)/dV)**(2._r8/3._r8)
- Ga = dV/sqrt(2._r8)*sqrt(1._r8-a)
- elseif( U .gt. (cldrh-dV) .and. U .le. (cldrh-dV/6._r8) ) then
- a = 4._r8*(cos((1._r8/3._r8)*(acos((3._r8/2._r8/sqrt(2._r8))* &
- (1._r8+(U-cldrh)/dV))-2._r8*3.141592_r8)))**2._r8
- Ga = dV/sqrt(2._r8)*(1._r8/sqrt(a)-sqrt(a))
- elseif( U .le. (cldrh-dV) ) then
- a = 0._r8
- Ga = 1.e10_r8
- endif
-
- if( freeze_dry ) then
- a = a *max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- Ga = Ga/max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- endif
-
- elseif( p .lt. premit ) then
-
- rhmin = rhminh
- dV = cldrh - rhmin
-
- if( U .ge. 1._r8 ) then
- a = 1._r8
- Ga = 1.e10_r8
- elseif( U .gt. (cldrh-dV/6._r8) .and. U .lt. 1._r8 ) then
- a = 1._r8 - (-3._r8/sqrt(2._r8)*(U-cldrh)/dV)**(2._r8/3._r8)
- Ga = dV/sqrt(2._r8)*sqrt(1._r8-a)
- elseif( U .gt. (cldrh-dV) .and. U .le. (cldrh-dV/6._r8) ) then
- a = 4._r8*(cos((1._r8/3._r8)*(acos((3._r8/2._r8/sqrt(2._r8))* &
- (1._r8+(U-cldrh)/dV))-2._r8*3.141592_r8)))**2._r8
- Ga = dV/sqrt(2._r8)*(1._r8/sqrt(a)-sqrt(a))
- elseif( U .le. (cldrh-dV) ) then
- a = 0._r8
- Ga = 1.e10_r8
- endif
-
- else
-
- rhwght = (premib-(max(p,premit)))/(premib-premit)
-
- ! if( land(i) .and. (snowh.le.0.000001_r8) ) then
- ! rhmin = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_r8-rhwght)
- ! else
- rhmin = rhminh*rhwght + rhminl*(1.0_r8-rhwght)
- ! endif
-
- dV = cldrh - rhmin
-
- if( U .ge. 1._r8 ) then
- a = 1._r8
- Ga = 1.e10_r8
- elseif( U .gt. (cldrh-dV/6._r8) .and. U .lt. 1._r8 ) then
- a = 1._r8 - (-3._r8/sqrt(2._r8)*(U-cldrh)/dV)**(2._r8/3._r8)
- Ga = dV/sqrt(2._r8)*sqrt(1._r8-a)
- elseif( U .gt. (cldrh-dV) .and. U .le. (cldrh-dV/6._r8) ) then
- a = 4._r8*(cos((1._r8/3._r8)*(acos((3._r8/2._r8/sqrt(2._r8))* &
- (1._r8+(U-cldrh)/dV))-2._r8*3.141592_r8)))**2._r8
- Ga = dV/sqrt(2._r8)*(1._r8/sqrt(a)-sqrt(a))
- elseif( U .le. (cldrh-dV) ) then
- a = 0._r8
- Ga = 1.e10_r8
- endif
-
- endif
-
- a_out(i) = a
- Ga_out(i) = Ga
-
- enddo
-
- return
- end subroutine astG_PDF
-
- ! ----------------- !
- ! End of subroutine !
- ! ----------------- !
-
- subroutine astG_RHU_single( U, p, qv, landfrac, snowh, a, Ga, orhmin )
-
- ! --------------------------------------------------------- !
- ! Compute 'stratus fraction(a)' and Gs=(dU/da) from the !
- ! CAM35 cloud fraction formula. !
- ! Below is valid only for CAMUW at 1.9x2.5 fv dynamics core !
- ! For the other cases, I should re-define 'rhminl,rhminh' & !
- ! 'premib,premit'. !
- ! Note that if U > 1, Ga = 1.e10 instead of Ga = 0, that is !
- ! G is discontinuous across U = 1. !
- ! --------------------------------------------------------- !
-
- implicit none
-
- real(r8), intent(in) :: U ! Relative humidity
- real(r8), intent(in) :: p ! Pressure [Pa]
- real(r8), intent(in) :: qv ! Grid-mean water vapor specific humidity [kg/kg]
- real(r8), intent(in) :: landfrac ! Land fraction
- real(r8), intent(in) :: snowh ! Snow depth (liquid water equivalent)
-
- real(r8), intent(out) :: a ! Stratus fraction
- real(r8), intent(out) :: Ga ! dU/da
- real(r8), optional, intent(out) :: orhmin ! Critical RH
-
- ! Local variables
- real(r8) rhmin ! Critical RH
- real(r8) rhdif ! Factor for stratus fraction
- real(r8) rhwght
-
- ! Statement functions
- logical land
- land = nint(landfrac) == 1
-
- ! ---------------- !
- ! Main computation !
- ! ---------------- !
-
- if( p .ge. premib ) then
-
- if( land .and. (snowh.le.0.000001_r8) ) then
- rhmin = rhminl - rhminl_adj_land
- else
- rhmin = rhminl
- endif
- rhdif = (U-rhmin)/(1.0_r8-rhmin)
- a = min(1._r8,(max(rhdif,0.0_r8))**2)
- if( (U.ge.1._r8) .or. (U.le.rhmin) ) then
- Ga = 1.e20_r8
- else
- Ga = 0.5_r8*(1._r8-rhmin)*((1._r8-rhmin)/(U-rhmin))
- endif
- if( freeze_dry ) then
- a = a*max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- Ga = Ga/max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- endif
-
- elseif( p .lt. premit ) then
-
- rhmin = rhminh
- rhdif = (U-rhmin)/(1.0_r8-rhmin)
- a = min(1._r8,(max(rhdif,0._r8))**2)
- if( (U.ge.1._r8) .or. (U.le.rhmin) ) then
- Ga = 1.e20_r8
- else
- Ga = 0.5_r8*(1._r8-rhmin)*((1._r8-rhmin)/(U-rhmin))
- endif
-
- else
-
- rhwght = (premib-(max(p,premit)))/(premib-premit)
-
- ! if( land .and. (snowh.le.0.000001_r8) ) then
- ! rhmin = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_r8-rhwght)
- ! else
- rhmin = rhminh*rhwght + rhminl*(1.0_r8-rhwght)
- ! endif
-
- rhdif = (U-rhmin)/(1.0_r8-rhmin)
- a = min(1._r8,(max(rhdif,0._r8))**2)
- if( (U.ge.1._r8) .or. (U.le.rhmin) ) then
- Ga = 1.e10_r8
- else
- Ga = 0.5_r8*(1._r8-rhmin)*((1._r8-rhmin)/(U-rhmin))
- endif
-
- endif
-
- if (present(orhmin)) orhmin = rhmin
-
- return
- end subroutine astG_RHU_single
-
- ! ----------------- !
- ! End of subroutine !
- ! ----------------- !
-
- subroutine astG_RHU( U_in, p_in, qv_in, landfrac_in, snowh_in, a_out, Ga_out, ncol )
-
- ! --------------------------------------------------------- !
- ! Compute 'stratus fraction(a)' and Gs=(dU/da) from the !
- ! CAM35 cloud fraction formula. !
- ! Below is valid only for CAMUW at 1.9x2.5 fv dynamics core !
- ! For the other cases, I should re-define 'rhminl,rhminh' & !
- ! 'premib,premit'. !
- ! Note that if U > 1, Ga = 1.e10 instead of Ga = 0, that is !
- ! G is discontinuous across U = 1. !
- ! --------------------------------------------------------- !
-
- implicit none
-
- integer, intent(in) :: ncol
- real(r8), intent(in) :: U_in(pcols) ! Relative humidity
- real(r8), intent(in) :: p_in(pcols) ! Pressure [Pa]
- real(r8), intent(in) :: qv_in(pcols) ! Grid-mean water vapor specific humidity [kg/kg]
- real(r8), intent(in) :: landfrac_in(pcols) ! Land fraction
- real(r8), intent(in) :: snowh_in(pcols) ! Snow depth (liquid water equivalent)
-
- real(r8), intent(out) :: a_out(pcols) ! Stratus fraction
- real(r8), intent(out) :: Ga_out(pcols) ! dU/da
-
- real(r8) :: U ! Relative humidity
- real(r8) :: p ! Pressure [Pa]
- real(r8) :: qv ! Grid-mean water vapor specific humidity [kg/kg]
- real(r8) :: landfrac ! Land fraction
- real(r8) :: snowh ! Snow depth (liquid water equivalent)
-
- real(r8) :: a ! Stratus fraction
- real(r8) :: Ga ! dU/da
-
- ! Local variables
- integer i
- real(r8) rhmin ! Critical RH
- real(r8) rhdif ! Factor for stratus fraction
- real(r8) rhwght
-
- ! Statement functions
- logical land
- land(i) = nint(landfrac_in(i)) == 1
-
- ! ---------------- !
- ! Main computation !
- ! ---------------- !
-
- a_out(:) = 0._r8
- Ga_out(:) = 0._r8
-
- do i = 1, ncol
-
- U = U_in(i)
- p = p_in(i)
- qv = qv_in(i)
- landfrac = landfrac_in(i)
- snowh = snowh_in(i)
-
- if( p .ge. premib ) then
-
- if( land(i) .and. (snowh.le.0.000001_r8) ) then
- rhmin = rhminl - rhminl_adj_land
- else
- rhmin = rhminl
- endif
- rhdif = (U-rhmin)/(1.0_r8-rhmin)
- a = min(1._r8,(max(rhdif,0.0_r8))**2)
- if( (U.ge.1._r8) .or. (U.le.rhmin) ) then
- Ga = 1.e20_r8
- else
- Ga = 0.5_r8*(1._r8-rhmin)*((1._r8-rhmin)/(U-rhmin))
- endif
- if( freeze_dry ) then
- a = a*max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- Ga = Ga/max(0.15_r8,min(1.0_r8,qv/0.0030_r8))
- endif
-
- elseif( p .lt. premit ) then
-
- rhmin = rhminh
- rhdif = (U-rhmin)/(1.0_r8-rhmin)
- a = min(1._r8,(max(rhdif,0._r8))**2)
- if( (U.ge.1._r8) .or. (U.le.rhmin) ) then
- Ga = 1.e20_r8
- else
- Ga = 0.5_r8*(1._r8-rhmin)*((1._r8-rhmin)/(U-rhmin))
- endif
-
- else
-
- rhwght = (premib-(max(p,premit)))/(premib-premit)
-
- ! if( land(i) .and. (snowh.le.0.000001_r8) ) then
- ! rhmin = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_r8-rhwght)
- ! else
- rhmin = rhminh*rhwght + rhminl*(1.0_r8-rhwght)
- ! endif
-
- rhdif = (U-rhmin)/(1.0_r8-rhmin)
- a = min(1._r8,(max(rhdif,0._r8))**2)
- if( (U.ge.1._r8) .or. (U.le.rhmin) ) then
- Ga = 1.e10_r8
- else
- Ga = 0.5_r8*(1._r8-rhmin)*((1._r8-rhmin)/(U-rhmin))
- endif
-
- endif
-
- a_out(i) = a
- Ga_out(i) = Ga
-
- enddo
-
- return
- end subroutine astG_RHU
-
- ! ----------------- !
- ! End of subroutine !
- ! ----------------- !
-
- subroutine aist_single( qv, T, p, qi, landfrac, snowh, aist )
-
- ! --------------------------------------------------------- !
- ! Compute non-physical ice stratus fraction !
- ! --------------------------------------------------------- !
-
- use physconst, only: rair
-
- implicit none
-
- real(r8), intent(in) :: qv ! Grid-mean water vapor[kg/kg]
- real(r8), intent(in) :: T ! Temperature
- real(r8), intent(in) :: p ! Pressure [Pa]
- real(r8), intent(in) :: qi ! Grid-mean ice water content [kg/kg]
- real(r8), intent(in) :: landfrac ! Land fraction
- real(r8), intent(in) :: snowh ! Snow depth (liquid water equivalent)
-
- real(r8), intent(out) :: aist ! Non-physical ice stratus fraction ( 0<= aist <= 1 )
-
- ! Local variables
- real(r8) rhmin ! Critical RH
- real(r8) rhwght
-
- real(r8) a,b,c,as,bs,cs ! Fit parameters
- real(r8) Kc ! Constant for ice cloud calc (wood & field)
- real(r8) ttmp ! Limited temperature
- real(r8) icicval ! Empirical IWC value [ kg/kg ]
- real(r8) rho ! Local air density
- real(r8) esl ! Liq sat vapor pressure
- real(r8) esi ! Ice sat vapor pressure
- real(r8) ncf,phi ! Wilson and Ballard parameters
- real(r8) es, qs
-
- real(r8) rhi ! grid box averaged relative humidity over ice
- real(r8) minice ! minimum grid box avg ice for having a 'cloud'
- real(r8) mincld ! minimum ice cloud fraction threshold
- real(r8) icimr ! in cloud ice mixing ratio
- ! real(r8) qist_min ! minimum in cloud ice mixing ratio
- ! real(r8) qist_max ! maximum in cloud ice mixing ratio
- real(r8) rhdif ! working variable for slingo scheme
-
-
- ! Statement functions
- logical land
- land = nint(landfrac) == 1
-
- ! --------- !
- ! Constants !
- ! --------- !
-
- ! Wang and Sassen IWC paramters ( Option.1 )
- a = 26.87_r8
- b = 0.569_r8
- c = 0.002892_r8
- ! Schiller parameters ( Option.2 )
- as = -68.4202_r8
- bs = 0.983917_r8
- cs = 2.81795_r8
- ! Wood and Field parameters ( Option.3 )
- Kc = 75._r8
- ! Wilson & Ballard closure ( Option.4. smaller = more ice clouds)
- ! Slingo modified (option 5)
- minice = 1.e-12_r8
- mincld = 1.e-4_r8
- ! qist_min = 1.e-7_r8
- ! qist_max = 5.e-3_r8
-
- ! ---------------- !
- ! Main computation !
- ! ---------------- !
-
- call qsat_water(T, p, es, qs)
- esl = svp_water(T)
- esi = svp_ice(T)
-
- if( iceopt.lt.3 ) then
- if( iceopt.eq.1 ) then
- ttmp = max(195._r8,min(T,253._r8)) - 273.16_r8
- icicval = a + b * ttmp + c * ttmp**2._r8
- rho = p/(rair*T)
- icicval = icicval * 1.e-6_r8 / rho
- else
- ttmp = max(190._r8,min(T,273.16_r8))
- icicval = 10._r8 **(as * bs**ttmp + cs)
- icicval = icicval * 1.e-6_r8 * 18._r8 / 28.97_r8
- endif
- aist = max(0._r8,min(qi/icicval,1._r8))
- elseif( iceopt.eq.3 ) then
- aist = 1._r8 - exp(-Kc*qi/(qs*(esi/esl)))
- aist = max(0._r8,min(aist,1._r8))
- elseif( iceopt.eq.4) then
- if( p .ge. premib ) then
- if( land .and. (snowh.le.0.000001_r8) ) then
- rhmin = rhminl - rhminl_adj_land
- else
- rhmin = rhminl
- endif
- elseif( p .lt. premit ) then
- rhmin = rhminh
- else
- rhwght = (premib-(max(p,premit)))/(premib-premit)
- ! if( land .and. (snowh.le.0.000001_r8) ) then
- ! rhmin = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_r8-rhwght)
- ! else
- rhmin = rhminh*rhwght + rhminl*(1.0_r8-rhwght)
- ! endif
- endif
- ncf = qi/((1._r8 - icecrit)*qs)
- if( ncf.le.0._r8 ) then
- aist = 0._r8
- elseif( ncf.gt.0._r8 .and. ncf.le.1._r8/6._r8 ) then
- aist = 0.5_r8*(6._r8 * ncf)**(2._r8/3._r8)
- elseif( ncf.gt.1._r8/6._r8 .and. ncf.lt.1._r8 ) then
- phi = (acos(3._r8*(1._r8-ncf)/2._r8**(3._r8/2._r8))+4._r8*3.1415927_r8)/3._r8
- aist = (1._r8 - 4._r8 * cos(phi) * cos(phi))
- else
- aist = 1._r8
- endif
- aist = max(0._r8,min(aist,1._r8))
- elseif (iceopt.eq.5) then
-! set rh ice cloud fraction
- rhi= (qv+qi)/qs * (esl/esi)
- rhdif= (rhi-rhmini) / (rhmaxi - rhmini)
- aist = min(1.0_r8, max(rhdif,0._r8)**2)
-
-! limiter to remove empty cloud and ice with no cloud
-! and set icecld fraction to mincld if ice exists
-
- if (qi.lt.minice) then
- aist=0._r8
- else
- aist=max(mincld,aist)
- endif
-
-! enforce limits on icimr
- if (qi.ge.minice) then
- icimr=qi/aist
-
-!minimum
- if (icimr.lt.qist_min) then
- aist = max(0._r8,min(1._r8,qi/qist_min))
- endif
-!maximum
- if (icimr.gt.qist_max) then
- aist = max(0._r8,min(1._r8,qi/qist_max))
- endif
-
- endif
- endif
-
- ! 0.999_r8 is added to prevent infinite 'ql_st' at the end of instratus_condensate
- ! computed after updating 'qi_st'.
-
- aist = max(0._r8,min(aist,0.999_r8))
-
- return
- end subroutine aist_single
-
- ! ----------------- !
- ! End of subroutine !
- ! ----------------- !
-
- subroutine aist_vector( qv_in, T_in, p_in, qi_in, landfrac_in, snowh_in, aist_out, ncol )
-
- ! --------------------------------------------------------- !
- ! Compute non-physical ice stratus fraction !
- ! --------------------------------------------------------- !
-
- use physconst, only: rair
-
- implicit none
-
- integer, intent(in) :: ncol
- real(r8), intent(in) :: qv_in(pcols) ! Grid-mean water vapor[kg/kg]
- real(r8), intent(in) :: T_in(pcols) ! Temperature
- real(r8), intent(in) :: p_in(pcols) ! Pressure [Pa]
- real(r8), intent(in) :: qi_in(pcols) ! Grid-mean ice water content [kg/kg]
- real(r8), intent(in) :: landfrac_in(pcols) ! Land fraction
- real(r8), intent(in) :: snowh_in(pcols) ! Snow depth (liquid water equivalent)
- real(r8), intent(out) :: aist_out(pcols) ! Non-physical ice stratus fraction ( 0<= aist <= 1 )
-
- ! Local variables
-
- real(r8) qv ! Grid-mean water vapor[kg/kg]
- real(r8) T ! Temperature
- real(r8) p ! Pressure [Pa]
- real(r8) qi ! Grid-mean ice water content [kg/kg]
- real(r8) landfrac ! Land fraction
- real(r8) snowh ! Snow depth (liquid water equivalent)
- real(r8) aist ! Non-physical ice stratus fraction ( 0<= aist <= 1 )
-
- real(r8) rhmin ! Critical RH
- real(r8) rhwght
-
- real(r8) a,b,c,as,bs,cs ! Fit parameters
- real(r8) Kc ! Constant for ice cloud calc (wood & field)
- real(r8) ttmp ! Limited temperature
- real(r8) icicval ! Empirical IWC value [ kg/kg ]
- real(r8) rho ! Local air density
- real(r8) esl ! Liq sat vapor pressure
- real(r8) esi ! Ice sat vapor pressure
- real(r8) ncf,phi ! Wilson and Ballard parameters
- real(r8) qs
- real(r8) esat_in(pcols)
- real(r8) qsat_in(pcols)
-
- real(r8) rhi ! grid box averaged relative humidity over ice
- real(r8) minice ! minimum grid box avg ice for having a 'cloud'
- real(r8) mincld ! minimum ice cloud fraction threshold
- real(r8) icimr ! in cloud ice mixing ratio
- ! real(r8) qist_min ! minimum in cloud ice mixing ratio
- ! real(r8) qist_max ! maximum in cloud ice mixing ratio
- real(r8) rhdif ! working variable for slingo scheme
-
- integer i
-
-
- ! Statement functions
- logical land
- land(i) = nint(landfrac_in(i)) == 1
-
- ! --------- !
- ! Constants !
- ! --------- !
-
- ! Wang and Sassen IWC paramters ( Option.1 )
- a = 26.87_r8
- b = 0.569_r8
- c = 0.002892_r8
- ! Schiller parameters ( Option.2 )
- as = -68.4202_r8
- bs = 0.983917_r8
- cs = 2.81795_r8
- ! Wood and Field parameters ( Option.3 )
- Kc = 75._r8
- ! Wilson & Ballard closure ( Option.4. smaller = more ice clouds)
- ! Slingo modified (option 5)
- minice = 1.e-12_r8
- mincld = 1.e-4_r8
- ! qist_min = 1.e-7_r8
- ! qist_max = 5.e-3_r8
-
- ! ---------------- !
- ! Main computation !
- ! ---------------- !
-
- aist_out(:) = 0._r8
- esat_in(:) = 0._r8
- qsat_in(:) = 0._r8
-
- call qsat_water(T_in(1:ncol), p_in(1:ncol), &
- esat_in(1:ncol), qsat_in(1:ncol))
-
- do i = 1, ncol
-
- landfrac = landfrac_in(i)
- snowh = snowh_in(i)
- T = T_in(i)
- qv = qv_in(i)
- p = p_in(i)
- qi = qi_in(i)
- qs = qsat_in(i)
- esl = svp_water(T)
- esi = svp_ice(T)
-
- if( iceopt.lt.3 ) then
- if( iceopt.eq.1 ) then
- ttmp = max(195._r8,min(T,253._r8)) - 273.16_r8
- icicval = a + b * ttmp + c * ttmp**2._r8
- rho = p/(rair*T)
- icicval = icicval * 1.e-6_r8 / rho
- else
- ttmp = max(190._r8,min(T,273.16_r8))
- icicval = 10._r8 **(as * bs**ttmp + cs)
- icicval = icicval * 1.e-6_r8 * 18._r8 / 28.97_r8
- endif
- aist = max(0._r8,min(qi/icicval,1._r8))
- elseif( iceopt.eq.3 ) then
- aist = 1._r8 - exp(-Kc*qi/(qs*(esi/esl)))
- aist = max(0._r8,min(aist,1._r8))
- elseif( iceopt.eq.4) then
- if( p .ge. premib ) then
- if( land(i) .and. (snowh.le.0.000001_r8) ) then
- rhmin = rhminl - rhminl_adj_land
- else
- rhmin = rhminl
- endif
- elseif( p .lt. premit ) then
- rhmin = rhminh
- else
- rhwght = (premib-(max(p,premit)))/(premib-premit)
- ! if( land(i) .and. (snowh.le.0.000001_r8) ) then
- ! rhmin = rhminh*rhwght + (rhminl - rhminl_adj_land)*(1.0_r8-rhwght)
- ! else
- rhmin = rhminh*rhwght + rhminl*(1.0_r8-rhwght)
- ! endif
- endif
- ncf = qi/((1._r8 - icecrit)*qs)
- if( ncf.le.0._r8 ) then
- aist = 0._r8
- elseif( ncf.gt.0._r8 .and. ncf.le.1._r8/6._r8 ) then
- aist = 0.5_r8*(6._r8 * ncf)**(2._r8/3._r8)
- elseif( ncf.gt.1._r8/6._r8 .and. ncf.lt.1._r8 ) then
- phi = (acos(3._r8*(1._r8-ncf)/2._r8**(3._r8/2._r8))+4._r8*3.1415927_r8)/3._r8
- aist = (1._r8 - 4._r8 * cos(phi) * cos(phi))
- else
- aist = 1._r8
- endif
- aist = max(0._r8,min(aist,1._r8))
- elseif (iceopt.eq.5) then
-! set rh ice cloud fraction
- rhi= (qv+qi)/qs * (esl/esi)
- rhdif= (rhi-rhmini) / (rhmaxi - rhmini)
- aist = min(1.0_r8, max(rhdif,0._r8)**2)
-
-! limiter to remove empty cloud and ice with no cloud
-! and set icecld fraction to mincld if ice exists
-
- if (qi.lt.minice) then
- aist=0._r8
- else
- aist=max(mincld,aist)
- endif
-
-! enforce limits on icimr
- if (qi.ge.minice) then
- icimr=qi/aist
-
-!minimum
- if (icimr.lt.qist_min) then
- aist = max(0._r8,min(1._r8,qi/qist_min))
- endif
-!maximum
- if (icimr.gt.qist_max) then
- aist = max(0._r8,min(1._r8,qi/qist_max))
- endif
-
- endif
- endif
-
- ! 0.999_r8 is added to prevent infinite 'ql_st' at the end of instratus_condensate
- ! computed after updating 'qi_st'.
-
- aist = max(0._r8,min(aist,0.999_r8))
-
- aist_out(i) = aist
-
- enddo
-
- return
- end subroutine aist_vector
-
! ----------------- !
! End of subroutine !
! ----------------- !
diff --git a/models/atm/cam/src/physics/cam/clubb_intr.F90 b/models/atm/cam/src/physics/cam/clubb_intr.F90
index 9d70d3037902..2f5365cbe3ed 100644
--- a/models/atm/cam/src/physics/cam/clubb_intr.F90
+++ b/models/atm/cam/src/physics/cam/clubb_intr.F90
@@ -19,10 +19,11 @@ module clubb_intr
use shr_kind_mod, only: r8=>shr_kind_r8
use ppgrid, only: pver, pverp
use phys_control, only: phys_getopts
- use physconst, only: rair, cpair, gravit, latvap, latice, zvir, rh2o, karman, tms_orocnst, tms_z0fac
+ use physconst, only: rair, cpair, gravit, latvap, latice, zvir, rh2o, karman, &
+ tms_orocnst, tms_z0fac
use cam_logfile, only: iulog
use spmd_utils, only: masterproc
- use constituents, only: pcnst
+ use constituents, only: pcnst, cnst_add
use pbl_utils, only: calc_ustar, calc_obklen
use mpishorthand
@@ -41,39 +42,60 @@ module clubb_intr
stats_init_clubb, &
#endif
stats_end_timestep_clubb, &
- clubb_surface
+ clubb_surface, &
+ clubb_readnl, &
+ clubb_init_cnst, &
+ clubb_implements_cnst
-#ifdef CLUBB_SGS
+#ifdef CLUBB_SGS
! Both of these utilize CLUBB specific variables in their interface
private :: stats_zero, stats_avg
#endif
+ logical, public :: do_cldcool
! ------------ !
! Private data !
! ------------ !
integer, parameter :: &
- grid_type = 3, & ! The 2 option specifies stretched thermodynamic levels
- hydromet_dim = 0 ! The hydromet array in SAM-CLUBB is currently 0 elements
+ grid_type = 3, & ! The 2 option specifies stretched thermodynamic levels
+ hydromet_dim = 0 ! The hydromet array in SAM-CLUBB is currently 0 elements
real(r8), dimension(0) :: &
sclr_tol = 1.e-8_r8 ! Total water in kg/kg
character(len=6), parameter :: &
- saturation_equation = "flatau" ! Flatau polynomial approximation for SVP
+ saturation_equation = "flatau" ! Flatau polynomial approximation for SVP
real(r8), parameter :: &
- theta0 = 300._r8, & ! Reference temperature [K]
- ts_nudge = 86400._r8, & ! Time scale for u/v nudging (not used) [s]
+ theta0 = 300._r8, & ! Reference temperature [K]
+ ts_nudge = 86400._r8, & ! Time scale for u/v nudging (not used) [s]
p0_clubb = 100000._r8
real(r8), parameter :: &
- host_dx = 100000._r8, & ! Host model deltax [m]
- host_dy = 100000._r8 ! Host model deltay [m]
+ host_dx = 100000._r8, & ! Host model deltax [m]
+ host_dy = 100000._r8 ! Host model deltay [m]
integer, parameter :: &
- sclr_dim = 0 ! Higher-order scalars, set to zero
+ sclr_dim = 0 ! Higher-order scalars, set to zero
+
+ real(r8), parameter :: &
+ wp3_const = 1._r8 ! Constant to add to wp3 when moments are advected
+
+ real(r8), parameter :: &
+ wpthlp_const = 10.0_r8 ! Constant to add to wpthlp when moments are advected
+
+ real(r8), parameter :: &
+ wprtp_const = 0.01_r8 ! Constant to add to wprtp when moments are advected
+
+ real(r8), parameter :: &
+ rtpthlp_const = 0.01_r8 ! Constant to add to rtpthlp when moments are advected
+
+ real(r8), parameter :: unset_r8 = huge(1.0_r8)
+
+ real(r8) :: clubb_timestep = unset_r8 ! Default CLUBB timestep, unless overwriten by namelist
+ real(r8) :: clubb_rnevap_effic = unset_r8
! Constant parameters
logical, parameter, private :: &
@@ -83,52 +105,83 @@ module clubb_intr
logical :: do_tms
logical :: lq(pcnst)
+ logical :: lq2(pcnst)
logical :: prog_modal_aero
-
+ logical :: do_rainturb
+ logical :: do_expldiff
+ logical :: clubb_do_adv
+ logical :: clubb_do_deep
+ logical :: micro_do_icesupersat
+ logical :: history_budget
+
+ integer :: history_budget_histfile_num
integer :: edsclr_dim ! Number of scalars to transport in CLUBB
+ integer :: offset
! define physics buffer indicies here
integer :: &
- wp2_idx, & ! vertical velocity variances
- wp3_idx, & ! third moment of vertical velocity
- wpthlp_idx, & ! turbulent flux of thetal
- wprtp_idx, & ! turbulent flux of total water
- rtpthlp_idx, & ! covariance of thetal and rt
- rtp2_idx, & ! variance of total water
- thlp2_idx, & ! variance of thetal
- up2_idx, & ! variance of east-west wind
- vp2_idx, & ! variance of north-south wind
- upwp_idx, & ! east-west momentum flux
- vpwp_idx, & ! north-south momentum flux
- thlm_idx, & ! mean thetal
- rtm_idx, & ! mean total water mixing ratio
- um_idx, & ! mean of east-west wind
- vm_idx, & ! mean of north-south wind
- cld_idx, & ! Cloud fraction
- concld_idx, & ! Convective cloud fraction
- ast_idx, & ! Stratiform cloud fraction
- alst_idx, & ! Liquid stratiform cloud fraction
- aist_idx, & ! Ice stratiform cloud fraction
- qlst_idx, & ! Physical in-cloud LWC
- qist_idx, & ! Physical in-cloud IWC
- dp_frac_idx, & ! deep convection cloud fraction
- sh_frac_idx, & ! shallow convection cloud fraction
- rel_idx, & ! Rel
- kvh_idx, & ! CLUBB eddy diffusivity on thermo levels
- kvm_idx, & ! CLUBB eddy diffusivity on mom levels
- pblh_idx, & ! PBL pbuf
- icwmrdp_idx, & ! In cloud mixing ratio for deep convection
- tke_idx, & ! turbulent kinetic energy
- tpert_idx, & ! temperature perturbation from PBL
- fice_idx, & ! fice_idx index in physics buffer
- cmeliq_idx, & ! cmeliq_idx index in physics buffer
- relvar_idx, & ! relative cloud water variance
- accre_enhan_idx ! optional accretion enhancement factor for MG
+ wp2_idx, & ! vertical velocity variances
+ wp3_idx, & ! third moment of vertical velocity
+ wpthlp_idx, & ! turbulent flux of thetal
+ wprtp_idx, & ! turbulent flux of total water
+ rtpthlp_idx, & ! covariance of thetal and rt
+ rtp2_idx, & ! variance of total water
+ thlp2_idx, & ! variance of thetal
+ up2_idx, & ! variance of east-west wind
+ vp2_idx, & ! variance of north-south wind
+ upwp_idx, & ! east-west momentum flux
+ vpwp_idx, & ! north-south momentum flux
+ thlm_idx, & ! mean thetal
+ rtm_idx, & ! mean total water mixing ratio
+ um_idx, & ! mean of east-west wind
+ vm_idx, & ! mean of north-south wind
+ cld_idx, & ! Cloud fraction
+ concld_idx, & ! Convective cloud fraction
+ ast_idx, & ! Stratiform cloud fraction
+ alst_idx, & ! Liquid stratiform cloud fraction
+ aist_idx, & ! Ice stratiform cloud fraction
+ qlst_idx, & ! Physical in-cloud LWC
+ qist_idx, & ! Physical in-cloud IWC
+ dp_frac_idx, & ! deep convection cloud fraction
+ sh_frac_idx, & ! shallow convection cloud fraction
+ rel_idx, & ! Rel
+ kvh_idx, & ! CLUBB eddy diffusivity on thermo levels
+ kvm_idx, & ! CLUBB eddy diffusivity on mom levels
+ pblh_idx, & ! PBL pbuf
+ icwmrdp_idx, & ! In cloud mixing ratio for deep convection
+ tke_idx, & ! turbulent kinetic energy
+ tpert_idx, & ! temperature perturbation from PBL
+ fice_idx, & ! fice_idx index in physics buffer
+ cmeliq_idx, & ! cmeliq_idx index in physics buffer
+ relvar_idx, & ! relative cloud water variance
+ accre_enhan_idx, & ! optional accretion enhancement factor for MG
+ naai_idx, & ! ice number concentration
+ prer_evap_idx, & ! rain evaporation rate
+ qrl_idx, & ! longwave cooling rate
+ radf_idx
+
+ integer, public :: &
+ ixthlp2 = 0, &
+ ixwpthlp = 0, &
+ ixwprtp = 0, &
+ ixwp2 = 0, &
+ ixwp3 = 0, &
+ ixrtpthlp = 0, &
+ ixrtp2 = 0, &
+ ixup2 = 0, &
+ ixvp2 = 0
+
+ integer :: cmfmc_sh_idx = 0
! Output arrays for CLUBB statistics
real(r8), allocatable, dimension(:,:,:) :: out_zt, out_zm, out_radzt, out_radzm, out_sfc
character(len=16) :: eddy_scheme ! Default set in phys_control.F90
+ character(len=16) :: deep_scheme ! Default set in phys_control.F90
+
+ integer, parameter :: ncnst=9
+ character(len=8) :: cnst_names(ncnst)
+ logical :: do_cnst=.false.
contains
@@ -153,8 +206,29 @@ subroutine clubb_register_cam( )
use physics_buffer, only: pbuf_add_field, dtype_r8, dyn_time_lvls
use ppgrid, only: pver, pverp, pcols
- call phys_getopts( eddy_scheme_out = eddy_scheme, &
- do_tms_out = do_tms)
+ call phys_getopts( eddy_scheme_out = eddy_scheme, &
+ deep_scheme_out = deep_scheme, &
+ do_tms_out = do_tms, &
+ history_budget_out = history_budget, &
+ history_budget_histfile_num_out = history_budget_histfile_num, &
+ micro_do_icesupersat_out = micro_do_icesupersat)
+
+ if (clubb_do_adv) then
+ cnst_names =(/'THLP2 ','RTP2 ','RTPTHLP','WPTHLP ','WPRTP ','WP2 ','WP3 ','UP2 ','VP2 '/)
+ do_cnst=.true.
+ ! If CLUBB moments are advected, do not output them automatically which is typically done. Some moments
+ ! need a constant added to them before they are advected, thus this would corrupt the output.
+ ! Users should refer to the "XXXX_CLUBB" (THLP2_CLUBB for instance) output variables for these moments
+ call cnst_add(trim(cnst_names(1)),0._r8,0._r8,0._r8,ixthlp2,longname='second moment vertical velocity',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(2)),0._r8,0._r8,0._r8,ixrtp2,longname='second moment rtp',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(3)),0._r8,0._r8,-999999._r8,ixrtpthlp,longname='covariance rtp thlp',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(4)),0._r8,0._r8,-999999._r8,ixwpthlp,longname='CLUBB heat flux',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(5)),0._r8,0._r8,-999999._r8,ixwprtp,longname='CLUBB moisture flux',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(6)),0._r8,0._r8,0._r8,ixwp2,longname='CLUBB wp2',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(7)),0._r8,0._r8,-999999._r8,ixwp3,longname='CLUBB 3rd moment vert velocity',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(8)),0._r8,0._r8,0._r8,ixup2,longname='CLUBB 2nd moment u wind',cam_outfld=.false.)
+ call cnst_add(trim(cnst_names(9)),0._r8,0._r8,0._r8,ixvp2,longname='CLUBB 2nd moment v wind',cam_outfld=.false.)
+ end if
! put pbuf_add calls here (see macrop_driver.F90 for sample) use indicies defined at top
call pbuf_add_field('pblh', 'global', dtype_r8, (/pcols/), pblh_idx)
@@ -169,18 +243,20 @@ subroutine clubb_register_cam( )
call pbuf_add_field('QLST', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), qlst_idx)
call pbuf_add_field('CONCLD', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), concld_idx)
call pbuf_add_field('CLD', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cld_idx)
- call pbuf_add_field('FICE', 'physpkg',dtype_r8, (/pcols,pver/), fice_idx)
+ call pbuf_add_field('FICE', 'physpkg',dtype_r8, (/pcols,pver/), fice_idx)
+ call pbuf_add_field('RAD_CLUBB', 'global', dtype_r8, (/pcols,pver/), radf_idx)
call pbuf_add_field('CMELIQ', 'physpkg',dtype_r8, (/pcols,pver/), cmeliq_idx)
- call pbuf_add_field('WP2', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wp2_idx)
- call pbuf_add_field('WP3', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wp3_idx)
- call pbuf_add_field('WPTHLP', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wpthlp_idx)
- call pbuf_add_field('WPRTP', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wprtp_idx)
- call pbuf_add_field('RTPTHLP', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), rtpthlp_idx)
- call pbuf_add_field('RTP2', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), rtp2_idx)
- call pbuf_add_field('THLP2', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), thlp2_idx)
- call pbuf_add_field('UP2', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), up2_idx)
- call pbuf_add_field('VP2', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), vp2_idx)
+ call pbuf_add_field('WP2_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wp2_idx)
+ call pbuf_add_field('WP3_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wp3_idx)
+ call pbuf_add_field('WPTHLP_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wpthlp_idx)
+ call pbuf_add_field('WPRTP_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), wprtp_idx)
+ call pbuf_add_field('RTPTHLP_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), rtpthlp_idx)
+ call pbuf_add_field('RTP2_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), rtp2_idx)
+ call pbuf_add_field('THLP2_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), thlp2_idx)
+ call pbuf_add_field('UP2_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), up2_idx)
+ call pbuf_add_field('VP2_nadv', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), vp2_idx)
+
call pbuf_add_field('UPWP', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), upwp_idx)
call pbuf_add_field('VPWP', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), vpwp_idx)
call pbuf_add_field('THLM', 'global', dtype_r8, (/pcols,pverp,dyn_time_lvls/), thlm_idx)
@@ -191,7 +267,163 @@ subroutine clubb_register_cam( )
#endif
end subroutine clubb_register_cam
+ ! =============================================================================== !
+ ! !
+ ! =============================================================================== !
+
+function clubb_implements_cnst(name)
+
+ !----------------------------------------------------------------------------- !
+ ! !
+ ! Return true if specified constituent is implemented by this package !
+ ! !
+ !----------------------------------------------------------------------------- !
+
+ character(len=*), intent(in) :: name ! constituent name
+ logical :: clubb_implements_cnst ! return value
+
+ !-----------------------------------------------------------------------
+
+ clubb_implements_cnst = (do_cnst .and. any(name == cnst_names))
+
+end function clubb_implements_cnst
+
+
+ ! =============================================================================== !
+ ! !
+ ! =============================================================================== !
+
+subroutine clubb_init_cnst(name, q, gcid)
+
+#ifdef CLUBB_SGS
+ use constants_clubb, only: w_tol_sqd, rt_tol, thl_tol
+#endif
+
+ !----------------------------------------------------------------------- !
+ ! !
+ ! Initialize the state if clubb_do_adv !
+ ! !
+ !----------------------------------------------------------------------- !
+
+ character(len=*), intent(in) :: name ! constituent name
+ real(r8), intent(out) :: q(:,:) ! mass mixing ratio (gcol, plev)
+ integer, intent(in) :: gcid(:) ! global column id
+ !-----------------------------------------------------------------------
+
+#ifdef CLUBB_SGS
+ if (clubb_do_adv) then
+ if (trim(name) == trim(cnst_names(1))) q = thl_tol**2
+ if (trim(name) == trim(cnst_names(2))) q = rt_tol**2
+ if (trim(name) == trim(cnst_names(3))) q = 0.0_r8
+ if (trim(name) == trim(cnst_names(4))) q = 0.0_r8
+ if (trim(name) == trim(cnst_names(5))) q = 0.0_r8
+ if (trim(name) == trim(cnst_names(6))) q = w_tol_sqd
+ if (trim(name) == trim(cnst_names(7))) q = 0.0_r8
+ if (trim(name) == trim(cnst_names(8))) q = w_tol_sqd
+ if (trim(name) == trim(cnst_names(9))) q = w_tol_sqd
+ end if
+#endif
+
+end subroutine clubb_init_cnst
+
+ ! =============================================================================== !
+ ! !
+ ! =============================================================================== !
+
+ subroutine clubb_readnl(nlfile)
+
+#ifdef CLUBB_SGS
+ use namelist_utils, only: find_group_name
+ use units, only: getunit, freeunit
+ use cam_abortutils, only: endrun
+ use stats_variables, only: l_stats, l_output_rad_files
+ use mpishorthand
+ use model_flags, only: l_diffuse_rtm_and_thlm, l_stability_correct_Kh_N2_zm
+#endif
+
+ character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
+
+#ifdef CLUBB_SGS
+ logical :: clubb_history, clubb_rad_history, clubb_cloudtop_cooling, clubb_rainevap_turb, &
+ clubb_stabcorrect, clubb_expldiff ! Stats enabled (T/F)
+
+ integer :: iunit, read_status
+
+ namelist /clubb_his_nl/ clubb_history, clubb_rad_history
+ namelist /clubbpbl_diff_nl/ clubb_cloudtop_cooling, clubb_rainevap_turb, clubb_expldiff, &
+ clubb_do_adv, clubb_do_deep, clubb_timestep, clubb_stabcorrect, &
+ clubb_rnevap_effic
+
+ !----- Begin Code -----
+
+ ! Determine if we want clubb_history to be output
+ clubb_history = .false. ! Initialize to false
+ l_stats = .false. ! Initialize to false
+ l_output_rad_files = .false. ! Initialize to false
+ do_cldcool = .false. ! Initialize to false
+ do_rainturb = .false. ! Initialize to false
+ do_expldiff = .false. ! Initialize to false
+
+
+ ! Read namelist to determine if CLUBB history should be called
+ if (masterproc) then
+ iunit = getunit()
+ open( iunit, file=trim(nlfile), status='old' )
+
+ call find_group_name(iunit, 'clubb_his_nl', status=read_status)
+ if (read_status == 0) then
+ read(unit=iunit, nml=clubb_his_nl, iostat=read_status)
+ if (read_status /= 0) then
+ call endrun('clubb_readnl: error reading namelist')
+ end if
+ end if
+
+ call find_group_name(iunit, 'clubbpbl_diff_nl', status=read_status)
+ if (read_status == 0) then
+ read(unit=iunit, nml=clubbpbl_diff_nl, iostat=read_status)
+ if (read_status /= 0) then
+ call endrun('clubb_readnl: error reading namelist')
+ end if
+ end if
+
+ close(unit=iunit)
+ call freeunit(iunit)
+ end if
+
+#ifdef SPMD
+! Broadcast namelist variables
+ call mpibcast(clubb_history, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_rad_history, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_cloudtop_cooling, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_rainevap_turb, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_expldiff, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_do_adv, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_do_deep, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_timestep, 1, mpir8, 0, mpicom)
+ call mpibcast(clubb_stabcorrect, 1, mpilog, 0, mpicom)
+ call mpibcast(clubb_rnevap_effic, 1, mpir8, 0, mpicom)
+#endif
+
+ ! Overwrite defaults if they are true
+ if (clubb_history) l_stats = .true.
+ if (clubb_rad_history) l_output_rad_files = .true.
+ if (clubb_cloudtop_cooling) do_cldcool = .true.
+ if (clubb_rainevap_turb) do_rainturb = .true.
+ if (clubb_expldiff) do_expldiff = .true.
+
+ if (clubb_stabcorrect .and. clubb_expldiff) then
+ call endrun('clubb_readnl: clubb_stabcorrect and clubb_expldiff may not both be set to true at the same time')
+ end if
+
+ if (clubb_stabcorrect) then
+ l_diffuse_rtm_and_thlm = .true. ! CLUBB flag set to true
+ l_stability_correct_Kh_N2_zm = .true. ! CLUBB flag set to true
+ endif
+
+#endif
+ end subroutine clubb_readnl
+
! =============================================================================== !
! !
! =============================================================================== !
@@ -212,33 +444,31 @@ subroutine clubb_ini_cam(pbuf2d)
#ifdef CLUBB_SGS
! From CAM libraries
- use physics_types, only: physics_state, physics_ptend
- use cam_history, only: addfld, add_default, phys_decomp
- use ppgrid, only: pver, pverp, pcols
+ use physics_types, only: physics_state, physics_ptend
+ use cam_history, only: addfld, add_default, phys_decomp
+ use ppgrid, only: pver, pverp, pcols
use ref_pres, only: pref_mid
use hb_diff, only: init_hb_diff
use trb_mtn_stress, only: init_tms
use rad_constituents, only: rad_cnst_get_info, rad_cnst_get_mode_num_idx, rad_cnst_get_mam_mmr_idx
! From the CLUBB libraries
- use clubb_core, only: setup_clubb_core
- use clubb_precision, only: time_precision
- use error_code, only: set_clubb_debug_level ! Subroutines
- use parameter_indices, only: nparams ! Constant
- use parameters_tunable, only: read_parameters ! Subroutine
- use stats_variables, only: l_stats, l_stats_samp, l_grads, l_output_rad_files, &
- zt, zm, sfc, rad_zt, rad_zm
- use namelist_utils, only: find_group_name
- use units, only: getunit, freeunit
- use cam_abortutils, only: endrun
- use error_messages, only: handle_errmsg
- use time_manager, only: is_first_step
- use constants_clubb, only: em_min, w_tol_sqd, rt_tol, thl_tol
+ use advance_clubb_core_module, only: setup_clubb_core
+ use clubb_precision, only: time_precision
+ use error_code, only: set_clubb_debug_level ! Subroutines
+ use parameter_indices, only: nparams ! Constant
+ use parameters_tunable, only: read_parameters ! Subroutine
+ use stats_variables, only: l_stats, l_stats_samp, l_grads, l_output_rad_files, &
+ stats_zt, stats_zm, stats_sfc, stats_rad_zt, stats_rad_zm
+ use units, only: getunit, freeunit
+ use error_messages, only: handle_errmsg
+ use time_manager, only: is_first_step
+ use constants_clubb, only: w_tol_sqd, rt_tol, thl_tol
! These are only needed if we're using a passive scalar
- use array_index, only: iisclr_rt, iisclr_thl, iisclr_CO2, & ! [kg/kg]/[K]/[1e6 mol/mol]
- iiedsclr_rt, iiedsclr_thl, iiedsclr_CO2 ! " "
+ use array_index, only: iisclr_rt, iisclr_thl, iisclr_CO2, & ! [kg/kg]/[K]/[1e6 mol/mol]
+ iiedsclr_rt, iiedsclr_thl, iiedsclr_CO2 ! " "
use constituents, only: cnst_get_ind
use phys_control, only: phys_getopts
@@ -255,25 +485,25 @@ subroutine clubb_ini_cam(pbuf2d)
real(8), dimension(nparams) :: clubb_params ! These adjustable CLUBB parameters (C1, C2 ...)
- logical :: clubb_history, clubb_rad_history ! Stats enabled (T/F)
+ logical :: clubb_history, clubb_rad_history, clubb_cloudtop_cooling, clubb_rainevap_turb, clubb_expldiff ! Stats enabled (T/F)
+
+ ! The similar name to clubb_history is unfortunate...
+ logical :: history_amwg, history_clubb
character(len=128) :: errstring ! error status for CLUBB init
- integer :: err_code, iunit ! Code for when CLUBB fails
+ integer :: err_code, iunit ! Code for when CLUBB fails
integer :: i, j, k, l ! Indices
- integer :: read_status ! Length of a string
- integer :: ntop_eddy ! Top interface level to which eddy vertical diffusion is applied ( = 1 )
- integer :: nbot_eddy ! Bottom interface level to which eddy vertical diffusion is applied ( = pver )
+ integer :: read_status ! Length of a string
+ integer :: ntop_eddy ! Top interface level to which eddy vertical diffusion is applied ( = 1 )
+ integer :: nbot_eddy ! Bottom interface level to which eddy vertical diffusion is applied ( = pver )
integer :: nmodes, nspec, pmam_ncnst, m
integer :: ixnumliq
integer :: lptr
-
real(r8) :: zt_g(pverp) ! Height dummy array
real(r8) :: zi_g(pverp) ! Height dummy array
-
- namelist /clubb_his_nl/ clubb_history, clubb_rad_history
!----- Begin Code -----
@@ -284,39 +514,40 @@ subroutine clubb_ini_cam(pbuf2d)
! off of pcnst (the total consituents)
! ----------------------------------------------------------------- !
- call phys_getopts(prog_modal_aero_out=prog_modal_aero)
+ call phys_getopts(prog_modal_aero_out=prog_modal_aero, &
+ history_amwg_out=history_amwg, &
+ history_clubb_out=history_clubb)
- ! Select variables to apply tendencies back to CAM
+ ! Select variables to apply tendencies back to CAM
- ! Initialize all consituents to true to start
- lq(1:pcnst) = .true.
- edsclr_dim = pcnst
-
- if (prog_modal_aero) then
- ! Turn off modal aerosols and decrement edsclr_dim accordingly
- call rad_cnst_get_info(0, nmodes=nmodes)
-
- do m = 1, nmodes
- call rad_cnst_get_mode_num_idx(m, lptr)
- lq(lptr)=.false.
- edsclr_dim = edsclr_dim-1
-
- call rad_cnst_get_info(0, m, nspec=nspec)
- do l = 1, nspec
- call rad_cnst_get_mam_mmr_idx(m, l, lptr)
- lq(lptr)=.false.
- edsclr_dim = edsclr_dim-1
- end do
- end do
-
-
- ! In addition, if running with MAM, droplet number is transported
- ! in dropmixnuc, therefore we do NOT want CLUBB to apply transport
- ! tendencies to avoid double counted. Else, we apply tendencies.
- call cnst_get_ind('NUMLIQ',ixnumliq)
- lq(ixnumliq) = .false.
- edsclr_dim = edsclr_dim-1
- endif
+ ! Initialize all consituents to true to start
+ lq(1:pcnst) = .true.
+ edsclr_dim = pcnst
+
+ if (prog_modal_aero) then
+ ! Turn off modal aerosols and decrement edsclr_dim accordingly
+ call rad_cnst_get_info(0, nmodes=nmodes)
+
+ do m = 1, nmodes
+ call rad_cnst_get_mode_num_idx(m, lptr)
+ lq(lptr)=.false.
+ edsclr_dim = edsclr_dim-1
+
+ call rad_cnst_get_info(0, m, nspec=nspec)
+ do l = 1, nspec
+ call rad_cnst_get_mam_mmr_idx(m, l, lptr)
+ lq(lptr)=.false.
+ edsclr_dim = edsclr_dim-1
+ end do
+ end do
+
+ ! In addition, if running with MAM, droplet number is transported
+ ! in dropmixnuc, therefore we do NOT want CLUBB to apply transport
+ ! tendencies to avoid double counted. Else, we apply tendencies.
+ call cnst_get_ind('NUMLIQ',ixnumliq)
+ lq(ixnumliq) = .false.
+ edsclr_dim = edsclr_dim-1
+ endif
! ----------------------------------------------------------------- !
! Set the debug level. Level 2 has additional computational expense since
@@ -329,35 +560,6 @@ subroutine clubb_ini_cam(pbuf2d)
! physics packages (e.g. tke)
! ----------------------------------------------------------------- !
- ! Determine if we want clubb_history to be output
- clubb_history = .false. ! Initialize to false
- l_stats = .false. ! Initialize to false
- l_output_rad_files = .false. ! Initialize to false
-
- ! Read namelist to determine if CLUBB history should be called
- if (masterproc) then
- iunit= getunit()
- open(unit=iunit,file="atm_in",status='old')
- call find_group_name(iunit, 'clubb_his_nl', status=read_status)
- if (read_status == 0) then
- read(unit=iunit, nml=clubb_his_nl, iostat=read_status)
- if (read_status /= 0) then
- call endrun('clubb_tend_cam: error reading namelist')
- end if
- end if
- close(unit=iunit)
- call freeunit(iunit)
- end if
-
-#ifdef SPMD
- ! Broadcast namelist variables
- call mpibcast(clubb_history, 1, mpilog, 0, mpicom)
- call mpibcast(clubb_rad_history, 1, mpilog, 0, mpicom)
-#endif
-
- ! Overwrite defaults if they are true
- if (clubb_history) l_stats = .true.
- if (clubb_rad_history) l_output_rad_files = .true.
! Defaults
l_stats_samp = .false.
@@ -379,6 +581,9 @@ subroutine clubb_ini_cam(pbuf2d)
sh_frac_idx = pbuf_get_index('SH_FRAC') ! Shallow convection cloud fraction
relvar_idx = pbuf_get_index('RELVAR') ! Relative cloud water variance
accre_enhan_idx = pbuf_get_index('ACCRE_ENHAN') ! accretion enhancement for MG
+ prer_evap_idx = pbuf_get_index('PRER_EVAP')
+ qrl_idx = pbuf_get_index('QRL')
+ cmfmc_sh_idx = pbuf_get_index('CMFMC_SH')
iisclr_rt = -1
iisclr_thl = -1
@@ -388,20 +593,29 @@ subroutine clubb_ini_cam(pbuf2d)
iiedsclr_thl = -1
iiedsclr_CO2 = -1
+ ! ----------------------------------------------------------------- !
+ ! Define number of tracers for CLUBB to diffuse
+ ! ----------------------------------------------------------------- !
+
+ if (do_expldiff) then
+ offset = 2 ! diffuse temperature and moisture explicitly
+ edsclr_dim = edsclr_dim + offset
+ endif
+
! ----------------------------------------------------------------- !
! Setup CLUBB core
! ----------------------------------------------------------------- !
! Read in parameters for CLUBB. Just read in default values
!$OMP PARALLEL
- call read_parameters( -99, "", clubb_params )
+ call read_parameters( -99, "", clubb_params )
!$OMP END PARALLEL
! Fill in dummy arrays for height. Note that these are overwrote
! at every CLUBB step to physical values.
do k=1,pverp
- zt_g(k) = ((k-1)*1000._r8)-500._r8 ! this is dummy garbage
- zi_g(k) = (k-1)*1000._r8 ! this is dummy garbage
+ zt_g(k) = ((k-1)*1000._r8)-500._r8 ! this is dummy garbage
+ zi_g(k) = (k-1)*1000._r8 ! this is dummy garbage
enddo
! Set up CLUBB core. Note that some of these inputs are overwrote
@@ -416,11 +630,10 @@ subroutine clubb_ini_cam(pbuf2d)
l_host_applies_sfc_fluxes, & ! In
l_uv_nudge, saturation_equation, & ! In
l_implemented, grid_type, zi_g(2), zi_g(1), zi_g(pverp), & ! In
- zi_g(1:pverp), zt_g(1:pverp), & ! In
- host_dx, host_dy, zi_g(1), & ! In
+ zi_g(1:pverp), zt_g(1:pverp), zi_g(1), & ! In
err_code )
!$OMP END PARALLEL
-
+
! ----------------------------------------------------------------- !
! Set-up HB diffusion. Only initialized to diagnose PBL depth !
! ----------------------------------------------------------------- !
@@ -437,144 +650,187 @@ subroutine clubb_ini_cam(pbuf2d)
! ------------------------------------------------------------------!
if ( do_tms) then
- call init_tms( r8, tms_orocnst, tms_z0fac, karman, gravit, rair, errstring)
- call handle_errmsg(errstring, subname="init_tms")
-
- call addfld( 'TAUTMSX' ,'N/m2 ', 1, 'A', 'Zonal turbulent mountain surface stress', phys_decomp )
- call addfld( 'TAUTMSY' ,'N/m2 ', 1, 'A', 'Meridional turbulent mountain surface stress', phys_decomp )
- call add_default( 'TAUTMSX ', 1, ' ' )
- call add_default( 'TAUTMSY ', 1, ' ' )
- if (masterproc) then
- write(iulog,*)'Using turbulent mountain stress module'
- write(iulog,*)' tms_orocnst = ',tms_orocnst
- write(iulog,*)' tms_z0fac = ',tms_z0fac
- end if
+ call init_tms( r8, tms_orocnst, tms_z0fac, karman, gravit, rair, errstring)
+ call handle_errmsg(errstring, subname="init_tms")
+
+ call addfld( 'TAUTMSX' ,'N/m2 ', 1, 'A', 'Zonal turbulent mountain surface stress', phys_decomp )
+ call addfld( 'TAUTMSY' ,'N/m2 ', 1, 'A', 'Meridional turbulent mountain surface stress', phys_decomp )
+ if (history_amwg) then
+ call add_default( 'TAUTMSX ', 1, ' ' )
+ call add_default( 'TAUTMSY ', 1, ' ' )
+ end if
+ if (masterproc) then
+ write(iulog,*)'Using turbulent mountain stress module'
+ write(iulog,*)' tms_orocnst = ',tms_orocnst
+ write(iulog,*)' tms_z0fac = ',tms_z0fac
+ end if
endif
! ----------------------------------------------------------------- !
! Add output fields for the history files
! ----------------------------------------------------------------- !
- ! These are default CLUBB output. Not the higher order history budgets
- call addfld ('RHO_CLUBB', 'kg/m3', pverp, 'A', 'Air Density', phys_decomp)
- call addfld ('UP2_CLUBB', 'm2/s2', pverp, 'A', 'Zonal Velocity Variance', phys_decomp)
- call addfld ('VP2_CLUBB', 'm2/s2', pverp, 'A', 'Meridional Velocity Variance', phys_decomp)
- call addfld ('WP2_CLUBB', 'm2/s2', pverp, 'A', 'Vertical Velocity Variance', phys_decomp)
- call addfld ('UPWP_CLUBB', 'm2/s2', pverp, 'A', 'Zonal Momentum Flux', phys_decomp)
- call addfld ('VPWP_CLUBB', 'm2/s2', pverp, 'A', 'Meridional Momentum Flux', phys_decomp)
- call addfld ('WP3_CLUBB', 'm3/s3', pverp, 'A', 'Third Moment Vertical Velocity', phys_decomp)
- call addfld ('WPTHLP_CLUBB', 'W/m2', pverp, 'A', 'Heat Flux', phys_decomp)
- call addfld ('WPRTP_CLUBB', 'W/m2', pverp, 'A', 'Moisture Flux', phys_decomp)
- call addfld ('RTP2_CLUBB', 'g^2/kg^2', pverp, 'A', 'Moisture Variance', phys_decomp)
- call addfld ('THLP2_CLUBB', 'K^2', pverp, 'A', 'Temperature Variance', phys_decomp)
- call addfld ('RTPTHLP_CLUBB', 'K g/kg', pverp, 'A', 'Temp. Moist. Covariance', phys_decomp)
- call addfld ('RCM_CLUBB', 'g/kg', pverp, 'A', 'Cloud Water Mixing Ratio', phys_decomp)
- call addfld ('WPRCP_CLUBB', 'W/m2', pverp, 'A', 'Liquid Water Flux', phys_decomp)
- call addfld ('CLOUDFRAC_CLUBB', 'fraction', pver, 'A', 'Cloud Fraction', phys_decomp)
- call addfld ('RCMINLAYER_CLUBB', 'g/kg', pverp, 'A', 'Cloud Water in Layer', phys_decomp)
- call addfld ('CLOUDCOVER_CLUBB', 'fraction', pverp, 'A', 'Cloud Cover', phys_decomp)
- call addfld ('WPTHVP_CLUBB', 'W/m2', pver, 'A', 'Buoyancy Flux',phys_decomp)
- call addfld ('RVMTEND_CLUBB', 'g/kg /s', pver, 'A', 'Water vapor tendency',phys_decomp)
- call addfld ('STEND_CLUBB', 'k/s', pver, 'A', 'Temperature tendency',phys_decomp)
- call addfld ('RCMTEND_CLUBB', 'g/kg /s', pver, 'A', 'Cloud Liquid Water Tendency',phys_decomp)
- call addfld ('RIMTEND_CLUBB', 'g/kg /s', pver, 'A', 'Cloud Ice Tendency',phys_decomp)
- call addfld ('UTEND_CLUBB', 'm/s /s', pver, 'A', 'U-wind Tendency',phys_decomp)
- call addfld ('VTEND_CLUBB', 'm/s /s', pver, 'A', 'V-wind Tendency',phys_decomp)
- call addfld ('ZT_CLUBB', 'm', pverp, 'A', 'Thermodynamic Heights',phys_decomp)
- call addfld ('ZM_CLUBB', 'm', pverp, 'A', 'Momentum Heights',phys_decomp)
- call addfld ('UM_CLUBB', 'm/s', pverp, 'A', 'Zonal Wind',phys_decomp)
- call addfld ('VM_CLUBB', 'm/s', pverp, 'A', 'Meridional Wind',phys_decomp)
- call addfld ('THETAL', 'K', pver, 'A', 'Liquid Water Potential Temperature',phys_decomp)
- call addfld ('PBLH', 'm', 1, 'A', 'PBL height',phys_decomp)
- call addfld ('QT', 'kg/kg', pver, 'A', 'Total water mixing ratio',phys_decomp)
- call addfld ('SL', 'J/kg', pver, 'A', 'Liquid water static energy',phys_decomp)
- call addfld ('CLDST', 'fraction', pver, 'A', 'Stratus cloud fraction',phys_decomp)
- call addfld ('ZMDLF', 'kg/kg/s', pver, 'A', 'Detrained liquid water from ZM convection',phys_decomp)
-
- call addfld ('CONCLD ', 'fraction', pver, 'A', 'Convective cloud cover',phys_decomp)
- call addfld ('CMELIQ ', 'kg/kg/s ', pver, 'A', 'Rate of cond-evap of liq within the cloud',phys_decomp)
-
- ! Initialize statistics, below are dummy variables
- dum1 = 300._r8
- dum2 = 1200._r8
- dum3 = 300._r8
-
- if (l_stats) then
+ if (clubb_do_deep) then
+ call addfld ('MU_CLUBB','1/m',1,'A','CLUBB value of entrainment',phys_decomp)
+ endif
+
+ ! These are default CLUBB output. Not the higher order history budgets
+ call addfld ('RHO_CLUBB', 'kg/m3', pverp, 'A', 'Air Density', phys_decomp)
+ call addfld ('UP2_CLUBB', 'm2/s2', pverp, 'A', 'Zonal Velocity Variance', phys_decomp)
+ call addfld ('VP2_CLUBB', 'm2/s2', pverp, 'A', 'Meridional Velocity Variance', phys_decomp)
+ call addfld ('WP2_CLUBB', 'm2/s2', pverp, 'A', 'Vertical Velocity Variance', phys_decomp)
+ call addfld ('UPWP_CLUBB', 'm2/s2', pverp, 'A', 'Zonal Momentum Flux', phys_decomp)
+ call addfld ('VPWP_CLUBB', 'm2/s2', pverp, 'A', 'Meridional Momentum Flux', phys_decomp)
+ call addfld ('WP3_CLUBB', 'm3/s3', pverp, 'A', 'Third Moment Vertical Velocity', phys_decomp)
+ call addfld ('WPTHLP_CLUBB', 'W/m2', pverp, 'A', 'Heat Flux', phys_decomp)
+ call addfld ('WPRTP_CLUBB', 'W/m2', pverp, 'A', 'Moisture Flux', phys_decomp)
+ call addfld ('RTP2_CLUBB', 'g^2/kg^2', pverp, 'A', 'Moisture Variance', phys_decomp)
+ call addfld ('THLP2_CLUBB', 'K^2', pverp, 'A', 'Temperature Variance', phys_decomp)
+ call addfld ('RTPTHLP_CLUBB', 'K g/kg', pverp, 'A', 'Temp. Moist. Covariance', phys_decomp)
+ call addfld ('RCM_CLUBB', 'g/kg', pverp, 'A', 'Cloud Water Mixing Ratio', phys_decomp)
+ call addfld ('WPRCP_CLUBB', 'W/m2', pverp, 'A', 'Liquid Water Flux', phys_decomp)
+ call addfld ('CLOUDFRAC_CLUBB', 'fraction', pver, 'A', 'Cloud Fraction', phys_decomp)
+ call addfld ('RCMINLAYER_CLUBB', 'g/kg', pverp, 'A', 'Cloud Water in Layer', phys_decomp)
+ call addfld ('CLOUDCOVER_CLUBB', 'fraction', pverp, 'A', 'Cloud Cover', phys_decomp)
+ call addfld ('WPTHVP_CLUBB', 'W/m2', pver, 'A', 'Buoyancy Flux',phys_decomp)
+ call addfld ('RVMTEND_CLUBB', 'g/kg /s', pver, 'A', 'Water vapor tendency',phys_decomp)
+ call addfld ('STEND_CLUBB', 'k/s', pver, 'A', 'Temperature tendency',phys_decomp)
+ call addfld ('RCMTEND_CLUBB', 'g/kg /s', pver, 'A', 'Cloud Liquid Water Tendency',phys_decomp)
+ call addfld ('RIMTEND_CLUBB', 'g/kg /s', pver, 'A', 'Cloud Ice Tendency',phys_decomp)
+ call addfld ('UTEND_CLUBB', 'm/s /s', pver, 'A', 'U-wind Tendency',phys_decomp)
+ call addfld ('VTEND_CLUBB', 'm/s /s', pver, 'A', 'V-wind Tendency',phys_decomp)
+ call addfld ('ZT_CLUBB', 'm', pverp, 'A', 'Thermodynamic Heights',phys_decomp)
+ call addfld ('ZM_CLUBB', 'm', pverp, 'A', 'Momentum Heights',phys_decomp)
+ call addfld ('UM_CLUBB', 'm/s', pverp, 'A', 'Zonal Wind',phys_decomp)
+ call addfld ('VM_CLUBB', 'm/s', pverp, 'A', 'Meridional Wind',phys_decomp)
+ call addfld ('THETAL', 'K', pver, 'A', 'Liquid Water Potential Temperature',phys_decomp)
+ call addfld ('PBLH', 'm', 1, 'A', 'PBL height',phys_decomp)
+ call addfld ('QT', 'kg/kg', pver, 'A', 'Total water mixing ratio',phys_decomp)
+ call addfld ('SL', 'J/kg', pver, 'A', 'Liquid water static energy',phys_decomp)
+ call addfld ('CLDST', 'fraction', pver, 'A', 'Stratus cloud fraction',phys_decomp)
+ call addfld ('ZMDLF', 'kg/kg/s', pver, 'A', 'Detrained liquid water from ZM convection',phys_decomp)
+ call addfld ('TTENDICE', 'K/s ', pver, 'A', 'T tendency from Ice Saturation Adjustment',phys_decomp)
+ call addfld ('QVTENDICE', 'kg/kg/s ', pver, 'A', 'Q tendency from Ice Saturation Adjustment',phys_decomp)
+ call addfld ('QITENDICE', 'kg/kg/s ', pver, 'A', 'CLDICE tendency from Ice Saturation Adjustment',phys_decomp)
+ call addfld ('NITENDICE', 'kg/kg/s ', pver, 'A', 'NUMICE tendency from Ice Saturation Adjustment',phys_decomp)
+ call addfld ('DPDLFLIQ ', 'kg/kg/s ', pver, 'A', 'Detrained liquid water from deep convection',phys_decomp)
+ call addfld ('DPDLFICE ', 'kg/kg/s ', pver, 'A', 'Detrained ice from deep convection',phys_decomp)
+ call addfld ('DPDLFT ', 'K/s ', pver, 'A', 'T-tendency due to deep convective detrainment',phys_decomp)
+ call addfld ('RELVAR ', '- ', pver, 'A', 'Relative cloud water variance',phys_decomp)
+
+
+ call addfld ('CONCLD ', 'fraction', pver, 'A', 'Convective cloud cover',phys_decomp)
+ call addfld ('CMELIQ ', 'kg/kg/s ', pver, 'A', 'Rate of cond-evap of liq within the cloud',phys_decomp)
+
+ ! Initialize statistics, below are dummy variables
+ dum1 = 300._r8
+ dum2 = 1200._r8
+ dum3 = 300._r8
+
+ if (l_stats) then
- call stats_init_clubb( .true., dum1, dum2, &
+ call stats_init_clubb( .true., dum1, dum2, &
pverp, pverp, pverp, dum3 )
-
- allocate(out_zt(pcols,pverp,zt%nn))
- allocate(out_zm(pcols,pverp,zm%nn))
- allocate(out_sfc(pcols,1,sfc%nn))
-
- allocate(out_radzt(pcols,pverp,rad_zt%nn))
- allocate(out_radzm(pcols,pverp,rad_zm%nn))
-
- endif
+
+ allocate(out_zt(pcols,pverp,stats_zt%num_output_fields))
+ allocate(out_zm(pcols,pverp,stats_zm%num_output_fields))
+ allocate(out_sfc(pcols,1,stats_sfc%num_output_fields))
+
+ allocate(out_radzt(pcols,pverp,stats_rad_zt%num_output_fields))
+ allocate(out_radzm(pcols,pverp,stats_rad_zm%num_output_fields))
+
+ endif
! ----------------------------------------------------------------- !
! Make all of this output default, this is not CLUBB history
! ----------------------------------------------------------------- !
-
- call add_default('RHO_CLUBB', 1, ' ')
- call add_default('UP2_CLUBB', 1, ' ')
- call add_default('VP2_CLUBB', 1, ' ')
- call add_default('WP2_CLUBB', 1, ' ')
- call add_default('WP3_CLUBB', 1, ' ')
- call add_default('UPWP_CLUBB', 1, ' ')
- call add_default('VPWP_CLUBB', 1, ' ')
- call add_default('WPTHLP_CLUBB', 1, ' ')
- call add_default('WPRTP_CLUBB', 1, ' ')
- call add_default('RTP2_CLUBB', 1, ' ')
- call add_default('THLP2_CLUBB', 1, ' ')
- call add_default('RTPTHLP_CLUBB', 1, ' ')
- call add_default('RCM_CLUBB', 1, ' ')
- call add_default('WPRCP_CLUBB', 1, ' ')
- call add_default('CLOUDFRAC_CLUBB', 1, ' ')
- call add_default('RCMINLAYER_CLUBB', 1, ' ')
- call add_default('CLOUDCOVER_CLUBB', 1, ' ')
- call add_default('WPTHVP_CLUBB', 1, ' ')
- call add_default('RVMTEND_CLUBB', 1, ' ')
- call add_default('STEND_CLUBB', 1, ' ')
- call add_default('RCMTEND_CLUBB', 1, ' ')
- call add_default('RIMTEND_CLUBB', 1, ' ')
- call add_default('UTEND_CLUBB', 1, ' ')
- call add_default('VTEND_CLUBB', 1, ' ')
- call add_default('ZT_CLUBB', 1, ' ')
- call add_default('ZM_CLUBB', 1, ' ')
- call add_default('UM_CLUBB', 1, ' ')
- call add_default('VM_CLUBB', 1, ' ')
- call add_default('PBLH', 1, ' ')
- call add_default('SL', 1, ' ')
- call add_default('QT', 1, ' ')
- call add_default('CONCLD', 1, ' ')
-
+ if (clubb_do_adv .or. history_clubb) then
+ call add_default('WP2_CLUBB', 1, ' ')
+ call add_default('WP3_CLUBB', 1, ' ')
+ call add_default('WPTHLP_CLUBB', 1, ' ')
+ call add_default('WPRTP_CLUBB', 1, ' ')
+ call add_default('RTP2_CLUBB', 1, ' ')
+ call add_default('THLP2_CLUBB', 1, ' ')
+ call add_default('RTPTHLP_CLUBB', 1, ' ')
+ call add_default('UP2_CLUBB', 1, ' ')
+ call add_default('VP2_CLUBB', 1, ' ')
+ end if
+
+ if (history_clubb) then
+
+ if (clubb_do_deep) then
+ call add_default('MU_CLUBB', 1, ' ')
+ endif
+
+ call add_default('RELVAR', 1, ' ')
+ call add_default('RHO_CLUBB', 1, ' ')
+ call add_default('UPWP_CLUBB', 1, ' ')
+ call add_default('VPWP_CLUBB', 1, ' ')
+ call add_default('RCM_CLUBB', 1, ' ')
+ call add_default('WPRCP_CLUBB', 1, ' ')
+ call add_default('CLOUDFRAC_CLUBB', 1, ' ')
+ call add_default('RCMINLAYER_CLUBB', 1, ' ')
+ call add_default('CLOUDCOVER_CLUBB', 1, ' ')
+ call add_default('WPTHVP_CLUBB', 1, ' ')
+ call add_default('RVMTEND_CLUBB', 1, ' ')
+ call add_default('STEND_CLUBB', 1, ' ')
+ call add_default('RCMTEND_CLUBB', 1, ' ')
+ call add_default('RIMTEND_CLUBB', 1, ' ')
+ call add_default('UTEND_CLUBB', 1, ' ')
+ call add_default('VTEND_CLUBB', 1, ' ')
+ call add_default('ZT_CLUBB', 1, ' ')
+ call add_default('ZM_CLUBB', 1, ' ')
+ call add_default('UM_CLUBB', 1, ' ')
+ call add_default('VM_CLUBB', 1, ' ')
+ call add_default('SL', 1, ' ')
+ call add_default('QT', 1, ' ')
+ call add_default('CONCLD', 1, ' ')
+
+ end if
+
+ if (history_amwg) then
+ call add_default('PBLH', 1, ' ')
+ end if
+
+ if (history_budget) then
+ call add_default('DPDLFLIQ', history_budget_histfile_num, ' ')
+ call add_default('DPDLFICE', history_budget_histfile_num, ' ')
+ call add_default('DPDLFT', history_budget_histfile_num, ' ')
+ call add_default('STEND_CLUBB', history_budget_histfile_num, ' ')
+ call add_default('RCMTEND_CLUBB', history_budget_histfile_num, ' ')
+ call add_default('RIMTEND_CLUBB', history_budget_histfile_num, ' ')
+ call add_default('RVMTEND_CLUBB', history_budget_histfile_num, ' ')
+ call add_default('UTEND_CLUBB', history_budget_histfile_num, ' ')
+ call add_default('VTEND_CLUBB', history_budget_histfile_num, ' ')
+ endif
+
! --------------- !
! First step? !
! Initialization !
! --------------- !
- ! Is this the first time step? If so then initialize CLUBB variables as follows
- if (is_first_step()) then
-
- call pbuf_set_field(pbuf2d, wp2_idx, w_tol_sqd)
- call pbuf_set_field(pbuf2d, wp3_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, wpthlp_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, wprtp_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, rtpthlp_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, rtp2_idx, rt_tol**2)
- call pbuf_set_field(pbuf2d, thlp2_idx, thl_tol**2)
- call pbuf_set_field(pbuf2d, up2_idx, w_tol_sqd)
- call pbuf_set_field(pbuf2d, vp2_idx, w_tol_sqd)
- call pbuf_set_field(pbuf2d, upwp_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, vpwp_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, tke_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, kvh_idx, 0.0_r8)
- call pbuf_set_field(pbuf2d, fice_idx, 0.0_r8)
+ ! Is this the first time step? If so then initialize CLUBB variables as follows
+ if (is_first_step()) then
+
+ call pbuf_set_field(pbuf2d, wp2_idx, w_tol_sqd)
+ call pbuf_set_field(pbuf2d, wp3_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, wpthlp_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, wprtp_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, rtpthlp_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, rtp2_idx, rt_tol**2)
+ call pbuf_set_field(pbuf2d, thlp2_idx, thl_tol**2)
+ call pbuf_set_field(pbuf2d, up2_idx, w_tol_sqd)
+ call pbuf_set_field(pbuf2d, vp2_idx, w_tol_sqd)
+
+ call pbuf_set_field(pbuf2d, upwp_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, vpwp_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, tke_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, kvh_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, fice_idx, 0.0_r8)
+ call pbuf_set_field(pbuf2d, radf_idx, 0.0_r8)
- endif
+ endif
! --------------- !
! End !
@@ -589,11 +845,11 @@ end subroutine clubb_ini_cam
! !
! =============================================================================== !
- subroutine clubb_tend_cam( &
+ subroutine clubb_tend_cam( &
state, ptend_all, pbuf, hdtime, &
- cmfmc, cmfmc2, cam_in, sgh30, dlf, &
- det_s, det_ice)
-
+ cmfmc, cam_in, sgh30, &
+ macmic_it, cld_macmic_num_steps,dlf, det_s, det_ice)
+
!-------------------------------------------------------------------------------
! Description: Provide tendencies of shallow convection, turbulence, and
! macrophysics from CLUBB to CAM
@@ -605,150 +861,181 @@ subroutine clubb_tend_cam( &
! None
!-------------------------------------------------------------------------------
- use physics_types, only: physics_state, physics_ptend, &
- physics_state_copy, physics_ptend_init, &
- physics_ptend_sum, physics_update
-
- use physics_buffer, only: pbuf_get_index, pbuf_old_tim_idx, pbuf_get_field, &
- pbuf_set_field, physics_buffer_desc
-
- use ppgrid, only: pver, pverp, pcols
- use constituents, only: cnst_get_ind
- use camsrfexch, only: cam_in_t
+ use physics_types, only: physics_state, physics_ptend, &
+ physics_state_copy, physics_ptend_init, &
+ physics_ptend_sum, physics_update
+
+ use physics_buffer, only: pbuf_get_index, pbuf_old_tim_idx, pbuf_get_field, &
+ pbuf_set_field, physics_buffer_desc
+
+ use ppgrid, only: pver, pverp, pcols
+ use constituents, only: cnst_get_ind
+ use camsrfexch, only: cam_in_t
+ use ref_pres, only: top_lev => trop_cloud_top_lev
+ use time_manager, only: is_first_step
+ use cam_abortutils, only: endrun
+ use wv_saturation, only: qsat
+ use micro_mg_cam, only: micro_mg_version
#ifdef CLUBB_SGS
- use hb_diff, only: pblintd
- use scamMOD, only: single_column,scm_clubb_iop_name
- use phys_grid, only: get_lat_p
- use parameter_indices, only: nparams
- use parameters_tunable, only: read_parameters, setup_parameters ! Subroutine
- use cldwat2m_macro, only: aist_vector
- use clubb_precision,only: time_precision
- use cam_history, only: outfld
- use clubb_core, only: advance_clubb_core
- use grid_class, only: zt2zm, gr, setup_grid, cleanup_grid
- use constants_clubb,only: em_min, w_tol_sqd, rt_tol, thl_tol
- use model_flags, only: l_use_boussinesq
- use stats_variables, only: l_stats, stats_tsamp, stats_tout, zt, &
- sfc, zm, rad_zt, rad_zm, l_output_rad_files
- use pdf_parameter_module, only: pdf_parameter ! Type
- use saturation, only: sat_mixrat_liq
- use trb_mtn_stress, only: compute_tms
- use stats_subs, only: stats_begin_timestep
+ use hb_diff, only: pblintd
+ use scamMOD, only: single_column,scm_clubb_iop_name
+ use phys_grid, only: get_lat_p
+ use parameter_indices, only: nparams
+ use parameters_tunable, only: read_parameters, setup_parameters ! Subroutine
+ use cldfrc2m, only: aist_vector
+ use clubb_precision, only: time_precision
+ use cam_history, only: outfld
+ use advance_clubb_core_module, only: advance_clubb_core, calculate_thlp2_rad
+ use grid_class, only: zt2zm, zm2zt, gr, setup_grid, cleanup_grid
+ use constants_clubb, only: w_tol_sqd, rt_tol, thl_tol
+ use model_flags, only: l_use_boussinesq
+ use stats_variables, only: l_stats, stats_tsamp, stats_tout, stats_zt, &
+ stats_sfc, stats_zm, stats_rad_zt, stats_rad_zm, l_output_rad_files
+ use pdf_parameter_module, only: pdf_parameter ! Type
+ use parameters_tunable, only: mu
+ use saturation, only: sat_mixrat_liq
+ use trb_mtn_stress, only: compute_tms
+ use stats_clubb_utilities, only: stats_begin_timestep
+ use advance_xp2_xpyp_module, only: update_xp2_mc
+ use macrop_driver, only: ice_macro_tend
#endif
- implicit none
+ implicit none
- ! --------------- !
- ! Input Auguments !
- ! --------------- !
+ ! --------------- !
+ ! Input Auguments !
+ ! --------------- !
- type(physics_state), intent(in) :: state ! Physics state variables [vary]
- type(cam_in_t), intent(in) :: cam_in
- real(r8), intent(in) :: hdtime ! Host model timestep [s]
- real(r8), intent(in) :: dlf(pcols,pver) ! Detraining cld H20 from deep convection [kg/ks/s]
- real(r8), intent(in) :: cmfmc(pcols,pverp) ! convective mass flux--m sub c [kg/m2/s]
- real(r8), intent(in) :: cmfmc2(pcols,pverp) ! shallow convective mass flux--m subc [kg/m2/s]
- real(r8), intent(in) :: sgh30(pcols) ! std deviation of orography [m]
+ type(physics_state), intent(in) :: state ! Physics state variables [vary]
+ type(cam_in_t), intent(in) :: cam_in
+ real(r8), intent(in) :: hdtime ! Host model timestep [s]
+ real(r8), intent(in) :: dlf(pcols,pver) ! Detraining cld H20 from deep convection [kg/ks/s]
+ real(r8), intent(in) :: cmfmc(pcols,pverp) ! convective mass flux--m sub c [kg/m2/s]
+ real(r8), intent(in) :: sgh30(pcols) ! std deviation of orography [m]
+ integer, intent(in) :: cld_macmic_num_steps ! number of mac-mic iterations
+ integer, intent(in) :: macmic_it ! number of mac-mic iterations
- ! ---------------------- !
- ! Input-Output Auguments !
- ! ---------------------- !
+ ! ---------------------- !
+ ! Input-Output Auguments !
+ ! ---------------------- !
- type(physics_buffer_desc), pointer :: pbuf(:)
+ type(physics_buffer_desc), pointer :: pbuf(:)
- ! ---------------------- !
- ! Output Auguments !
- ! ---------------------- !
+ ! ---------------------- !
+ ! Output Auguments !
+ ! ---------------------- !
- type(physics_ptend), intent(out) :: ptend_all ! package tendencies
+ type(physics_ptend), intent(out) :: ptend_all ! package tendencies
- ! These two variables are needed for energy check
- real(r8), intent(out) :: det_s(pcols) ! Integral of detrained static energy from ice
- real(r8), intent(out) :: det_ice(pcols) ! Integral of detrained ice for energy check
+ ! These two variables are needed for energy check
+ real(r8), intent(out) :: det_s(pcols) ! Integral of detrained static energy from ice
+ real(r8), intent(out) :: det_ice(pcols) ! Integral of detrained ice for energy check
- ! --------------- !
- ! Local Variables !
- ! --------------- !
+ ! --------------- !
+ ! Local Variables !
+ ! --------------- !
-#if CLUBB_SGS
+#ifdef CLUBB_SGS
- type(physics_state) :: state1 ! Local copy of state variable
- type(physics_ptend) :: ptend_loc ! Local tendency from processes, added up to return as ptend_all
+ type(physics_state) :: state1 ! Local copy of state variable
+ type(physics_ptend) :: ptend_loc ! Local tendency from processes, added up to return as ptend_all
integer :: i, j, k, t, ixind, nadv
integer :: ixcldice, ixcldliq, ixnumliq, ixnumice, ixq
integer :: itim_old
- integer :: ncol, lchnk ! # of columns, and chunk identifier
- integer :: err_code ! Diagnostic, for if some calculation goes amiss.
+ integer :: ncol, lchnk ! # of columns, and chunk identifier
+ integer :: err_code ! Diagnostic, for if some calculation goes amiss.
integer :: begin_height, end_height
integer :: icnt
real(r8) :: frac_limit, ic_limit
- real(r8) :: dtime ! CLUBB time step [s]
- real(r8) :: edsclr_in(pverp,edsclr_dim) ! Scalars to be diffused through CLUBB [units vary]
- real(r8) :: wp2_in(pverp) ! vertical velocity variance (CLUBB) [m^2/s^2]
- real(r8) :: wp3_in(pverp) ! third moment vertical velocity [m^3/s^3]
- real(r8) :: wpthlp_in(pverp) ! turbulent flux of thetal [K m/s]
- real(r8) :: wprtp_in(pverp) ! turbulent flux of total water [kg/kg m/s]
- real(r8) :: rtpthlp_in(pverp) ! covariance of thetal and qt [kg/kg K]
- real(r8) :: rtp2_in(pverp) ! total water variance [kg^2/k^2]
- real(r8) :: thlp2_in(pverp) ! thetal variance [K^2]
- real(r8) :: up2_in(pverp) ! meridional wind variance [m^2/s^2]
- real(r8) :: vp2_in(pverp) ! zonal wind variance [m^2/s^2]
- real(r8) :: upwp_in(pverp) ! meridional wind flux [m^2/s^2]
- real(r8) :: vpwp_in(pverp) ! zonal wind flux [m^2/s^2]
- real(r8) :: thlm_in(pverp) ! liquid water potential temperature (thetal) [K]
- real(r8) :: rtm_in(pverp) ! total water mixing ratio [kg/kg]
- real(r8) :: um_in(pverp) ! meridional wind [m/s]
- real(r8) :: vm_in(pverp) ! zonal wind [m/s]
- real(r8) :: rho_in(pverp) ! mid-point density [kg/m^3]
- real(r8) :: rcm_out(pverp) ! CLUBB output of liquid water mixing ratio [kg/kg]
- real(r8) :: wprcp_out(pverp) ! CLUBB output of flux of liquid water [kg/kg m/s]
- real(r8) :: cloud_frac_out(pverp) ! CLUBB output of cloud fraction [fraction]
- real(r8) :: rcm_in_layer_out(pverp) ! CLUBB output of in-cloud liq. wat. mix. ratio [kg/kg]
- real(r8) :: cloud_cover_out(pverp) ! CLUBB output of in-cloud cloud fraction [fraction]
- real(r8) :: rho_ds_zm(pverp) ! Dry, static density on momentum levels [kg/m^3]
- real(r8) :: rho_ds_zt(pverp) ! Dry, static density on thermodynamic levels [kg/m^3]
- real(r8) :: invrs_rho_ds_zm(pverp) ! Inv. dry, static density on momentum levels [m^3/kg]
- real(r8) :: invrs_rho_ds_zt(pverp) ! Inv. dry, static density on thermo. levels [m^3/kg]
- real(r8) :: thv_ds_zm(pverp) ! Dry, base-state theta_v on momentum levels [K]
- real(r8) :: thv_ds_zt(pverp) ! Dry, base-state theta_v on thermo. levels [K]
- real(r8) :: zt_g(pverp) ! Thermodynamic grid of CLUBB [m]
- real(r8) :: zi_g(pverp) ! Momentum grid of CLUBB [m]
- real(r8) :: zt_out(pcols,pverp) ! output for the thermo CLUBB grid [m]
- real(r8) :: zi_out(pcols,pverp) ! output for momentum CLUBB grid [m]
- real(r8) :: fcor ! Coriolis forcing [s^-1]
- real(r8) :: sfc_elevation ! Elevation of ground [m AMSL] [m]
- real(r8) :: ubar ! surface wind [m/s]
- real(r8) :: ustar ! surface stress [m/s]
- real(r8) :: z0 ! roughness height [m]
- real(r8) :: thlm_forcing(pverp) ! theta_l forcing (thermodynamic levels) [K/s]
- real(r8) :: rtm_forcing(pverp) ! r_t forcing (thermodynamic levels) [(kg/kg)/s]
- real(r8) :: um_forcing(pverp) ! u wind forcing (thermodynamic levels) [m/s/s]
- real(r8) :: vm_forcing(pverp) ! v wind forcing (thermodynamic levels) [m/s/s]
- real(r8) :: wm_zm(pverp) ! w mean wind component on momentum levels [m/s]
- real(r8) :: wm_zt(pverp) ! w mean wind component on thermo. levels [m/s]
- real(r8) :: p_in_Pa(pverp) ! Air pressure (thermodynamic levels) [Pa]
+ real(r8) :: dtime ! CLUBB time step [s]
+ real(r8) :: edsclr_in(pverp,edsclr_dim) ! Scalars to be diffused through CLUBB [units vary]
+ real(r8) :: wp2_in(pverp) ! vertical velocity variance (CLUBB) [m^2/s^2]
+ real(r8) :: wp3_in(pverp) ! third moment vertical velocity [m^3/s^3]
+ real(r8) :: wpthlp_in(pverp) ! turbulent flux of thetal [K m/s]
+ real(r8) :: wprtp_in(pverp) ! turbulent flux of total water [kg/kg m/s]
+ real(r8) :: rtpthlp_in(pverp) ! covariance of thetal and qt [kg/kg K]
+ real(r8) :: rtp2_in(pverp) ! total water variance [kg^2/k^2]
+ real(r8) :: thlp2_in(pverp) ! thetal variance [K^2]
+ real(r8) :: up2_in(pverp) ! meridional wind variance [m^2/s^2]
+ real(r8) :: vp2_in(pverp) ! zonal wind variance [m^2/s^2]
+ real(r8) :: upwp_in(pverp) ! meridional wind flux [m^2/s^2]
+ real(r8) :: vpwp_in(pverp) ! zonal wind flux [m^2/s^2]
+ real(r8) :: thlm_in(pverp) ! liquid water potential temperature (thetal) [K]
+ real(r8) :: rtm_in(pverp) ! total water mixing ratio [kg/kg]
+ real(r8) :: rvm_in(pverp) ! water vapor mixing ratio [kg/kg]
+ real(r8) :: um_in(pverp) ! meridional wind [m/s]
+ real(r8) :: vm_in(pverp) ! zonal wind [m/s]
+ real(r8) :: rho_in(pverp) ! mid-point density [kg/m^3]
+ real(r8) :: pre_in(pverp) ! input for precip evaporation
+ real(r8) :: rtp2_mc_out(pverp) ! total water tendency from rain evap
+ real(r8) :: thlp2_mc_out(pverp) ! thetal tendency from rain evap
+ real(r8) :: wprtp_mc_out(pverp)
+ real(r8) :: wpthlp_mc_out(pverp)
+ real(r8) :: rtpthlp_mc_out(pverp)
+ real(r8) :: rcm_out(pverp) ! CLUBB output of liquid water mixing ratio [kg/kg]
+ real(r8) :: rcm_out_zm(pverp)
+ real(r8) :: wprcp_out(pverp) ! CLUBB output of flux of liquid water [kg/kg m/s]
+ real(r8) :: cloud_frac_out(pverp) ! CLUBB output of cloud fraction [fraction]
+ real(r8) :: rcm_in_layer_out(pverp) ! CLUBB output of in-cloud liq. wat. mix. ratio [kg/kg]
+ real(r8) :: cloud_cover_out(pverp) ! CLUBB output of in-cloud cloud fraction [fraction]
+ real(r8) :: thlprcp_out(pverp)
+ real(r8) :: rho_ds_zm(pverp) ! Dry, static density on momentum levels [kg/m^3]
+ real(r8) :: rho_ds_zt(pverp) ! Dry, static density on thermodynamic levels [kg/m^3]
+ real(r8) :: invrs_rho_ds_zm(pverp) ! Inv. dry, static density on momentum levels [m^3/kg]
+ real(r8) :: invrs_rho_ds_zt(pverp) ! Inv. dry, static density on thermo. levels [m^3/kg]
+ real(r8) :: thv_ds_zm(pverp) ! Dry, base-state theta_v on momentum levels [K]
+ real(r8) :: thv_ds_zt(pverp) ! Dry, base-state theta_v on thermo. levels [K]
+ real(r8) :: rfrzm(pverp)
+ real(r8) :: radf(pverp)
+ real(r8) :: wprtp_forcing(pverp)
+ real(r8) :: wpthlp_forcing(pverp)
+ real(r8) :: rtp2_forcing(pverp)
+ real(r8) :: thlp2_forcing(pverp)
+ real(r8) :: rtpthlp_forcing(pverp)
+ real(r8) :: ice_supersat_frac(pverp)
+ real(r8) :: zt_g(pverp) ! Thermodynamic grid of CLUBB [m]
+ real(r8) :: zi_g(pverp) ! Momentum grid of CLUBB [m]
+ real(r8) :: zt_out(pcols,pverp) ! output for the thermo CLUBB grid [m]
+ real(r8) :: zi_out(pcols,pverp) ! output for momentum CLUBB grid [m]
+ real(r8) :: fcor ! Coriolis forcing [s^-1]
+ real(r8) :: sfc_elevation ! Elevation of ground [m AMSL]
+ real(r8) :: ubar ! surface wind [m/s]
+ real(r8) :: ustar ! surface stress [m/s]
+ real(r8) :: z0 ! roughness height [m]
+ real(r8) :: thlm_forcing(pverp) ! theta_l forcing (thermodynamic levels) [K/s]
+ real(r8) :: rtm_forcing(pverp) ! r_t forcing (thermodynamic levels) [(kg/kg)/s]
+ real(r8) :: um_forcing(pverp) ! u wind forcing (thermodynamic levels) [m/s/s]
+ real(r8) :: vm_forcing(pverp) ! v wind forcing (thermodynamic levels) [m/s/s]
+ real(r8) :: wm_zm(pverp) ! w mean wind component on momentum levels [m/s]
+ real(r8) :: wm_zt(pverp) ! w mean wind component on thermo. levels [m/s]
+ real(r8) :: p_in_Pa(pverp) ! Air pressure (thermodynamic levels) [Pa]
real(r8) :: rho_zt(pverp) ! Air density on thermo levels [kt/m^3]
- real(r8) :: rho_zm(pverp) ! Air density on momentum levels [kg/m^3]
- real(r8) :: exner(pverp) ! Exner function (thermodynamic levels) [-]
- real(r8) :: wpthlp_sfc ! w' theta_l' at surface [(m K)/s]
- real(r8) :: wprtp_sfc ! w' r_t' at surface [(kg m)/( kg s)]
- real(r8) :: upwp_sfc ! u'w' at surface [m^2/s^2]
- real(r8) :: vpwp_sfc ! v'w' at surface [m^2/s^2]
- real(r8) :: sclrm_forcing(pverp,sclr_dim) ! Passive scalar forcing [{units vary}/s]
- real(r8) :: wpsclrp_sfc(sclr_dim) ! Scalar flux at surface [{units vary} m/s]
- real(r8) :: edsclrm_forcing(pverp,edsclr_dim)! Eddy passive scalar forcing [{units vary}/s]
- real(r8) :: wpedsclrp_sfc(edsclr_dim) ! Eddy-scalar flux at surface [{units vary} m/s]
- real(r8) :: sclrm(pverp,sclr_dim) ! Passive scalar mean (thermo. levels) [units vary]
- real(r8) :: wpsclrp(pverp,sclr_dim) ! w'sclr' (momentum levels) [{units vary} m/s]
- real(r8) :: sclrp2(pverp,sclr_dim) ! sclr'^2 (momentum levels) [{units vary}^2]
- real(r8) :: sclrprtp(pverp,sclr_dim) ! sclr'rt' (momentum levels) [{units vary} (kg/kg)]
- real(r8) :: sclrpthlp(pverp,sclr_dim) ! sclr'thlp' (momentum levels) [{units vary} (K)]
+ real(r8) :: rho_zm(pverp) ! Air density on momentum levels [kg/m^3]
+ real(r8) :: exner(pverp) ! Exner function (thermodynamic levels) [-]
+ real(r8) :: wpthlp_sfc ! w' theta_l' at surface [(m K)/s]
+ real(r8) :: wprtp_sfc ! w' r_t' at surface [(kg m)/( kg s)]
+ real(r8) :: upwp_sfc ! u'w' at surface [m^2/s^2]
+ real(r8) :: vpwp_sfc ! v'w' at surface [m^2/s^2]
+ real(r8) :: sclrm_forcing(pverp,sclr_dim) ! Passive scalar forcing [{units vary}/s]
+ real(r8) :: wpsclrp_sfc(sclr_dim) ! Scalar flux at surface [{units vary} m/s]
+ real(r8) :: edsclrm_forcing(pverp,edsclr_dim)! Eddy passive scalar forcing [{units vary}/s]
+ real(r8) :: wpedsclrp_sfc(edsclr_dim) ! Eddy-scalar flux at surface [{units vary} m/s]
+ real(r8) :: sclrm(pverp,sclr_dim) ! Passive scalar mean (thermo. levels) [units vary]
+ real(r8) :: wpsclrp(pverp,sclr_dim) ! w'sclr' (momentum levels) [{units vary} m/s]
+ real(r8) :: sclrp2(pverp,sclr_dim) ! sclr'^2 (momentum levels) [{units vary}^2]
+ real(r8) :: sclrprtp(pverp,sclr_dim) ! sclr'rt' (momentum levels) [{units vary} (kg/kg)]
+ real(r8) :: sclrpthlp(pverp,sclr_dim) ! sclr'thlp' (momentum levels) [{units vary} (K)]
+ real(r8) :: hydromet(pverp,hydromet_dim)
+ real(r8) :: wphydrometp(pverp,hydromet_dim)
+ real(r8) :: wp2hmp(pverp,hydromet_dim)
+ real(r8) :: rtphmp_zt(pverp,hydromet_dim)
+ real(r8) :: thlphmp_zt (pverp,hydromet_dim)
real(r8) :: bflx22 ! Variable for buoyancy flux for pbl [K m/s]
real(r8) :: C_10 ! transfer coefficient [-]
real(r8) :: khzm_out(pverp) ! eddy diffusivity on momentum grids [m^2/s]
@@ -761,6 +1048,10 @@ subroutine clubb_tend_cam( &
real(r8) :: minqn ! minimum total cloud liquid + ice threshold [kg/kg]
real(r8) :: tempqn ! temporary total cloud liquid + ice [kg/kg]
real(r8) :: cldthresh ! threshold to determin cloud fraction [kg/kg]
+ real(r8) :: relvarmax
+ real(r8) :: qmin
+ real(r8) :: varmu(pcols)
+ real(r8) :: varmu2
! Variables below are needed to compute energy integrals for conservation
real(r8) :: ke_a(pcols), ke_b(pcols), te_a(pcols), te_b(pcols)
@@ -770,90 +1061,127 @@ subroutine clubb_tend_cam( &
real(r8) :: exner_clubb(pcols,pverp) ! Exner function consistent with CLUBB [-]
real(r8) :: wpthlp_output(pcols,pverp) ! Heat flux output variable [W/m2]
real(r8) :: wprtp_output(pcols,pverp) ! Total water flux output variable [W/m2]
+ real(r8) :: wp3_output(pcols,pverp) ! wp3 output [m^3/s^3]
+ real(r8) :: rtpthlp_output(pcols,pverp) ! rtpthlp ouptut [K kg/kg]
real(r8) :: qt_output(pcols,pver) ! Total water mixing ratio for output [kg/kg]
real(r8) :: thetal_output(pcols,pver) ! Liquid water potential temperature output [K]
real(r8) :: sl_output(pcols,pver) ! Liquid water static energy [J/kg]
real(r8) :: ustar2(pcols) ! Surface stress for PBL height [m2/s2]
- real(r8) :: rho(pcols,pverp) ! Midpoint density in CAM [kg/m^3]
- real(r8) :: thv(pcols,pver) ! virtual potential temperature [K]
- real(r8) :: edsclr_out(pverp,edsclr_dim) ! Scalars to be diffused through CLUBB [units vary]
- real(r8) :: rcm(pcols,pverp) ! CLUBB cloud water mixing ratio [kg/kg]
- real(r8) :: cloud_frac(pcols,pverp) ! CLUBB cloud fraction [fraction]
- real(r8) :: rcm_in_layer(pcols,pverp) ! CLUBB in-cloud liquid water mixing ratio [kg/kg]
- real(r8) :: cloud_cover(pcols,pverp) ! CLUBB in-cloud cloud fraction [fraction]
- real(r8) :: wprcp(pcols,pverp) ! CLUBB liquid water flux [m/s kg/kg]
- real(r8) :: wpthvp(pcols,pverp) ! CLUBB buoyancy flux [W/m^2]
+ real(r8) :: rho(pcols,pverp) ! Midpoint density in CAM [kg/m^3]
+ real(r8) :: thv(pcols,pver) ! virtual potential temperature [K]
+ real(r8) :: edsclr_out(pverp,edsclr_dim) ! Scalars to be diffused through CLUBB [units vary]
+ real(r8) :: rcm(pcols,pverp) ! CLUBB cloud water mixing ratio [kg/kg]
+ real(r8) :: cloud_frac(pcols,pverp) ! CLUBB cloud fraction [fraction]
+ real(r8) :: rcm_in_layer(pcols,pverp) ! CLUBB in-cloud liquid water mixing ratio [kg/kg]
+ real(r8) :: cloud_cover(pcols,pverp) ! CLUBB in-cloud cloud fraction [fraction]
+ real(r8) :: wprcp(pcols,pverp) ! CLUBB liquid water flux [m/s kg/kg]
+ real(r8) :: wpthvp(pcols,pverp) ! CLUBB buoyancy flux [W/m^2]
+ real(r8) :: rvm(pcols,pverp)
real(r8) :: dlf2(pcols,pver) ! Detraining cld H20 from shallow convection [kg/kg/day]
- real(r8) :: eps ! Rv/Rd [-]
- real(r8) :: dum1 ! dummy variable [units vary]
- real(r8) :: obklen(pcols) ! Obukov length [m]
- real(r8) :: kbfs(pcols) ! Kinematic Surface heat flux [K m/s]
- real(r8) :: th(pcols,pver) ! potential temperature [K]
- real(r8) :: dummy2(pcols) ! dummy variable [units vary]
- real(r8) :: dummy3(pcols) ! dummy variable [units vary]
- real(r8) :: kinheat(pcols) ! Kinematic Surface heat flux [K m/s]
- real(r8) :: ksrftms(pcols) ! Turbulent mountain stress surface drag [kg/s/m2]
- real(r8) :: tautmsx(pcols) ! U component of turbulent mountain stress [N/m2]
- real(r8) :: tautmsy(pcols) ! V component of turbulent mountain stress [N/m2]
- real(r8) :: rrho ! Inverse of air density [1/kg/m^3]
+ real(r8) :: eps ! Rv/Rd [-]
+ real(r8) :: dum1 ! dummy variable [units vary]
+ real(r8) :: obklen(pcols) ! Obukov length [m]
+ real(r8) :: kbfs(pcols) ! Kinematic Surface heat flux [K m/s]
+ real(r8) :: th(pcols,pver) ! potential temperature [K]
+ real(r8) :: dummy2(pcols) ! dummy variable [units vary]
+ real(r8) :: dummy3(pcols) ! dummy variable [units vary]
+ real(r8) :: kinheat(pcols) ! Kinematic Surface heat flux [K m/s]
+ real(r8) :: ksrftms(pcols) ! Turbulent mountain stress surface drag [kg/s/m2]
+ real(r8) :: tautmsx(pcols) ! U component of turbulent mountain stress [N/m2]
+ real(r8) :: tautmsy(pcols) ! V component of turbulent mountain stress [N/m2]
+ real(r8) :: rrho ! Inverse of air density [1/kg/m^3]
real(r8) :: kinwat(pcols) ! Kinematic water vapor flux [m/s]
+ real(r8) :: latsub
+ real(r8) :: qrl_clubb(pverp)
+ real(r8) :: qrl_zm(pverp)
+ real(r8) :: thlp2_rad_out(pverp)
+ real(r8) :: apply_const
+
+ integer :: ktop(pcols,pver)
+ integer :: ncvfin(pcols)
+ real(r8) :: chs(pcols,pverp)
+ real(r8) :: lwp_CL(pver)
+ real(r8) :: opt_depth_CL(pver)
+ real(r8) :: radinvfrac_CL(pver)
+ real(r8) :: radf_CL(pver)
+ real(r8) :: radf_out(pver)
+ real(r8) :: es(pcols,pver)
+ real(r8) :: qs(pcols,pver)
+ real(r8) :: gam(pcols,pver)
+ real(r8) :: bfact, orgparam, delpavg
+ character(len=6) :: choice_radf
- real(kind=time_precision) :: time_elapsed ! time keep track of stats [s]
- real(r8), dimension(nparams) :: clubb_params ! These adjustable CLUBB parameters (C1, C2 ...)
- real(r8), dimension(sclr_dim) :: sclr_tol ! Tolerance on passive scalar [units vary]
- type(pdf_parameter), dimension(pverp) :: pdf_params ! PDF parameters [units vary]
- character(len=200) :: temp1, sub ! Strings needed for CLUBB output
-
- ! --------------- !
- ! Pointers !
- ! --------------- !
-
- real(r8), pointer, dimension(:,:) :: wp2 ! vertical velocity variance [m^2/s^2]
- real(r8), pointer, dimension(:,:) :: wp3 ! third moment of vertical velocity [m^3/s^3]
- real(r8), pointer, dimension(:,:) :: wpthlp ! turbulent flux of thetal [m/s K]
- real(r8), pointer, dimension(:,:) :: wprtp ! turbulent flux of moisture [m/s kg/kg]
- real(r8), pointer, dimension(:,:) :: rtpthlp ! covariance of thetal and qt [kg/kg K]
- real(r8), pointer, dimension(:,:) :: rtp2 ! moisture variance [kg^2/kg^2]
- real(r8), pointer, dimension(:,:) :: thlp2 ! temperature variance [K^2]
- real(r8), pointer, dimension(:,:) :: up2 ! east-west wind variance [m^2/s^2]
- real(r8), pointer, dimension(:,:) :: vp2 ! north-south wind variance [m^2/s^2]
- real(r8), pointer, dimension(:,:) :: upwp ! east-west momentum flux [m^2/s^2]
- real(r8), pointer, dimension(:,:) :: vpwp ! north-south momentum flux [m^2/s^2]
- real(r8), pointer, dimension(:,:) :: thlm ! mean temperature [K]
- real(r8), pointer, dimension(:,:) :: rtm ! mean moisture mixing ratio [kg/kg]
- real(r8), pointer, dimension(:,:) :: um ! mean east-west wind [m/s]
- real(r8), pointer, dimension(:,:) :: vm ! mean north-south wind [m/s]
- real(r8), pointer, dimension(:,:) :: cld ! cloud fraction [fraction]
- real(r8), pointer, dimension(:,:) :: concld ! convective cloud fraction [fraction]
- real(r8), pointer, dimension(:,:) :: ast ! stratiform cloud fraction [fraction]
- real(r8), pointer, dimension(:,:) :: alst ! liquid stratiform cloud fraction [fraction]
- real(r8), pointer, dimension(:,:) :: aist ! ice stratiform cloud fraction [fraction]
- real(r8), pointer, dimension(:,:) :: qlst ! Physical in-stratus LWC [kg/kg]
- real(r8), pointer, dimension(:,:) :: qist ! Physical in-stratus IWC [kg/kg]
- real(r8), pointer, dimension(:,:) :: deepcu ! deep convection cloud fraction [fraction]
- real(r8), pointer, dimension(:,:) :: shalcu ! shallow convection cloud fraction [fraction]
+ integer :: time_elapsed ! time keep track of stats [s]
+ real(r8), dimension(nparams) :: clubb_params ! These adjustable CLUBB parameters (C1, C2 ...)
+ real(r8), dimension(sclr_dim) :: sclr_tol ! Tolerance on passive scalar [units vary]
+ type(pdf_parameter), dimension(pverp) :: pdf_params ! PDF parameters [units vary]
+ character(len=200) :: temp1, sub ! Strings needed for CLUBB output
+ logical :: l_Lscale_plume_centered, l_use_ice_latent
+
+
+ ! --------------- !
+ ! Pointers !
+ ! --------------- !
+
+ real(r8), pointer, dimension(:,:) :: wp2 ! vertical velocity variance [m^2/s^2]
+ real(r8), pointer, dimension(:,:) :: wp3 ! third moment of vertical velocity [m^3/s^3]
+ real(r8), pointer, dimension(:,:) :: wpthlp ! turbulent flux of thetal [m/s K]
+ real(r8), pointer, dimension(:,:) :: wprtp ! turbulent flux of moisture [m/s kg/kg]
+ real(r8), pointer, dimension(:,:) :: rtpthlp ! covariance of thetal and qt [kg/kg K]
+ real(r8), pointer, dimension(:,:) :: rtp2 ! moisture variance [kg^2/kg^2]
+ real(r8), pointer, dimension(:,:) :: thlp2 ! temperature variance [K^2]
+ real(r8), pointer, dimension(:,:) :: up2 ! east-west wind variance [m^2/s^2]
+ real(r8), pointer, dimension(:,:) :: vp2 ! north-south wind variance [m^2/s^2]
+
+ real(r8), pointer, dimension(:,:) :: upwp ! east-west momentum flux [m^2/s^2]
+ real(r8), pointer, dimension(:,:) :: vpwp ! north-south momentum flux [m^2/s^2]
+ real(r8), pointer, dimension(:,:) :: thlm ! mean temperature [K]
+ real(r8), pointer, dimension(:,:) :: rtm ! mean moisture mixing ratio [kg/kg]
+ real(r8), pointer, dimension(:,:) :: um ! mean east-west wind [m/s]
+ real(r8), pointer, dimension(:,:) :: vm ! mean north-south wind [m/s]
+ real(r8), pointer, dimension(:,:) :: cld ! cloud fraction [fraction]
+ real(r8), pointer, dimension(:,:) :: concld ! convective cloud fraction [fraction]
+ real(r8), pointer, dimension(:,:) :: ast ! stratiform cloud fraction [fraction]
+ real(r8), pointer, dimension(:,:) :: alst ! liquid stratiform cloud fraction [fraction]
+ real(r8), pointer, dimension(:,:) :: aist ! ice stratiform cloud fraction [fraction]
+ real(r8), pointer, dimension(:,:) :: qlst ! Physical in-stratus LWC [kg/kg]
+ real(r8), pointer, dimension(:,:) :: qist ! Physical in-stratus IWC [kg/kg]
+ real(r8), pointer, dimension(:,:) :: deepcu ! deep convection cloud fraction [fraction]
+ real(r8), pointer, dimension(:,:) :: shalcu ! shallow convection cloud fraction [fraction]
real(r8), pointer, dimension(:,:) :: khzt ! eddy diffusivity on thermo levels [m^2/s]
real(r8), pointer, dimension(:,:) :: khzm ! eddy diffusivity on momentum levels [m^2/s]
- real(r8), pointer, dimension(:,:) :: pblh ! planetary boundary layer height [m]
+ real(r8), pointer, dimension(:) :: pblh ! planetary boundary layer height [m]
real(r8), pointer, dimension(:,:) :: tke ! turbulent kinetic energy [m^2/s^2]
real(r8), pointer, dimension(:,:) :: dp_icwmr ! deep convection in cloud mixing ratio [kg/kg]
real(r8), pointer, dimension(:,:) :: relvar ! relative cloud water variance [-]
real(r8), pointer, dimension(:,:) :: accre_enhan ! accretion enhancement factor [-]
real(r8), pointer, dimension(:,:) :: cmeliq
+ real(r8), pointer, dimension(:,:) :: cmfmc_sh ! Shallow convective mass flux--m subc (pcols,pverp) [kg/m2/s/]
+
+ real(r8), pointer, dimension(:,:) :: naai
+ real(r8), pointer, dimension(:,:) :: prer_evap
+ real(r8), pointer, dimension(:,:) :: qrl
+ real(r8), pointer, dimension(:,:) :: radf_clubb
+ real(r8) stend(pcols,pver)
+ real(r8) qvtend(pcols,pver)
+ real(r8) qitend(pcols,pver)
+ real(r8) initend(pcols,pver)
logical :: lqice(pcnst)
+
+ integer :: ixorg
intrinsic :: selected_real_kind, max
#endif
det_s(:) = 0.0_r8
det_ice(:) = 0.0_r8
-#if CLUBB_SGS
+#ifdef CLUBB_SGS
!-----------------------------------------------------------------------------------------------!
!-----------------------------------------------------------------------------------------------!
!-----------------------------------------------------------------------------------------------!
- ! MAIN COMPUTATION BEGINS HERE !
+ ! MAIN COMPUTATION BEGINS HERE !
!-----------------------------------------------------------------------------------------------!
!-----------------------------------------------------------------------------------------------!
!-----------------------------------------------------------------------------------------------!
@@ -861,6 +1189,12 @@ subroutine clubb_tend_cam( &
frac_limit = 0.01_r8
ic_limit = 1.e-12_r8
+ if (clubb_do_adv) then
+ apply_const = 1._r8 ! Initialize to one, only if CLUBB's moments are advected
+ else
+ apply_const = 0._r8 ! Never want this if CLUBB's moments are not advected
+ endif
+
! Get indicees for cloud and ice mass and cloud and ice number
call cnst_get_ind('Q',ixq)
@@ -870,11 +1204,19 @@ subroutine clubb_tend_cam( &
call cnst_get_ind('NUMICE',ixnumice)
! Initialize physics tendency arrays, copy the state to state1 array to use in this routine
-
- call physics_ptend_init(ptend_loc,state%psetcols, 'clubb', ls=.true., lu=.true., lv=.true., lq=lq)
+
+ if (.not. micro_do_icesupersat) then
+ call physics_ptend_init(ptend_loc,state%psetcols, 'clubb', ls=.true., lu=.true., lv=.true., lq=lq)
+ endif
call physics_state_copy(state,state1)
+ if (micro_do_icesupersat) then
+ naai_idx = pbuf_get_index('NAAI')
+ call pbuf_get_field(pbuf, naai_idx, naai)
+ call physics_ptend_init(ptend_all, state%psetcols, 'clubb')
+ endif
+
! Determine number of columns and which chunk computation is to be performed on
ncol = state%ncol
@@ -895,14 +1237,17 @@ subroutine clubb_tend_cam( &
call pbuf_get_field(pbuf, thlp2_idx, thlp2, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
call pbuf_get_field(pbuf, up2_idx, up2, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
call pbuf_get_field(pbuf, vp2_idx, vp2, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
+
call pbuf_get_field(pbuf, upwp_idx, upwp, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
call pbuf_get_field(pbuf, vpwp_idx, vpwp, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
call pbuf_get_field(pbuf, thlm_idx, thlm, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
call pbuf_get_field(pbuf, rtm_idx, rtm, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
call pbuf_get_field(pbuf, um_idx, um, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
call pbuf_get_field(pbuf, vm_idx, vm, start=(/1,1,itim_old/), kount=(/pcols,pverp,1/))
-
+
call pbuf_get_field(pbuf, tke_idx, tke)
+ call pbuf_get_field(pbuf, qrl_idx, qrl)
+ call pbuf_get_field(pbuf, radf_idx, radf_clubb)
call pbuf_get_field(pbuf, cld_idx, cld, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
call pbuf_get_field(pbuf, concld_idx, concld, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
@@ -912,6 +1257,7 @@ subroutine clubb_tend_cam( &
call pbuf_get_field(pbuf, qlst_idx, qlst, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
call pbuf_get_field(pbuf, qist_idx, qist, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, prer_evap_idx, prer_evap)
call pbuf_get_field(pbuf, accre_enhan_idx, accre_enhan)
call pbuf_get_field(pbuf, cmeliq_idx, cmeliq)
call pbuf_get_field(pbuf, relvar_idx, relvar)
@@ -921,13 +1267,103 @@ subroutine clubb_tend_cam( &
call pbuf_get_field(pbuf, kvh_idx, khzm)
call pbuf_get_field(pbuf, pblh_idx, pblh)
call pbuf_get_field(pbuf, icwmrdp_idx, dp_icwmr)
+ call pbuf_get_field(pbuf, cmfmc_sh_idx, cmfmc_sh)
+
+ ! Intialize the apply_const variable (note special logic is due to eularian backstepping)
+ if (clubb_do_adv .and. (is_first_step() .or. all(wpthlp(1:ncol,1:pver) .eq. 0._r8))) then
+ apply_const = 0._r8 ! On first time through do not remove constant
+ ! from moments since it has not been added yet
+ endif
+
+ if (micro_do_icesupersat) then
- ! Determine CLUBB time step based on host model time step
- ! Current algorithm is to always allow at least 4 CLUBB timesteps per host model
- ! timestep. However, a maximum timestep of 300 s and a minimum timestep of 60 s
- ! is imposed.
- dtime=max(min((1.0_r8*hdtime)/4.0_r8,300.0_r8),60.0_r8)
+ ! -------------------------------------- !
+ ! Ice Saturation Adjustment Computation !
+ ! -------------------------------------- !
+ lq2(:) = .FALSE.
+ lq2(1) = .TRUE.
+ lq2(ixcldice) = .TRUE.
+ lq2(ixnumice) = .TRUE.
+
+ latsub = latvap + latice
+
+ call physics_ptend_init(ptend_loc, state%psetcols, 'iceadj', ls=.true., lq=lq2 )
+
+ stend(:ncol,:)=0._r8
+ qvtend(:ncol,:)=0._r8
+ qitend(:ncol,:)=0._r8
+ initend(:ncol,:)=0._r8
+
+ call ice_macro_tend(naai(:ncol,top_lev:pver),state1%t(:ncol,top_lev:pver), &
+ state1%pmid(:ncol,top_lev:pver),state1%q(:ncol,top_lev:pver,1),state1%q(:ncol,top_lev:pver,ixcldice),&
+ state1%q(:ncol,top_lev:pver,ixnumice),latsub,hdtime,&
+ stend(:ncol,top_lev:pver),qvtend(:ncol,top_lev:pver),qitend(:ncol,top_lev:pver),&
+ initend(:ncol,top_lev:pver))
+
+ ! update local copy of state with the tendencies
+ ptend_loc%q(:ncol,top_lev:pver,1)=qvtend(:ncol,top_lev:pver)
+ ptend_loc%q(:ncol,top_lev:pver,ixcldice)=qitend(:ncol,top_lev:pver)
+ ptend_loc%q(:ncol,top_lev:pver,ixnumice)=initend(:ncol,top_lev:pver)
+ ptend_loc%s(:ncol,top_lev:pver)=stend(:ncol,top_lev:pver)
+
+ ! Add the ice tendency to the output tendency
+ call physics_ptend_sum(ptend_loc, ptend_all, ncol)
+
+ ! ptend_loc is reset to zero by this call
+ call physics_update(state1, ptend_loc, hdtime)
+
+ !Write output for tendencies:
+ ! oufld: QVTENDICE,QITENDICE,NITENDICE
+ call outfld( 'TTENDICE', stend/cpair, pcols, lchnk )
+ call outfld( 'QVTENDICE', qvtend, pcols, lchnk )
+ call outfld( 'QITENDICE', qitend, pcols, lchnk )
+ call outfld( 'NITENDICE', initend, pcols, lchnk )
+
+ endif
+
+ ! Determine CLUBB time step and make it sub-step friendly
+ ! For now we want CLUBB time step to be 5 min since that is
+ ! what has been scientifically validated. However, there are certain
+ ! instances when a 5 min time step will not be possible (based on
+ ! host model time step or on macro-micro sub-stepping
+
+ dtime = clubb_timestep
+
+ ! Now check to see if dtime is greater than the host model
+ ! (or sub stepped) time step. If it is, then simply
+ ! set it equal to the host (or sub step) time step.
+ ! This section is mostly to deal with small host model
+ ! time steps (or small sub-steps)
+
+ if (dtime .gt. hdtime) then
+ dtime = hdtime
+ endif
+
+ ! Now check to see if CLUBB time step divides evenly into
+ ! the host model time step. If not, force it to divide evenly.
+ ! We also want it to be 5 minutes or less. This section is
+ ! mainly for host model time steps that are not evenly divisible
+ ! by 5 minutes
+
+ if (mod(hdtime,dtime) .ne. 0) then
+ dtime = hdtime/2._r8
+ do while (dtime .gt. 300._r8)
+ dtime = dtime/2._r8
+ end do
+ endif
+
+ ! If resulting host model time step and CLUBB time step do not divide evenly
+ ! into each other, have model throw a fit.
+
+ if (mod(hdtime,dtime) .ne. 0) then
+ call endrun('clubb_tend_cam: CLUBB time step and HOST time step NOT compatible')
+ endif
+
+ ! determine number of timesteps CLUBB core should be advanced,
+ ! host time step divided by CLUBB time step
+ nadv = max(hdtime/dtime,1._r8)
+
! Initialize forcings for transported scalars to zero
sclrm_forcing(:,:) = 0._r8
@@ -939,10 +1375,6 @@ subroutine clubb_tend_cam( &
where(state1%q(:ncol,:pver,3) .gt. minqn) &
newfice(:ncol,:pver) = state1%q(:ncol,:pver,3)/(state1%q(:ncol,:pver,2)+state1%q(:ncol,:pver,3))
- ! determine number of timesteps CLUBB core should be advanced,
- ! host time step divided by CLUBB time step
- nadv = max(hdtime/dtime,1._r8)
-
! Compute exner function consistent with CLUBB's definition, which uses a constant
! surface pressure. CAM's exner (in state does not). Therefore, for consistent
! treatment with CLUBB code, anytime exner is needed to treat CLUBB variables
@@ -960,18 +1392,59 @@ subroutine clubb_tend_cam( &
do k=1,pver ! loop over levels
do i=1,ncol ! loop over columns
- rtm(i,k) = state1%q(i,k,ixq)+state1%q(i,k,ixcldliq)
- um(i,k) = state1%u(i,k)
- vm(i,k) = state1%v(i,k)
- thlm(i,k) = state1%t(i,k)*exner_clubb(i,k)-(latvap/cpair)*state1%q(i,k,ixcldliq)
-
+ rtm(i,k) = state1%q(i,k,ixq)+state1%q(i,k,ixcldliq)
+ rvm(i,k) = state1%q(i,k,ixq)
+ um(i,k) = state1%u(i,k)
+ vm(i,k) = state1%v(i,k)
+ thlm(i,k) = state1%t(i,k)*exner_clubb(i,k)-(latvap/cpair)*state1%q(i,k,ixcldliq)
+
+ if (clubb_do_adv) then
+ if (macmic_it .eq. 1) then
+
+ ! Note that some of the moments below can be positive or negative.
+ ! Remove a constant that was added to prevent dynamics from clipping
+ ! them to prevent dynamics from making them positive.
+ thlp2(i,k) = state1%q(i,k,ixthlp2)
+ rtp2(i,k) = state1%q(i,k,ixrtp2)
+ rtpthlp(i,k) = state1%q(i,k,ixrtpthlp) - (rtpthlp_const*apply_const)
+ wpthlp(i,k) = state1%q(i,k,ixwpthlp) - (wpthlp_const*apply_const)
+ wprtp(i,k) = state1%q(i,k,ixwprtp) - (wprtp_const*apply_const)
+ wp2(i,k) = state1%q(i,k,ixwp2)
+ wp3(i,k) = state1%q(i,k,ixwp3) - (wp3_const*apply_const)
+ up2(i,k) = state1%q(i,k,ixup2)
+ vp2(i,k) = state1%q(i,k,ixvp2)
+ endif
+ endif
+
enddo
enddo
+
+ if (clubb_do_adv) then
+ ! If not last step of macmic loop then set apply_const back to
+ ! zero to prevent output from being corrupted.
+ if (macmic_it .eq. cld_macmic_num_steps) then
+ apply_const = 1._r8
+ else
+ apply_const = 0._r8
+ endif
+ endif
rtm(1:ncol,pverp) = rtm(1:ncol,pver)
um(1:ncol,pverp) = state1%u(1:ncol,pver)
vm(1:ncol,pverp) = state1%v(1:ncol,pver)
thlm(1:ncol,pverp) = thlm(1:ncol,pver)
+
+ if (clubb_do_adv) then
+ thlp2(1:ncol,pverp)=thlp2(1:ncol,pver)
+ rtp2(1:ncol,pverp)=rtp2(1:ncol,pver)
+ rtpthlp(1:ncol,pverp)=rtpthlp(1:ncol,pver)
+ wpthlp(1:ncol,pverp)=wpthlp(1:ncol,pver)
+ wprtp(1:ncol,pverp)=wprtp(1:ncol,pver)
+ wp2(1:ncol,pverp)=wp2(1:ncol,pver)
+ wp3(1:ncol,pverp)=wp3(1:ncol,pver)
+ up2(1:ncol,pverp)=up2(1:ncol,pver)
+ vp2(1:ncol,pverp)=vp2(1:ncol,pver)
+ endif
! Compute integrals of static energy, kinetic energy, water vapor, and liquid water
! for the computation of total energy before CLUBB is called. This is for an
@@ -992,24 +1465,28 @@ subroutine clubb_tend_cam( &
! Compute virtual potential temperature, which is needed for CLUBB
do k=1,pver
- do i=1,ncol
+ do i=1,ncol
thv(i,k) = state1%t(i,k)*exner_clubb(i,k)*(1._r8+zvir*state1%q(i,k,ixq)&
-state1%q(i,k,ixcldliq))
enddo
enddo
! ------------------------------------------------- !
- ! Begin module to compute turbulent mountain stress !
+ ! Begin module to compute turbulent mountain stress !
! ------------------------------------------------- !
call compute_tms( pcols, pver, ncol, &
state1%u, state1%v, state1%t, state1%pmid, &
- state1%exner, state1%zm, sgh30, ksrftms, &
- tautmsx, tautmsy, cam_in%landfrac )
-
+ state1%exner, state1%zm, sgh30, ksrftms, &
+ tautmsx, tautmsy, cam_in%landfrac )
+
+ if (micro_do_icesupersat) then
+ call physics_ptend_init(ptend_loc,state%psetcols, 'clubb', ls=.true., lu=.true., lv=.true., lq=lq)
+ endif
+
+ ! ------------------------------------------------- !
+ ! End module to compute turbulent mountain stress !
! ------------------------------------------------- !
- ! End module to compute turbulent mountain stress !
- ! ------------------------------------------------- !
! Loop over all columns in lchnk to advance CLUBB core
do i=1,ncol ! loop over columns
@@ -1031,7 +1508,7 @@ subroutine clubb_tend_cam( &
! Define the CLUBB thermodynamic grid (in units of m)
do k=1,pver
zt_g(k+1) = state1%zm(i,pver-k+1)-state1%zi(i,pver+1)
- dz_g(k) = state1%zi(i,k)-state1%zi(i,k+1) ! compute thickness
+ dz_g(k) = state1%zi(i,k)-state1%zi(i,k+1) ! compute thickness
enddo
! Thermodynamic ghost point is below surface
@@ -1049,6 +1526,9 @@ subroutine clubb_tend_cam( &
invrs_rho_ds_zt(k+1) = 1._r8/(rho_ds_zt(k+1)) ! Inverse ds rho at thermo
rho(i,k+1) = rho_ds_zt(k+1) ! rho on thermo
thv_ds_zt(k+1) = thv(i,pver-k+1) ! thetav on thermo
+ rfrzm(k+1) = state1%q(i,pver-k+1,ixcldice)
+ radf(k+1) = radf_clubb(i,pver-k+1)
+ qrl_clubb(k+1) = qrl(i,pver-k+1)/(cpair*state1%pdel(i,pver-k+1))
enddo
! Below computes the same stuff for the ghost point. May or may
@@ -1060,6 +1540,9 @@ subroutine clubb_tend_cam( &
rho_zt(:) = rho(i,:)
p_in_Pa(1) = p_in_Pa(2)
exner(1) = exner(2)
+ rfrzm(1) = rfrzm(2)
+ radf(1) = radf(2)
+ qrl_clubb(1) = qrl_clubb(2)
! Compute mean w wind on thermo grid, convert from omega to w
wm_zt(1) = 0._r8
@@ -1067,19 +1550,13 @@ subroutine clubb_tend_cam( &
wm_zt(k+1) = -1._r8*state1%omega(i,pver-k+1)/(rho(i,k+1)*gravit)
enddo
- ! Surface fluxes provided by host model
- wpthlp_sfc = cam_in%shf(i)/(cpair*rho(i,1)) ! Sensible heat flux
- wprtp_sfc = cam_in%lhf(i)/(latvap*rho(i,1)) ! Latent heat flux
- upwp_sfc = cam_in%wsx(i)/rho(i,1) ! Surface meridional momentum flux
- vpwp_sfc = cam_in%wsy(i)/rho(i,1) ! Surface zonal momentum flux
-
- ! ------------------------------------------------- !
- ! Begin case specific code for SCAM cases. !
- ! This section of code block NOT called in !
- ! global simulations !
- ! ------------------------------------------------- !
+ ! ------------------------------------------------- !
+ ! Begin case specific code for SCAM cases. !
+ ! This section of code block NOT called in !
+ ! global simulations !
+ ! ------------------------------------------------- !
- if (single_column) then
+ if (single_column) then
! Initialize zo if variable ustar is used
@@ -1099,28 +1576,16 @@ subroutine clubb_tend_cam( &
! Define ustar (based on case, if not variable)
ustar = 0.25_r8 ! Initialize ustar in case no case
- if(trim(scm_clubb_iop_name) .eq. 'DYCOMSrf01_4day') then
- ustar = 0.25_r8
- endif
-
- if(trim(scm_clubb_iop_name) .eq. 'DYCOMSrf02_06hr') then
- ustar = 0.25_r8
- endif
-
if(trim(scm_clubb_iop_name) .eq. 'BOMEX_5day') then
ustar = 0.28_r8
endif
if(trim(scm_clubb_iop_name) .eq. 'ATEX_48hr') then
- ustar = 0.30_r8
- wpthlp_sfc = 3.0_r8/(cpair*rho(i,1))
- wprtp_sfc = 110.0_r8/(latvap*rho(i,1))
+ ustar = 0.30_r8
endif
if(trim(scm_clubb_iop_name) .eq. 'RICO_3day') then
- ustar = 0.28_r8
- wpthlp_sfc = 9.5_r8/(cpair*rho(i,1))
- wprtp_sfc = 138.0_r8/(latvap*rho(i,1))
+ ustar = 0.28_r8
endif
if(trim(scm_clubb_iop_name) .eq. 'arm97' .or. trim(scm_clubb_iop_name) .eq. 'gate' .or. &
@@ -1131,283 +1596,488 @@ subroutine clubb_tend_cam( &
ustar = diag_ustar(zt_g(2),bflx22,ubar,zo)
endif
- if(trim(scm_clubb_iop_name) .eq. 'gate') then
- C_10 = 0.0013_r8
- wpthlp_sfc = -C_10*ubar*(thlm(1,pver)-300.5_r8*(1000._r8/1015._r8)**(rair/cpair))
- wprtp_sfc = -C_10*ubar*(rtm(1,pver)-0.0198293_r8)
- endif
-
! Compute the surface momentum fluxes, if this is a SCAM simulation
upwp_sfc = -um(i,pver)*ustar**2/ubar
vpwp_sfc = -vm(i,pver)*ustar**2/ubar
- endif
+ endif
- ! ------------------------------------------------- !
- ! End case specific code for SCAM cases !
- ! ------------------------------------------------- !
-
- ! ------------------------------------------------- !
- ! Apply TMS !
- ! ------------------------------------------------- !
+ ! Define surface sources for transported variables for diffusion, will
+ ! be zero as these tendencies are done in clubb_surface
+ do ixind=1,edsclr_dim
+ wpedsclrp_sfc(ixind) = 0._r8
+ enddo
+
+ ! Define forcings from CAM to CLUBB as zero for momentum and thermo,
+ ! forcings already applied through CAM
+ thlm_forcing(1:pverp) = 0._r8
+ rtm_forcing(1:pverp) = 0._r8
+ um_forcing(1:pverp) = 0._r8
+ vm_forcing(1:pverp) = 0._r8
+
+ wprtp_forcing(1:pverp) = 0._r8
+ wpthlp_forcing(1:pverp) = 0._r8
+ rtp2_forcing(1:pverp) = 0._r8
+ thlp2_forcing(1:pverp) = 0._r8
+ rtpthlp_forcing(1:pverp) = 0._r8
+
+ ice_supersat_frac(1:pverp) = 0._r8
+
+ ! Set stats output and increment equal to CLUBB and host dt
+ stats_tsamp = dtime
+ stats_tout = hdtime
+
+ ! Heights need to be set at each timestep. Therefore, recall
+ ! setup_grid and setup_parameters for this.
+
+ ! Read in parameters for CLUBB. Just read in default values
+ call read_parameters( -99, "", clubb_params )
+
+ ! Set-up CLUBB core at each CLUBB call because heights can change
+ call setup_grid(pverp, sfc_elevation, l_implemented, grid_type, &
+ zi_g(2), zi_g(1), zi_g(pverp), zi_g(1:pverp), zt_g(1:pverp), &
+ begin_height, end_height)
+
+ call setup_parameters(zi_g(2), clubb_params, pverp, grid_type, &
+ zi_g(begin_height:end_height), zt_g(begin_height:end_height), err_code)
+
+ ! Compute some inputs from the thermodynamic grid
+ ! to the momentum grid
+ rho_ds_zm = zt2zm(rho_ds_zt)
+ rho_zm = zt2zm(rho_zt)
+ invrs_rho_ds_zm = zt2zm(invrs_rho_ds_zt)
+ thv_ds_zm = zt2zm(thv_ds_zt)
+ wm_zm = zt2zm(wm_zt)
- upwp_sfc = upwp_sfc-((ksrftms(i)*state1%u(i,pver))/rho(i,1))
- vpwp_sfc = vpwp_sfc-((ksrftms(i)*state1%v(i,pver))/rho(i,1))
-
- ! Define surface sources for transported variables for diffusion, will
- ! be zero as these tendencies are done in clubb_surface
- do ixind=1,edsclr_dim
- wpedsclrp_sfc(ixind) = 0._r8
- enddo
-
- ! Define forcings from CAM to CLUBB as zero for momentum and thermo,
- ! forcings already applied through CAM
- thlm_forcing(1:pverp) = 0._r8
- rtm_forcing(1:pverp) = 0._r8
- um_forcing(1:pverp) = 0._r8
- vm_forcing(1:pverp) = 0._r8
-
- ! Set stats output and increment equal to CLUBB and host dt
- stats_tsamp = dtime
- stats_tout = hdtime
-
- ! Heights need to be set at each timestep. Therefore, recall
- ! setup_grid and setup_parameters for this.
-
- ! Read in parameters for CLUBB. Just read in default values
- call read_parameters( -99, "", clubb_params )
-
- ! Set-up CLUBB core at each CLUBB call because heights can change
- call setup_grid(pverp, sfc_elevation, l_implemented, grid_type, &
- zi_g(2), zi_g(1), zi_g(pverp), zi_g(1:pverp), zt_g(1:pverp), &
- begin_height, end_height)
-
- call setup_parameters(zi_g(2), clubb_params, pverp, grid_type, &
- zi_g(begin_height:end_height), zt_g(begin_height:end_height), err_code)
-
- ! Compute some inputs from the thermodynamic grid
- ! to the momentum grid
- rho_ds_zm = zt2zm(rho_ds_zt)
- rho_zm = zt2zm(rho_zt)
- invrs_rho_ds_zm = zt2zm(invrs_rho_ds_zt)
- thv_ds_zm = zt2zm(thv_ds_zt)
- wm_zm = zt2zm(wm_zt)
+ ! Surface fluxes provided by host model
+ wpthlp_sfc = cam_in%shf(i)/(cpair*rho_ds_zm(1)) ! Sensible heat flux
+ wprtp_sfc = cam_in%lhf(i)/(latvap*rho_ds_zm(1)) ! Latent heat flux
+ upwp_sfc = cam_in%wsx(i)/rho_ds_zm(1) ! Surface meridional momentum flux
+ vpwp_sfc = cam_in%wsy(i)/rho_ds_zm(1) ! Surface zonal momentum flux
+
+ ! ------------------------------------------------- !
+ ! Apply TMS !
+ ! ------------------------------------------------- !
+
+ upwp_sfc = upwp_sfc-((ksrftms(i)*state1%u(i,pver))/rho_ds_zm(1))
+ vpwp_sfc = vpwp_sfc-((ksrftms(i)*state1%v(i,pver))/rho_ds_zm(1))
+
+ ! Need to flip arrays around for CLUBB core
+ do k=1,pverp
+ um_in(k) = um(i,pverp-k+1)
+ vm_in(k) = vm(i,pverp-k+1)
+ upwp_in(k) = upwp(i,pverp-k+1)
+ vpwp_in(k) = vpwp(i,pverp-k+1)
+ up2_in(k) = up2(i,pverp-k+1)
+ vp2_in(k) = vp2(i,pverp-k+1)
+ wp2_in(k) = wp2(i,pverp-k+1)
+ wp3_in(k) = wp3(i,pverp-k+1)
+ rtp2_in(k) = rtp2(i,pverp-k+1)
+ thlp2_in(k) = thlp2(i,pverp-k+1)
+ thlm_in(k) = thlm(i,pverp-k+1)
+ rtm_in(k) = rtm(i,pverp-k+1)
+ rvm_in(k) = rvm(i,pverp-k+1)
+ wprtp_in(k) = wprtp(i,pverp-k+1)
+ wpthlp_in(k) = wpthlp(i,pverp-k+1)
+ rtpthlp_in(k) = rtpthlp(i,pverp-k+1)
- ! Need to flip arrays around for CLUBB core
- do k=1,pverp
- um_in(k) = um(i,pverp-k+1)
- vm_in(k) = vm(i,pverp-k+1)
- upwp_in(k) = upwp(i,pverp-k+1)
- vpwp_in(k) = vpwp(i,pverp-k+1)
- up2_in(k) = up2(i,pverp-k+1)
- vp2_in(k) = vp2(i,pverp-k+1)
- wp2_in(k) = wp2(i,pverp-k+1)
- wp3_in(k) = wp3(i,pverp-k+1)
- rtp2_in(k) = rtp2(i,pverp-k+1)
- thlp2_in(k) = thlp2(i,pverp-k+1)
- thlm_in(k) = thlm(i,pverp-k+1)
- rtm_in(k) = rtm(i,pverp-k+1)
- wprtp_in(k) = wprtp(i,pverp-k+1)
- wpthlp_in(k) = wpthlp(i,pverp-k+1)
- rtpthlp_in(k) = rtpthlp(i,pverp-k+1)
-
- ! Initialize these to prevent crashing behavior
- rcm_out(k) = 0._r8
- wprcp_out(k) = 0._r8
- cloud_frac_out(k) = 0._r8
- rcm_in_layer_out(k) = 0._r8
- cloud_cover_out(k) = 0._r8
- edsclr_in(k,:) = 0._r8
- edsclr_out(k,:) = 0._r8
- khzm_out(k) = 0._r8
- khzt_out(k) = 0._r8
-
- ! higher order scalar stuff, put to zero
- sclrm(k,:) = 0._r8
- wpsclrp(k,:) = 0._r8
- sclrp2(k,:) = 0._r8
- sclrprtp(k,:) = 0._r8
- sclrpthlp(k,:) = 0._r8
- wpsclrp_sfc(:) = 0._r8
-
- enddo
+ if (k .ne. 1) then
+ pre_in(k) = prer_evap(i,pverp-k+1)
+ endif
+
+ ! Initialize these to prevent crashing behavior
+ rcm_out(k) = 0._r8
+ wprcp_out(k) = 0._r8
+ cloud_frac_out(k) = 0._r8
+ rcm_in_layer_out(k) = 0._r8
+ cloud_cover_out(k) = 0._r8
+ edsclr_in(k,:) = 0._r8
+ edsclr_out(k,:) = 0._r8
+ khzm_out(k) = 0._r8
+ khzt_out(k) = 0._r8
+
+ ! higher order scalar stuff, put to zero
+ sclrm(k,:) = 0._r8
+ wpsclrp(k,:) = 0._r8
+ sclrp2(k,:) = 0._r8
+ sclrprtp(k,:) = 0._r8
+ sclrpthlp(k,:) = 0._r8
+ wpsclrp_sfc(:) = 0._r8
+ hydromet(k,:) = 0._r8
+ wphydrometp(k,:) = 0._r8
+ wp2hmp(k,:) = 0._r8
+ rtphmp_zt(k,:) = 0._r8
+ thlphmp_zt(k,:) = 0._r8
+
+ enddo
+
+ pre_in(1) = pre_in(2)
+
+ if (clubb_do_adv) then
+ if (macmic_it .eq. 1) then
+ wp2_in=zt2zm(wp2_in)
+ wpthlp_in=zt2zm(wpthlp_in)
+ wprtp_in=zt2zm(wprtp_in)
+ up2_in=zt2zm(up2_in)
+ vp2_in=zt2zm(vp2_in)
+ thlp2_in=zt2zm(thlp2_in)
+ rtp2_in=zt2zm(rtp2_in)
+ rtpthlp_in=zt2zm(rtpthlp_in)
+
+ do k=1,pverp
+ thlp2_in(k)=max(thl_tol**2,thlp2_in(k))
+ rtp2_in(k)=max(rt_tol**2,rtp2_in(k))
+ wp2_in(k)=max(w_tol_sqd,wp2_in(k))
+ up2_in(k)=max(w_tol_sqd,up2_in(k))
+ vp2_in(k)=max(w_tol_sqd,vp2_in(k))
+ enddo
+ endif
+ endif
+
+ ! Do the same for tracers
+ icnt=0
+ do ixind=1,pcnst
+ if (lq(ixind)) then
+ icnt=icnt+1
+ do k=1,pver
+ edsclr_in(k+1,icnt) = state1%q(i,pver-k+1,ixind)
+ enddo
+ edsclr_in(1,icnt) = edsclr_in(2,icnt)
+ end if
+ enddo
+
+ if (do_expldiff) then
+ do k=1,pver
+ edsclr_in(k+1,icnt+1) = thlm(i,pver-k+1)
+ edsclr_in(k+1,icnt+2) = rtm(i,pver-k+1)
+ enddo
+
+ edsclr_in(1,icnt+1) = edsclr_in(2,icnt+1)
+ edsclr_in(1,icnt+2) = edsclr_in(2,icnt+2)
+ endif
- ! Do the same for tracers
- icnt=0
- do ixind=1,pcnst
- if (lq(ixind)) then
- icnt=icnt+1
- do k=1,pver
- edsclr_in(k+1,icnt) = state1%q(i,pver-k+1,ixind)
- enddo
- edsclr_in(1,icnt) = edsclr_in(2,icnt)
- end if
- enddo
-
- rho_in(:) = rho(i,:)
+ rho_in(:) = rho(i,:)
+
+ ! --------------------------------------------------------- !
+ ! Compute cloud-top radiative cooling contribution to CLUBB !
+ ! --------------------------------------------------------- !
+
+ ! Sandbox version of code to take into account meso organization
+
+ if (clubb_do_deep) then
+ orgparam = 0._r8
+ delpavg = 0._r8
+
+ do k = 1, pver
+ if (abs(prer_evap(i,k)) .gt. 0._r8) then
+ orgparam = orgparam + (abs(prer_evap(i,k)) * 1000._r8 * 1000._r8 * 2._r8 ) * state1%pdel(i,k)
+ delpavg = delpavg + state1%pdel(i,k)
+ endif
+ enddo
+
+ if (delpavg .gt. 0._r8) then
+ orgparam = orgparam/delpavg
+ endif
+
+ ! Now compute new entrainment rate based on organization
+ varmu2 = mu / (1._r8 + orgparam * 100._r8)
+ varmu(i) = varmu2
+
+ endif
- do t=1,nadv ! do needed number of "sub" timesteps for each CAM step
-
- ! Increment the statistics then being stats timestep
- if (l_stats) then
- time_elapsed = time_elapsed+dtime
- call stats_begin_timestep(time_elapsed)
- endif
+ ! --------------------------------------------------------- !
+ ! End cloud-top radiative cooling contribution to CLUBB !
+ ! --------------------------------------------------------- !
+
+ do t=1,nadv ! do needed number of "sub" timesteps for each CAM step
+
+ ! Increment the statistics then being stats timestep
+ if (l_stats) then
+ time_elapsed = time_elapsed+dtime
+ call stats_begin_timestep(time_elapsed, 1, 1)
+ endif
+
+ ! Advance CLUBB CORE one timestep in the future
+ call advance_clubb_core &
+ ( l_implemented, dtime, fcor, sfc_elevation, hydromet_dim, &
+ thlm_forcing, rtm_forcing, um_forcing, vm_forcing, &
+ sclrm_forcing, edsclrm_forcing, wprtp_forcing, &
+ wpthlp_forcing, rtp2_forcing, thlp2_forcing, &
+ rtpthlp_forcing, wm_zm, wm_zt, &
+ wpthlp_sfc, wprtp_sfc, upwp_sfc, vpwp_sfc, &
+ wpsclrp_sfc, wpedsclrp_sfc, &
+ p_in_Pa, rho_zm, rho_in, exner, &
+ rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
+ invrs_rho_ds_zt, thv_ds_zm, thv_ds_zt, hydromet, &
+ rfrzm, radf, do_expldiff, &
+#ifdef CLUBBND_CAM
+ varmu2, &
+#endif
+ wphydrometp, wp2hmp, rtphmp_zt, thlphmp_zt, &
+ host_dx, host_dy, &
+ um_in, vm_in, upwp_in, &
+ vpwp_in, up2_in, vp2_in, &
+ thlm_in, rtm_in, wprtp_in, wpthlp_in, &
+ wp2_in, wp3_in, rtp2_in, &
+ thlp2_in, rtpthlp_in, &
+ sclrm, sclrp2, sclrprtp, sclrpthlp, &
+ wpsclrp, edsclr_in, err_code, &
+ rcm_out, wprcp_out, cloud_frac_out, ice_supersat_frac, &
+ rcm_in_layer_out, cloud_cover_out, &
+ khzm_out, khzt_out, qclvar_out, thlprcp_out, &
+ pdf_params)
+
+ if (do_rainturb) then
+ rvm_in = rtm_in - rcm_out
+ call update_xp2_mc(pverp, dtime, cloud_frac_out, &
+ rcm_out, rvm_in, thlm_in, wm_zt, exner, pre_in, pdf_params, &
+ rtp2_mc_out, thlp2_mc_out, &
+ wprtp_mc_out, wpthlp_mc_out, &
+ rtpthlp_mc_out)
+
+ if (clubb_do_deep) then
+ dum1 = 1._r8
+ else
+ dum1 = (1._r8 - cam_in%landfrac(i))
+ end if
+
+ ! update turbulent moments based on rain evaporation
+ rtp2_in = rtp2_in + clubb_rnevap_effic * dum1 * rtp2_mc_out * dtime
+ thlp2_in = thlp2_in + clubb_rnevap_effic * dum1 * thlp2_mc_out * dtime
+ if (.not. clubb_do_deep) then
+ wprtp_in = wprtp_in + clubb_rnevap_effic * dum1 * wprtp_mc_out * dtime
+ wpthlp_in = wpthlp_in + clubb_rnevap_effic * dum1 * wpthlp_mc_out * dtime
+ endif
+! rtpthlp_in = rtpthlp_in + rtpthlp_mc_out * dtime
+ endif
+
+ if (do_cldcool) then
+
+ rcm_out_zm = zt2zm(rcm_out)
+ qrl_zm = zt2zm(qrl_clubb)
+ thlp2_rad_out(:) = 0._r8
+ call calculate_thlp2_rad(pverp, rcm_out_zm, thlprcp_out, qrl_zm, thlp2_rad_out)
+ thlp2_in = thlp2_in + thlp2_rad_out * dtime
+ thlp2_in = max(thl_tol**2,thlp2_in)
+ endif
- ! Advance CLUBB CORE one timestep in the future
- call advance_clubb_core &
- ( l_implemented, dtime, fcor, sfc_elevation, &
- thlm_forcing, rtm_forcing, um_forcing, vm_forcing, &
- sclrm_forcing, edsclrm_forcing,&
- wm_zm, wm_zt, &
- wpthlp_sfc, wprtp_sfc, upwp_sfc, vpwp_sfc, &
- wpsclrp_sfc, wpedsclrp_sfc, &
- p_in_Pa, rho_zm, rho_in, exner, &
- rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
- invrs_rho_ds_zt, thv_ds_zm, thv_ds_zt, &
- um_in, vm_in, upwp_in, &
- vpwp_in, up2_in, vp2_in, &
- thlm_in, rtm_in, wprtp_in, wpthlp_in, &
- wp2_in, wp3_in, rtp2_in, &
- thlp2_in, rtpthlp_in, &
- sclrm, sclrp2, sclrprtp, sclrpthlp, &
- wpsclrp, edsclr_in, err_code, &
- rcm_out, wprcp_out, cloud_frac_out, &
- rcm_in_layer_out, cloud_cover_out, &
- khzm_out, khzt_out, qclvar_out, &
- pdf_params)
-
- ! Check to see if stats should be output, here stats are read into
- ! output arrays to make them conformable to CAM output
- if (l_stats) call stats_end_timestep_clubb(lchnk,i,out_zt,out_zm,&
- out_radzt,out_radzm,out_sfc)
-
- enddo ! end time loop
-
- call cleanup_grid()
+ ! Check to see if stats should be output, here stats are read into
+ ! output arrays to make them conformable to CAM output
+ if (l_stats) call stats_end_timestep_clubb(lchnk,i,out_zt,out_zm,&
+ out_radzt,out_radzm,out_sfc)
+
+ enddo ! end time loop
+
+ if (clubb_do_adv) then
+ if (macmic_it .eq. cld_macmic_num_steps) then
+ wp2_in=zm2zt(wp2_in)
+ wpthlp_in=zm2zt(wpthlp_in)
+ wprtp_in=zm2zt(wprtp_in)
+ up2_in=zm2zt(up2_in)
+ vp2_in=zm2zt(vp2_in)
+ thlp2_in=zm2zt(thlp2_in)
+ rtp2_in=zm2zt(rtp2_in)
+ rtpthlp_in=zm2zt(rtpthlp_in)
+
+ do k=1,pverp
+ thlp2_in(k)=max(thl_tol**2,thlp2_in(k))
+ rtp2_in(k)=max(rt_tol**2,rtp2_in(k))
+ wp2_in(k)=max(w_tol_sqd,wp2_in(k))
+ up2_in(k)=max(w_tol_sqd,up2_in(k))
+ vp2_in(k)=max(w_tol_sqd,vp2_in(k))
+ enddo
+ endif
+ endif
+
+ call cleanup_grid()
- ! Arrays need to be "flipped" to CAM grid
- do k=1,pverp
+ ! Arrays need to be "flipped" to CAM grid
+ do k=1,pverp
- um(i,k) = um_in(pverp-k+1)
- vm(i,k) = vm_in(pverp-k+1)
- upwp(i,k) = upwp_in(pverp-k+1)
- vpwp(i,k) = vpwp_in(pverp-k+1)
- up2(i,k) = up2_in(pverp-k+1)
- vp2(i,k) = vp2_in(pverp-k+1)
- thlm(i,k) = thlm_in(pverp-k+1)
- rtm(i,k) = rtm_in(pverp-k+1)
- wprtp(i,k) = wprtp_in(pverp-k+1)
- wpthlp(i,k) = wpthlp_in(pverp-k+1)
- wp2(i,k) = wp2_in(pverp-k+1)
- wp3(i,k) = wp3_in(pverp-k+1)
- rtp2(i,k) = rtp2_in(pverp-k+1)
- thlp2(i,k) = thlp2_in(pverp-k+1)
- rtpthlp(i,k) = rtpthlp_in(pverp-k+1)
- rcm(i,k) = rcm_out(pverp-k+1)
- wprcp(i,k) = wprcp_out(pverp-k+1)
- cloud_frac(i,k) = min(cloud_frac_out(pverp-k+1),1._r8)
- rcm_in_layer(i,k) = rcm_in_layer_out(pverp-k+1)
- cloud_cover(i,k) = min(cloud_cover_out(pverp-k+1),1._r8)
- zt_out(i,k) = zt_g(pverp-k+1)
- zi_out(i,k) = zi_g(pverp-k+1)
- khzm(i,k) = khzm_out(pverp-k+1)
- khzt(i,k) = khzt_out(pverp-k+1)
- qclvar(i,k) = min(1._r8,qclvar_out(pverp-k+1))
+ um(i,k) = um_in(pverp-k+1)
+ vm(i,k) = vm_in(pverp-k+1)
+ upwp(i,k) = upwp_in(pverp-k+1)
+ vpwp(i,k) = vpwp_in(pverp-k+1)
+ up2(i,k) = up2_in(pverp-k+1)
+ vp2(i,k) = vp2_in(pverp-k+1)
+ thlm(i,k) = thlm_in(pverp-k+1)
+ rtm(i,k) = rtm_in(pverp-k+1)
+ wprtp(i,k) = wprtp_in(pverp-k+1)
+ wpthlp(i,k) = wpthlp_in(pverp-k+1)
+ wp2(i,k) = wp2_in(pverp-k+1)
+ wp3(i,k) = wp3_in(pverp-k+1)
+ rtp2(i,k) = rtp2_in(pverp-k+1)
+ thlp2(i,k) = thlp2_in(pverp-k+1)
+ rtpthlp(i,k) = rtpthlp_in(pverp-k+1)
+ rcm(i,k) = rcm_out(pverp-k+1)
+ wprcp(i,k) = wprcp_out(pverp-k+1)
+ cloud_frac(i,k) = min(cloud_frac_out(pverp-k+1),1._r8)
+ rcm_in_layer(i,k) = rcm_in_layer_out(pverp-k+1)
+ cloud_cover(i,k) = min(cloud_cover_out(pverp-k+1),1._r8)
+ zt_out(i,k) = zt_g(pverp-k+1)
+ zi_out(i,k) = zi_g(pverp-k+1)
+ khzm(i,k) = khzm_out(pverp-k+1)
+ khzt(i,k) = khzt_out(pverp-k+1)
+ qclvar(i,k) = min(1._r8,qclvar_out(pverp-k+1))
- do ixind=1,edsclr_dim
- edsclr_out(k,ixind) = edsclr_in(pverp-k+1,ixind)
- enddo
-
- enddo
+ do ixind=1,edsclr_dim
+ edsclr_out(k,ixind) = edsclr_in(pverp-k+1,ixind)
+ enddo
- zi_out(i,1) = 0._r8
+ enddo
- ! Compute integrals for static energy, kinetic energy, water vapor, and liquid water
- ! after CLUBB is called. This is for energy conservation purposes.
- se_a = 0._r8
- ke_a = 0._r8
- wv_a = 0._r8
- wl_a = 0._r8
- do k=1,pver
- clubb_s(k) = cpair*((thlm(i,k)+(latvap/cpair)*rcm(i,k))/exner_clubb(i,k))+ &
- gravit*state1%zm(i,k)+state1%phis(i)
- se_a(i) = se_a(i) + clubb_s(k)*state1%pdel(i,k)/gravit
- ke_a(i) = ke_a(i) + 0.5_r8*(um(i,k)**2+vm(i,k)**2)*state1%pdel(i,k)/gravit
- wv_a(i) = wv_a(i) + (rtm(i,k)-rcm(i,k))*state1%pdel(i,k)/gravit
- wl_a(i) = wl_a(i) + (rcm(i,k))*state1%pdel(i,k)/gravit
- enddo
+ ! Fill up arrays needed for McICA. Note we do not want the ghost point,
+ ! thus why the second loop is needed.
- ! Based on these integrals, compute the total energy before and after CLUBB call
- do k=1,pver
- te_a(i) = se_a(i) + ke_a(i) + (latvap+latice)*wv_a(i)+latice*wl_a(i)
- te_b(i) = se_b(i) + ke_b(i) + (latvap+latice)*wv_b(i)+latice*wl_b(i)
- enddo
+ zi_out(i,1) = 0._r8
- ! Take into account the surface fluxes of heat and moisture
- te_b(i) = te_b(i)+(cam_in%shf(i)+(cam_in%lhf(i)/latvap)*(latvap+latice))*hdtime
+ ! Compute integrals for static energy, kinetic energy, water vapor, and liquid water
+ ! after CLUBB is called. This is for energy conservation purposes.
+ se_a = 0._r8
+ ke_a = 0._r8
+ wv_a = 0._r8
+ wl_a = 0._r8
+ do k=1,pver
+ clubb_s(k) = cpair*((thlm(i,k)+(latvap/cpair)*rcm(i,k))/exner_clubb(i,k))+ &
+ gravit*state1%zm(i,k)+state1%phis(i)
+ se_a(i) = se_a(i) + clubb_s(k)*state1%pdel(i,k)/gravit
+ ke_a(i) = ke_a(i) + 0.5_r8*(um(i,k)**2+vm(i,k)**2)*state1%pdel(i,k)/gravit
+ wv_a(i) = wv_a(i) + (rtm(i,k)-rcm(i,k))*state1%pdel(i,k)/gravit
+ wl_a(i) = wl_a(i) + (rcm(i,k))*state1%pdel(i,k)/gravit
+ enddo
- ! Compute the disbalance of total energy
- se_dis = (te_a(i) - te_b(i))/(state1%ps(i)-state1%pint(i,1))
+ ! Based on these integrals, compute the total energy before and after CLUBB call
+ do k=1,pver
+ te_a(i) = se_a(i) + ke_a(i) + (latvap+latice)*wv_a(i)+latice*wl_a(i)
+ te_b(i) = se_b(i) + ke_b(i) + (latvap+latice)*wv_b(i)+latice*wl_b(i)
+ enddo
+
+ ! Take into account the surface fluxes of heat and moisture
+ te_b(i) = te_b(i)+(cam_in%shf(i)+(cam_in%lhf(i)/latvap)*(latvap+latice))*hdtime
- ! Fix the total energy coming out of CLUBB so it achieves enery conservation.
- ! Apply this fixer throughout the column evenly.
- do k=1,pver
- clubb_s(k) = clubb_s(k) - se_dis*gravit
- enddo
-
- ! Now compute the tendencies of CLUBB to CAM, note that pverp is the ghost point
- ! for all variables and therefore is never called in this loop
- do k=1,pver
+ ! Compute the disbalance of total energy
+ se_dis = (te_a(i) - te_b(i))/(state1%ps(i)-state1%pint(i,1))
+
+ ! Fix the total energy coming out of CLUBB so it achieves enery conservation.
+ ! Apply this fixer throughout the column evenly.
+ do k=1,pver
+ clubb_s(k) = clubb_s(k) - se_dis*gravit
+ enddo
+
+ ! Now compute the tendencies of CLUBB to CAM, note that pverp is the ghost point
+ ! for all variables and therefore is never called in this loop
+ do k=1,pver
- ptend_loc%u(i,k) = (um(i,k)-state1%u(i,k))/hdtime ! east-west wind
- ptend_loc%v(i,k) = (vm(i,k)-state1%v(i,k))/hdtime ! north-south wind
- ptend_loc%q(i,k,ixq) = (rtm(i,k)-rcm(i,k)-state1%q(i,k,ixq))/hdtime ! water vapor
- ptend_loc%q(i,k,ixcldliq) = (rcm(i,k)-state1%q(i,k,ixcldliq))/hdtime ! Tendency of liquid water
- ptend_loc%s(i,k) = (clubb_s(k)-state1%s(i,k))/hdtime ! Tendency of static energy
-
- ! Apply tendencies to ice mixing ratio, liquid and ice number, and aerosol constituents.
- ! Loading up this array doesn't mean the tendencies are applied.
- ! edsclr_out is compressed with just the constituents being used, ptend and state are not compressed
-
- icnt=0
- do ixind=1,pcnst
- if (lq(ixind)) then
- icnt=icnt+1
- if ((ixind /= ixq) .and. (ixind /= ixcldliq)) then
- ptend_loc%q(i,k,ixind) = (edsclr_out(k,icnt)-state1%q(i,k,ixind))/hdtime ! transported constituents
- end if
- end if
- enddo
+ ptend_loc%u(i,k) = (um(i,k)-state1%u(i,k))/hdtime ! east-west wind
+ ptend_loc%v(i,k) = (vm(i,k)-state1%v(i,k))/hdtime ! north-south wind
+ ptend_loc%q(i,k,ixq) = (rtm(i,k)-rcm(i,k)-state1%q(i,k,ixq))/hdtime ! water vapor
+ ptend_loc%q(i,k,ixcldliq) = (rcm(i,k)-state1%q(i,k,ixcldliq))/hdtime ! Tendency of liquid water
+ ptend_loc%s(i,k) = (clubb_s(k)-state1%s(i,k))/hdtime ! Tendency of static energy
+
+ if (clubb_do_adv) then
+ if (macmic_it .eq. cld_macmic_num_steps) then
+
+ ! Here add a constant to moments which can be either positive or
+ ! negative. This is to prevent clipping when dynamics tries to
+ ! make all constituents positive
+ wp3(i,k) = wp3(i,k) + wp3_const
+ rtpthlp(i,k) = rtpthlp(i,k) + rtpthlp_const
+ wpthlp(i,k) = wpthlp(i,k) + wpthlp_const
+ wprtp(i,k) = wprtp(i,k) + wprtp_const
+
+ ptend_loc%q(i,k,ixthlp2)=(thlp2(i,k)-state1%q(i,k,ixthlp2))/hdtime ! THLP Variance
+ ptend_loc%q(i,k,ixrtp2)=(rtp2(i,k)-state1%q(i,k,ixrtp2))/hdtime ! RTP Variance
+ ptend_loc%q(i,k,ixrtpthlp)=(rtpthlp(i,k)-state1%q(i,k,ixrtpthlp))/hdtime ! RTP THLP covariance
+ ptend_loc%q(i,k,ixwpthlp)=(wpthlp(i,k)-state1%q(i,k,ixwpthlp))/hdtime ! WPTHLP
+ ptend_loc%q(i,k,ixwprtp)=(wprtp(i,k)-state1%q(i,k,ixwprtp))/hdtime ! WPRTP
+ ptend_loc%q(i,k,ixwp2)=(wp2(i,k)-state1%q(i,k,ixwp2))/hdtime ! WP2
+ ptend_loc%q(i,k,ixwp3)=(wp3(i,k)-state1%q(i,k,ixwp3))/hdtime ! WP3
+ ptend_loc%q(i,k,ixup2)=(up2(i,k)-state1%q(i,k,ixup2))/hdtime ! UP2
+ ptend_loc%q(i,k,ixvp2)=(vp2(i,k)-state1%q(i,k,ixvp2))/hdtime ! VP2
+ else
+ ptend_loc%q(i,k,ixthlp2)=0._r8
+ ptend_loc%q(i,k,ixrtp2)=0._r8
+ ptend_loc%q(i,k,ixrtpthlp)=0._r8
+ ptend_loc%q(i,k,ixwpthlp)=0._r8
+ ptend_loc%q(i,k,ixwprtp)=0._r8
+ ptend_loc%q(i,k,ixwp2)=0._r8
+ ptend_loc%q(i,k,ixwp3)=0._r8
+ ptend_loc%q(i,k,ixup2)=0._r8
+ ptend_loc%q(i,k,ixvp2)=0._r8
+ endif
- enddo
+ endif
+
+ ! Apply tendencies to ice mixing ratio, liquid and ice number, and aerosol constituents.
+ ! Loading up this array doesn't mean the tendencies are applied.
+ ! edsclr_out is compressed with just the constituents being used, ptend and state are not compressed
+
+ icnt=0
+ do ixind=1,pcnst
+ if (lq(ixind)) then
+ icnt=icnt+1
+ if ((ixind /= ixq) .and. (ixind /= ixcldliq) .and.&
+ (ixind /= ixthlp2) .and. (ixind /= ixrtp2) .and.&
+ (ixind /= ixrtpthlp) .and. (ixind /= ixwpthlp) .and.&
+ (ixind /= ixwprtp) .and. (ixind /= ixwp2) .and.&
+ (ixind /= ixwp3) .and. (ixind /= ixup2) .and. (ixind /= ixvp2) ) then
+ ptend_loc%q(i,k,ixind) = (edsclr_out(k,icnt)-state1%q(i,k,ixind))/hdtime ! transported constituents
+ end if
+ end if
+ enddo
+
+ enddo
enddo ! end column loop
+
+ ! Add constant to ghost point so that output is not corrupted
+ if (clubb_do_adv) then
+ if (macmic_it .eq. cld_macmic_num_steps) then
+ wp3(:,pverp) = wp3(:,pverp) + wp3_const
+ rtpthlp(:,pverp) = rtpthlp(:,pverp) + rtpthlp_const
+ wpthlp(:,pverp) = wpthlp(:,pverp) + wpthlp_const
+ wprtp(:,pverp) = wprtp(:,pverp) + wprtp_const
+ endif
+ endif
cmeliq(:,:) = ptend_loc%q(:,:,ixcldliq)
! ------------------------------------------------- !
! End column computation of CLUBB, begin to apply !
- ! and compute output, etc !
+ ! and compute output, etc !
! ------------------------------------------------- !
! Output CLUBB tendencies
- call outfld( 'RVMTEND_CLUBB', ptend_loc%q(:,:,ixq)*1000._r8, pcols, lchnk)
- call outfld( 'RCMTEND_CLUBB', ptend_loc%q(:,:,ixcldliq)*1000._r8, pcols, lchnk)
- call outfld( 'RIMTEND_CLUBB', ptend_loc%q(:,:,ixcldice)*1000._r8, pcols, lchnk)
+ call outfld( 'RVMTEND_CLUBB', ptend_loc%q(:,:,ixq), pcols, lchnk)
+ call outfld( 'RCMTEND_CLUBB', ptend_loc%q(:,:,ixcldliq), pcols, lchnk)
+ call outfld( 'RIMTEND_CLUBB', ptend_loc%q(:,:,ixcldice), pcols, lchnk)
call outfld( 'STEND_CLUBB', ptend_loc%s,pcols, lchnk)
call outfld( 'UTEND_CLUBB', ptend_loc%u,pcols, lchnk)
- call outfld( 'VTEND_CLUBB', ptend_loc%v,pcols, lchnk)
+ call outfld( 'VTEND_CLUBB', ptend_loc%v,pcols, lchnk)
+
+ if (clubb_do_deep) call outfld( 'MU_CLUBB', varmu ,pcols, lchnk)
call outfld( 'CMELIQ', cmeliq, pcols, lchnk)
! Update physics tendencies
- call physics_ptend_init(ptend_all, state%psetcols, 'clubb')
+ if (.not. micro_do_icesupersat) then
+ call physics_ptend_init(ptend_all, state%psetcols, 'clubb')
+ endif
call physics_ptend_sum(ptend_loc,ptend_all,ncol)
call physics_update(state1,ptend_loc,hdtime)
+
+ ! ------------------------------------------------------------ !
+ ! ------------------------------------------------------------ !
+ ! ------------------------------------------------------------ !
+ ! The rest of the code deals with diagnosing variables !
+ ! for microphysics/radiation computation and macrophysics !
+ ! ------------------------------------------------------------ !
+ ! ------------------------------------------------------------ !
+ ! ------------------------------------------------------------ !
+
! --------------------------------------------------------------------------------- !
- ! COMPUTE THE ICE CLOUD DETRAINMENT !
+ ! COMPUTE THE ICE CLOUD DETRAINMENT !
! Detrainment of convective condensate into the environment or stratiform cloud !
! --------------------------------------------------------------------------------- !
@@ -1424,67 +2094,69 @@ subroutine clubb_tend_cam( &
do k=1,pver
do i=1,ncol
- if( state1%t(i,k) > 268.15_r8 ) then
- dum1 = 0.0_r8
- elseif ( state1%t(i,k) < 238.15_r8 ) then
- dum1 = 1.0_r8
- else
- dum1 = ( 268.15_r8 - state1%t(i,k) ) / 30._r8
- endif
+ if( state1%t(i,k) > 268.15_r8 ) then
+ dum1 = 0.0_r8
+ elseif ( state1%t(i,k) < 238.15_r8 ) then
+ dum1 = 1.0_r8
+ else
+ dum1 = ( 268.15_r8 - state1%t(i,k) ) / 30._r8
+ endif
- ptend_loc%q(i,k,ixcldliq) = dlf(i,k) * ( 1._r8 - dum1 )
- ptend_loc%q(i,k,ixcldice) = dlf(i,k) * dum1
- ptend_loc%q(i,k,ixnumliq) = 3._r8 * ( max(0._r8, ( dlf(i,k) - dlf2(i,k) )) * ( 1._r8 - dum1 ) ) &
- / (4._r8*3.14_r8* 8.e-6_r8**3*997._r8) + & ! Deep Convection
- 3._r8 * ( dlf2(i,k) * ( 1._r8 - dum1 ) ) &
- / (4._r8*3.14_r8*10.e-6_r8**3*997._r8) ! Shallow Convection
- ptend_loc%q(i,k,ixnumice) = 3._r8 * ( max(0._r8, ( dlf(i,k) - dlf2(i,k) )) * dum1 ) &
- / (4._r8*3.14_r8*25.e-6_r8**3*500._r8) + & ! Deep Convection
- 3._r8 * ( dlf2(i,k) * dum1 ) &
- / (4._r8*3.14_r8*50.e-6_r8**3*500._r8) ! Shallow Convection
- ptend_loc%s(i,k) = dlf(i,k) * dum1 * latice
-
- ! Only rliq is saved from deep convection, which is the reserved liquid. We need to keep
- ! track of the integrals of ice and static energy that is effected from conversion to ice
- ! so that the energy checker doesn't complain.
- det_s(i) = det_s(i) + ptend_loc%s(i,k)*state1%pdel(i,k)/gravit
- det_ice(i) = det_ice(i) - ptend_loc%q(i,k,ixcldice)*state1%pdel(i,k)/gravit
-
+ ptend_loc%q(i,k,ixcldliq) = dlf(i,k) * ( 1._r8 - dum1 )
+ ptend_loc%q(i,k,ixcldice) = dlf(i,k) * dum1
+ ptend_loc%q(i,k,ixnumliq) = 3._r8 * ( max(0._r8, ( dlf(i,k) - dlf2(i,k) )) * ( 1._r8 - dum1 ) ) &
+ / (4._r8*3.14_r8* 8.e-6_r8**3*997._r8) + & ! Deep Convection
+ 3._r8 * ( dlf2(i,k) * ( 1._r8 - dum1 ) ) &
+ / (4._r8*3.14_r8*10.e-6_r8**3*997._r8) ! Shallow Convection
+ ptend_loc%q(i,k,ixnumice) = 3._r8 * ( max(0._r8, ( dlf(i,k) - dlf2(i,k) )) * dum1 ) &
+ / (4._r8*3.14_r8*25.e-6_r8**3*500._r8) + & ! Deep Convection
+ 3._r8 * ( dlf2(i,k) * dum1 ) &
+ / (4._r8*3.14_r8*50.e-6_r8**3*500._r8) ! Shallow Convection
+ ptend_loc%s(i,k) = dlf(i,k) * dum1 * latice
+
+ ! Only rliq is saved from deep convection, which is the reserved liquid. We need to keep
+ ! track of the integrals of ice and static energy that is effected from conversion to ice
+ ! so that the energy checker doesn't complain.
+ det_s(i) = det_s(i) + ptend_loc%s(i,k)*state1%pdel(i,k)/gravit
+ det_ice(i) = det_ice(i) - ptend_loc%q(i,k,ixcldice)*state1%pdel(i,k)/gravit
+
enddo
enddo
det_ice(:ncol) = det_ice(:ncol)/1000._r8 ! divide by density of water
+
+ call outfld( 'DPDLFLIQ', ptend_loc%q(:,:,ixcldliq), pcols, lchnk)
+ call outfld( 'DPDLFICE', ptend_loc%q(:,:,ixcldice), pcols, lchnk)
+ call outfld( 'DPDLFT', ptend_loc%s(:,:)/cpair, pcols, lchnk)
call physics_ptend_sum(ptend_loc,ptend_all,ncol)
call physics_update(state1,ptend_loc,hdtime)
- ! ------------------------------------------------------------ !
- ! ------------------------------------------------------------ !
- ! ------------------------------------------------------------ !
- ! The rest of the code deals with diagnosing variables !
- ! for microphysics/radiation computation and macrophysics !
- ! ------------------------------------------------------------ !
- ! ------------------------------------------------------------ !
- ! ------------------------------------------------------------ !
-
! ------------------------------------------------- !
- ! Diagnose relative cloud water variance !
+ ! Diagnose relative cloud water variance !
! ------------------------------------------------- !
+ if (deep_scheme .eq. 'CLUBB_SGS') then
+ relvarmax = 2.0_r8
+ else
+ relvarmax = 10.0_r8
+ endif
- relvar(:,:) = 1.0_r8 ! default
-
- where (rcm(:ncol,:pver) /= 0 .and. qclvar(:ncol,:pver) /= 0) &
- relvar(:ncol,:pver) = min(1.0_r8,max(0.001_r8,rcm(:ncol,:pver)**2/qclvar(:ncol,:pver)))
+ relvar(:,:) = relvarmax ! default
+
+ if (deep_scheme .ne. 'CLUBB_SGS') then
+ where (rcm(:ncol,:pver) /= 0 .and. qclvar(:ncol,:pver) /= 0) &
+ relvar(:ncol,:pver) = min(relvarmax,max(0.001_r8,rcm(:ncol,:pver)**2/qclvar(:ncol,:pver)))
+ endif
! ------------------------------------------------- !
- ! Optional Accretion enhancement factor !
+ ! Optional Accretion enhancement factor !
! ------------------------------------------------- !
-
- accre_enhan(:ncol,:pver) = 1._r8+0.65_r8*(1.0_r8/relvar(:ncol,:pver))
+
+ accre_enhan(:ncol,:pver) = 1._r8
! ------------------------------------------------- !
- ! Diagnose some output variables !
+ ! Diagnose some output variables !
! ------------------------------------------------- !
! density
@@ -1494,35 +2166,35 @@ subroutine clubb_tend_cam( &
eps = rair/rh2o
wpthvp(:,:) = 0.0_r8
do k=1,pver
- do i=1,ncol
- ! buoyancy flux
- wpthvp(i,k) = wpthlp(i,k)+((1._r8-eps)/eps)*theta0*wprtp(i,k)+((latvap/cpair)* &
- state1%exner(i,k)-(1._r8/eps)*theta0)*wprcp(i,k)
-
- ! total water mixing ratio
- qt_output(i,k) = state1%q(i,k,ixq)+state1%q(i,k,ixcldliq)+state1%q(i,k,ixcldice)
- ! liquid water potential temperature
- thetal_output(i,k) = (state1%t(i,k)*state1%exner(i,k))-(latvap/cpair)*state1%q(i,k,ixcldliq)
- ! liquid water static energy
- sl_output(i,k) = cpair*state1%t(i,k)+gravit*state1%zm(i,k)-latvap*state1%q(i,k,ixcldliq)
- enddo
+ do i=1,ncol
+ ! buoyancy flux
+ wpthvp(i,k) = (wpthlp(i,k)-(apply_const*wpthlp_const))+((1._r8-eps)/eps)*theta0* &
+ (wprtp(i,k)-(apply_const*wprtp_const))+((latvap/cpair)* &
+ state1%exner(i,k)-(1._r8/eps)*theta0)*wprcp(i,k)
+
+ ! total water mixing ratio
+ qt_output(i,k) = state1%q(i,k,ixq)+state1%q(i,k,ixcldliq)+state1%q(i,k,ixcldice)
+ ! liquid water potential temperature
+ thetal_output(i,k) = (state1%t(i,k)*state1%exner(i,k))-(latvap/cpair)*state1%q(i,k,ixcldliq)
+ ! liquid water static energy
+ sl_output(i,k) = cpair*state1%t(i,k)+gravit*state1%zm(i,k)-latvap*state1%q(i,k,ixcldliq)
+ enddo
enddo
do k=1,pverp
- do i=1,ncol
- ! liquid water potential temperature flux
- wpthlp_output(i,k) = wpthlp(i,k)*rho(i,k)*cpair
- ! total water mixig ratio flux
- wprtp_output(i,k) = wprtp(i,k)*rho(i,k)*latvap
- ! turbulent kinetic energy
- tke(i,k) = 0.5_r8*(up2(i,k)+vp2(i,k)+wp2(i,k))
- enddo
+ do i=1,ncol
+ wpthlp_output(i,k) = (wpthlp(i,k)-(apply_const*wpthlp_const))*rho(i,k)*cpair ! liquid water potential temperature flux
+ wprtp_output(i,k) = (wprtp(i,k)-(apply_const*wprtp_const))*rho(i,k)*latvap ! total water mixig ratio flux
+ rtpthlp_output(i,k) = rtpthlp(i,k)-(apply_const*rtpthlp_const) ! rtpthlp output
+ wp3_output(i,k) = wp3(i,k) - (apply_const*wp3_const) ! wp3 output
+ tke(i,k) = 0.5_r8*(up2(i,k)+vp2(i,k)+wp2(i,k)) ! turbulent kinetic energy
+ enddo
enddo
! --------------------------------------------------------------------------------- !
! Diagnose some quantities that are computed in macrop_tend here. !
! These are inputs required for the microphysics calculation. !
- ! !
+ ! !
! FIRST PART COMPUTES THE STRATIFORM CLOUD FRACTION FROM CLUBB CLOUD FRACTION !
! --------------------------------------------------------------------------------- !
@@ -1531,69 +2203,70 @@ subroutine clubb_tend_cam( &
qlst(:,:) = 0.0_r8
do k=1,pver
- do i=1,ncol
- alst(i,k) = cloud_frac(i,k)
- qlst(i,k) = rcm(i,k)/max(0.01_r8,alst(i,k)) ! Incloud stratus condensate mixing ratio
- enddo
+ do i=1,ncol
+ alst(i,k) = cloud_frac(i,k)
+ qlst(i,k) = rcm(i,k)/max(0.01_r8,alst(i,k)) ! Incloud stratus condensate mixing ratio
+ enddo
enddo
! --------------------------------------------------------------------------------- !
- ! THIS PART COMPUTES CONVECTIVE AND DEEP CONVECTIVE CLOUD FRACTION !
+ ! THIS PART COMPUTES CONVECTIVE AND DEEP CONVECTIVE CLOUD FRACTION !
! --------------------------------------------------------------------------------- !
deepcu(:,pver) = 0.0_r8
shalcu(:,pver) = 0.0_r8
do k=1,pver-1
- do i=1,ncol
- ! diagnose the deep convective cloud fraction, as done in macrophysics based on the
- ! deep convective mass flux, read in from pbuf. Since shallow convection is never
- ! called, the shallow convective mass flux will ALWAYS be zero, ensuring that this cloud
- ! fraction is purely from deep convection scheme.
- deepcu(i,k) = max(0.0_r8,min(0.1_r8*log(1.0_r8+500.0_r8*(cmfmc(i,k+1)-cmfmc2(i,k+1))),0.6_r8))
- shalcu(i,k) = 0._r8
+ do i=1,ncol
+ ! diagnose the deep convective cloud fraction, as done in macrophysics based on the
+ ! deep convective mass flux, read in from pbuf. Since shallow convection is never
+ ! called, the shallow convective mass flux will ALWAYS be zero, ensuring that this cloud
+ ! fraction is purely from deep convection scheme.
+ deepcu(i,k) = max(0.0_r8,min(0.1_r8*log(1.0_r8+500.0_r8*(cmfmc(i,k+1)-cmfmc_sh(i,k+1))),0.6_r8))
+ shalcu(i,k) = 0._r8
- if (deepcu(i,k) <= frac_limit .or. dp_icwmr(i,k) < ic_limit) then
- deepcu(i,k) = 0._r8
- endif
+ if (deepcu(i,k) <= frac_limit .or. dp_icwmr(i,k) < ic_limit) then
+ deepcu(i,k) = 0._r8
+ endif
- ! using the deep convective cloud fraction, and CLUBB cloud fraction (variable
- ! "cloud_frac"), compute the convective cloud fraction. This follows the formulation
- ! found in macrophysics code. Assumes that convective cloud is all nonstratiform cloud
- ! from CLUBB plus the deep convective cloud fraction
- concld(i,k) = min(cloud_frac(i,k)-alst(i,k)+deepcu(i,k),0.80_r8)
- enddo
+ ! using the deep convective cloud fraction, and CLUBB cloud fraction (variable
+ ! "cloud_frac"), compute the convective cloud fraction. This follows the formulation
+ ! found in macrophysics code. Assumes that convective cloud is all nonstratiform cloud
+ ! from CLUBB plus the deep convective cloud fraction
+ concld(i,k) = min(cloud_frac(i,k)-alst(i,k)+deepcu(i,k),0.80_r8)
+ enddo
enddo
if (single_column) then
- if (trim(scm_clubb_iop_name) .eq. 'ATEX_48hr' .or. trim(scm_clubb_iop_name) .eq. 'BOMEX_5day' .or. &
- trim(scm_clubb_iop_name) .eq. 'DYCOMSrf01_4day' .or. &
- trim(scm_clubb_iop_name) .eq. 'DYCOMSrf02_06hr' .or. &
- trim(scm_clubb_iop_name) .eq. 'RICO_3day' .or. &
- trim(scm_clubb_iop_name) .eq. 'ARM_CC') then
+ if (trim(scm_clubb_iop_name) .eq. 'ATEX_48hr' .or. &
+ trim(scm_clubb_iop_name) .eq. 'BOMEX_5day' .or. &
+ trim(scm_clubb_iop_name) .eq. 'DYCOMSrf01_4day' .or. &
+ trim(scm_clubb_iop_name) .eq. 'DYCOMSrf02_06hr' .or. &
+ trim(scm_clubb_iop_name) .eq. 'RICO_3day' .or. &
+ trim(scm_clubb_iop_name) .eq. 'ARM_CC') then
- deepcu(:,:) = 0.0_r8
- concld(:,:) = 0.0_r8
+ deepcu(:,:) = 0.0_r8
+ concld(:,:) = 0.0_r8
- endif
+ endif
endif
! --------------------------------------------------------------------------------- !
- ! COMPUTE THE ICE CLOUD FRACTION PORTION !
+ ! COMPUTE THE ICE CLOUD FRACTION PORTION !
! use the aist_vector function to compute the ice cloud fraction !
! --------------------------------------------------------------------------------- !
- do k=1,pver
+ do k=1,pver
call aist_vector(state1%q(:,k,ixq),state1%t(:,k),state1%pmid(:,k),state1%q(:,k,ixcldice), &
- cam_in%landfrac(:),cam_in%snowhland(:),aist(:,k),ncol)
- enddo
+ state1%q(:,k,ixnumice),cam_in%landfrac(:),cam_in%snowhland(:),aist(:,k),ncol)
+ enddo
! --------------------------------------------------------------------------------- !
- ! THIS PART COMPUTES THE LIQUID STRATUS FRACTION !
- ! !
+ ! THIS PART COMPUTES THE LIQUID STRATUS FRACTION !
+ ! !
! For now leave the computation of ice stratus fraction from macrop_driver intact !
! because CLUBB does nothing with ice. Here I simply overwrite the liquid stratus !
- ! fraction that was coded in macrop_driver !
+ ! fraction that was coded in macrop_driver !
! --------------------------------------------------------------------------------- !
! Recompute net stratus fraction using maximum over-lapping assumption, as done
@@ -1602,58 +2275,54 @@ subroutine clubb_tend_cam( &
cldthresh=1.e-18_r8
do k=1,pver
- do i=1,ncol
- ast(i,k) = 0._r8 ! init AST
-
- if (newfice(i,k) .le. 0.5_r8 .and. state1%q(i,k,2) .gt. cldthresh) then
- ast(i,k) = alst(i,k)
- else if ((newfice(i,k) .gt. 0.5_r8 .and. state1%q(i,k,3) .gt. cldthresh) .or. &
- (newfice(i,k) .le. 0.5_r8 .and. state1%q(i,k,2) .lt. cldthresh &
- .and. state1%q(i,k,3) .gt. cldthresh)) then
- ast(i,k) = aist(i,k)
- end if
-
- qist(i,k) = state1%q(i,k,ixcldice)/max(0.01_r8,aist(i,k))
- enddo
+ do i=1,ncol
+
+ ast(i,k) = max(alst(i,k),aist(i,k))
+
+ qist(i,k) = state1%q(i,k,ixcldice)/max(0.01_r8,aist(i,k))
+ enddo
enddo
! Probably need to add deepcu cloud fraction to the cloud fraction array, else would just
! be outputting the shallow convective cloud fraction
do k=1,pver
- do i=1,ncol
- cloud_frac(i,k) = min(ast(i,k)+deepcu(i,k),1.0_r8)
- enddo
+ do i=1,ncol
+ cloud_frac(i,k) = min(ast(i,k)+deepcu(i,k),1.0_r8)
+ enddo
enddo
! --------------------------------------------------------------------------------- !
- ! DIAGNOSE THE PBL DEPTH !
+ ! DIAGNOSE THE PBL DEPTH !
! this is needed for aerosol code !
- ! --------------------------------------------------------------------------------- !
+ ! --------------------------------------------------------------------------------- !
do i=1,ncol
- do k=1,pver
- th(i,k) = state1%t(i,k)*state1%exner(i,k)
- thv(i,k) = th(i,k)*(1.0_r8+zvir*state1%q(i,k,ixq))
- enddo
+ do k=1,pver
+ th(i,k) = state1%t(i,k)*state1%exner(i,k)
+ thv(i,k) = th(i,k)*(1.0_r8+zvir*state1%q(i,k,ixq))
+ enddo
enddo
! diagnose surface friction and obukhov length (inputs to diagnose PBL depth)
do i=1,ncol
- call calc_ustar( state1%t(i,pver), state1%pmid(i,pver), cam_in%wsx(i), cam_in%wsy(i), &
- rrho, ustar2(i) )
- call calc_obklen( th(i,pver), thv(i,pver), cam_in%lhf(i)/latvap, cam_in%shf(i), rrho, ustar2(i), &
- kinheat(i), kinwat(i), kbfs(i), obklen(i) )
+ rrho = (1._r8/gravit)*(state1%pdel(i,pver)/dz_g(pver))
+ call calc_ustar( state1%t(i,pver), state1%pmid(i,pver), cam_in%wsx(i), cam_in%wsy(i), &
+ rrho, ustar2(i) )
+ call calc_obklen( th(i,pver), thv(i,pver), cam_in%lhf(i)/latvap, cam_in%shf(i), rrho, ustar2(i), &
+ kinheat(i), kinwat(i), kbfs(i), obklen(i) )
enddo
dummy2(:) = 0._r8
dummy3(:) = 0._r8
+
+ where (kbfs .eq. -0.0_r8) kbfs = 0.0_r8
! Compute PBL depth according to Holtslag-Boville Scheme
call pblintd(ncol, thv, state1%zm, state1%u, state1%v, &
- ustar2, obklen, kinheat, pblh, dummy2, &
- state1%zi, cloud_frac(:,1:pver), 1._r8-cam_in%landfrac, dummy3)
-
+ ustar2, obklen, kbfs, pblh, dummy2, &
+ state1%zi, cloud_frac(:,1:pver), 1._r8-cam_in%landfrac, dummy3)
+
! Output the PBL depth
call outfld('PBLH', pblh, pcols, lchnk)
@@ -1665,66 +2334,68 @@ subroutine clubb_tend_cam( &
! --------------------------------------------------------------------------------- !
! Output calls of variables goes here
- call outfld( 'RHO_CLUBB', rho, pcols, lchnk )
- call outfld( 'WP2_CLUBB', wp2, pcols, lchnk )
- call outfld( 'UP2_CLUBB', up2, pcols, lchnk )
- call outfld( 'VP2_CLUBB', vp2, pcols, lchnk )
- call outfld( 'WP3_CLUBB', wp3, pcols, lchnk )
- call outfld( 'UPWP_CLUBB', upwp, pcols, lchnk )
- call outfld( 'VPWP_CLUBB', vpwp, pcols, lchnk )
- call outfld( 'WPTHLP_CLUBB', wpthlp_output, pcols, lchnk )
- call outfld( 'WPRTP_CLUBB', wprtp_output, pcols, lchnk )
- call outfld( 'RTP2_CLUBB', rtp2*1000._r8, pcols, lchnk )
- call outfld( 'THLP2_CLUBB', thlp2, pcols, lchnk )
- call outfld( 'RTPTHLP_CLUBB', rtpthlp*1000._r8, pcols, lchnk )
- call outfld( 'RCM_CLUBB', rcm*1000._r8, pcols, lchnk )
- call outfld( 'WPRCP_CLUBB', wprcp*latvap, pcols, lchnk )
- call outfld( 'CLOUDFRAC_CLUBB', alst, pcols, lchnk )
- call outfld( 'RCMINLAYER_CLUBB', rcm_in_layer*1000._r8, pcols, lchnk )
- call outfld( 'CLOUDCOVER_CLUBB', cloud_frac, pcols, lchnk )
- call outfld( 'WPTHVP_CLUBB', wpthvp*cpair, pcols, lchnk )
- call outfld( 'ZT_CLUBB', 1._r8*zt_out, pcols, lchnk )
- call outfld( 'ZM_CLUBB', 1._r8*zi_out, pcols, lchnk )
- call outfld( 'UM_CLUBB', um, pcols, lchnk )
- call outfld( 'VM_CLUBB', vm, pcols, lchnk )
- call outfld( 'THETAL', thetal_output, pcols, lchnk )
- call outfld( 'QT', qt_output, pcols, lchnk )
- call outfld( 'SL', sl_output, pcols, lchnk )
+ call outfld( 'RELVAR', relvar, pcols, lchnk )
+ call outfld( 'RHO_CLUBB', rho, pcols, lchnk )
+ call outfld( 'WP2_CLUBB', wp2, pcols, lchnk )
+ call outfld( 'UP2_CLUBB', up2, pcols, lchnk )
+ call outfld( 'VP2_CLUBB', vp2, pcols, lchnk )
+ call outfld( 'WP3_CLUBB', wp3_output, pcols, lchnk )
+ call outfld( 'UPWP_CLUBB', upwp, pcols, lchnk )
+ call outfld( 'VPWP_CLUBB', vpwp, pcols, lchnk )
+ call outfld( 'WPTHLP_CLUBB', wpthlp_output, pcols, lchnk )
+ call outfld( 'WPRTP_CLUBB', wprtp_output, pcols, lchnk )
+ call outfld( 'RTP2_CLUBB', rtp2*1000._r8, pcols, lchnk )
+ call outfld( 'THLP2_CLUBB', thlp2, pcols, lchnk )
+ call outfld( 'RTPTHLP_CLUBB', rtpthlp_output*1000._r8, pcols, lchnk )
+ call outfld( 'RCM_CLUBB', rcm*1000._r8, pcols, lchnk )
+ call outfld( 'WPRCP_CLUBB', wprcp*latvap, pcols, lchnk )
+ call outfld( 'CLOUDFRAC_CLUBB', alst, pcols, lchnk )
+ call outfld( 'RCMINLAYER_CLUBB', rcm_in_layer*1000._r8, pcols, lchnk )
+ call outfld( 'CLOUDCOVER_CLUBB', cloud_frac, pcols, lchnk )
+ call outfld( 'WPTHVP_CLUBB', wpthvp*cpair, pcols, lchnk )
+ call outfld( 'ZT_CLUBB', 1._r8*zt_out, pcols, lchnk )
+ call outfld( 'ZM_CLUBB', 1._r8*zi_out, pcols, lchnk )
+ call outfld( 'UM_CLUBB', um, pcols, lchnk )
+ call outfld( 'VM_CLUBB', vm, pcols, lchnk )
+ call outfld( 'THETAL', thetal_output, pcols, lchnk )
+ call outfld( 'QT', qt_output, pcols, lchnk )
+ call outfld( 'SL', sl_output, pcols, lchnk )
+ call outfld( 'CONCLD', concld, pcols, lchnk )
! Output CLUBB history here
if (l_stats) then
- do i=1,zt%nn
+ do i=1,stats_zt%num_output_fields
- temp1 = trim(zt%f%var(i)%name)
- sub = temp1
- if (len(temp1) .gt. 16) sub = temp1(1:16)
-
- call outfld(trim(sub), out_zt(:,:,i), pcols, lchnk )
- enddo
+ temp1 = trim(stats_zt%file%var(i)%name)
+ sub = temp1
+ if (len(temp1) .gt. 16) sub = temp1(1:16)
- do i=1,zm%nn
+ call outfld(trim(sub), out_zt(:,:,i), pcols, lchnk )
+ enddo
- temp1 = trim(zm%f%var(i)%name)
- sub = temp1
- if (len(temp1) .gt. 16) sub = temp1(1:16)
+ do i=1,stats_zm%num_output_fields
- call outfld(trim(sub),out_zm(:,:,i), pcols, lchnk)
- enddo
+ temp1 = trim(stats_zm%file%var(i)%name)
+ sub = temp1
+ if (len(temp1) .gt. 16) sub = temp1(1:16)
+
+ call outfld(trim(sub),out_zm(:,:,i), pcols, lchnk)
+ enddo
- if (l_output_rad_files) then
- do i=1,rad_zt%nn
- call outfld(trim(rad_zt%f%var(i)%name), out_radzt(:,:,i), pcols, lchnk)
- enddo
+ if (l_output_rad_files) then
+ do i=1,stats_rad_zt%num_output_fields
+ call outfld(trim(stats_rad_zt%file%var(i)%name), out_radzt(:,:,i), pcols, lchnk)
+ enddo
- do i=1,rad_zm%nn
- call outfld(trim(rad_zm%f%var(i)%name), out_radzm(:,:,i), pcols, lchnk)
- enddo
- endif
+ do i=1,stats_rad_zm%num_output_fields
+ call outfld(trim(stats_rad_zm%file%var(i)%name), out_radzm(:,:,i), pcols, lchnk)
+ enddo
+ endif
- do i=1,sfc%nn
- call outfld(trim(sfc%f%var(i)%name), out_sfc(:,:,i), pcols, lchnk)
- enddo
+ do i=1,stats_sfc%num_output_fields
+ call outfld(trim(stats_sfc%file%var(i)%name), out_sfc(:,:,i), pcols, lchnk)
+ enddo
endif
@@ -1736,8 +2407,7 @@ end subroutine clubb_tend_cam
! !
! =============================================================================== !
- subroutine clubb_surface ( &
- state, ptend, ztodt, cam_in, ustar, obklen)
+ subroutine clubb_surface (state, ptend, ztodt, cam_in, ustar, obklen)
!-------------------------------------------------------------------------------
! Description: Provide the obukov length and the surface friction velocity
@@ -1753,10 +2423,10 @@ subroutine clubb_surface ( &
! None
!-------------------------------------------------------------------------------
- use physics_types, only: physics_state, physics_ptend, physics_ptend_init
- use physconst, only: gravit, zvir, latvap
- use ppgrid, only: pver, pcols
- use constituents, only: pcnst, cnst_get_ind
+ use physics_types, only: physics_state, physics_ptend, physics_ptend_init
+ use physconst, only: gravit, zvir, latvap
+ use ppgrid, only: pver, pcols
+ use constituents, only: pcnst, cnst_get_ind
use camsrfexch, only: cam_in_t
implicit none
@@ -1765,18 +2435,18 @@ subroutine clubb_surface ( &
! Input Auguments !
! --------------- !
- type(physics_state), intent(in) :: state ! Physics state variables
+ type(physics_state), intent(in) :: state ! Physics state variables
type(cam_in_t), intent(in) :: cam_in
- real(r8), intent(in) :: ztodt ! 2 delta-t [ s ]
+ real(r8), intent(in) :: ztodt ! 2 delta-t [ s ]
! ---------------- !
! Output Auguments !
! ---------------- !
- type(physics_ptend), intent(out) :: ptend ! Individual parameterization tendencies
- real(r8), intent(out) :: obklen(pcols) ! Obukhov length [ m ]
- real(r8), intent(out) :: ustar(pcols) ! Surface friction velocity [ m/s ]
+ type(physics_ptend), intent(out) :: ptend ! Individual parameterization tendencies
+ real(r8), intent(out) :: obklen(pcols) ! Obukhov length [ m ]
+ real(r8), intent(out) :: ustar(pcols) ! Surface friction velocity [ m/s ]
#ifdef CLUBB_SGS
@@ -1784,19 +2454,19 @@ subroutine clubb_surface ( &
! Local Variables !
! --------------- !
- integer :: i ! indicees
- integer :: ncol ! # of atmospheric columns
+ integer :: i ! indicees
+ integer :: ncol ! # of atmospheric columns
real(r8) :: th(pcols) ! surface potential temperature
real(r8) :: thv(pcols) ! surface virtual potential temperature
- real(r8) :: kinheat ! kinematic surface heat flux
- real(r8) :: kinwat ! kinematic surface vapor flux
- real(r8) :: kbfs ! kinematic surface buoyancy flux
+ real(r8) :: kinheat ! kinematic surface heat flux
+ real(r8) :: kinwat ! kinematic surface vapor flux
+ real(r8) :: kbfs ! kinematic surface buoyancy flux
real(r8) :: tmp1(pcols)
real(r8) :: rztodt ! 1./ztodt
integer :: m
integer :: ixq
- real(r8) :: rrho ! Inverse air density
+ real(r8) :: rrho ! Inverse air density
logical :: lq(pcnst)
@@ -1820,20 +2490,21 @@ subroutine clubb_surface ( &
! Compute the surface friction velocity and obukov length
do i = 1, ncol
- th(i) = state%t(i,pver)*state%exner(i,pver) ! diagnose potential temperature
- thv(i) = th(i)*(1._r8+zvir*state%q(i,pver,ixq)) ! diagnose virtual potential temperature
+ th(i) = state%t(i,pver)*state%exner(i,pver) ! diagnose potential temperature
+ thv(i) = th(i)*(1._r8+zvir*state%q(i,pver,ixq)) ! diagnose virtual potential temperature
enddo
do i = 1, ncol
- call calc_ustar( state%t(i,pver), state%pmid(i,pver), cam_in%wsx(i), cam_in%wsy(i), &
- rrho, ustar(i) )
- call calc_obklen( th(i), thv(i), cam_in%lhf(i)/latvap, cam_in%shf(i), rrho, ustar(i), &
- kinheat, kinwat, kbfs, obklen(i) )
+ call calc_ustar( state%t(i,pver), state%pmid(i,pver), cam_in%wsx(i), cam_in%wsy(i), &
+ rrho, ustar(i) )
+ call calc_obklen( th(i), thv(i), cam_in%lhf(i)/latvap, cam_in%shf(i), rrho, ustar(i), &
+ kinheat, kinwat, kbfs, obklen(i) )
enddo
- rztodt = 1._r8/ztodt
+ rztodt = 1._r8/ztodt
ptend%q(:ncol,:pver,:) = state%q(:ncol,:pver,:)
- tmp1(:ncol) = ztodt * gravit * state%rpdel(:ncol,pver)
+ tmp1(:ncol) = ztodt * gravit * state%rpdel(:ncol,pver)
+
do m = 2, pcnst
ptend%q(:ncol,pver,m) = ptend%q(:ncol,pver,m) + tmp1(:ncol) * cam_in%cflx(:ncol,m)
enddo
@@ -1897,22 +2568,22 @@ real(r8) function diag_ustar( z, bflx, wnd, z0 )
ustar = wnd*klnz
if (abs(bflx) > 1.e-6_r8) then
- do iterate=1,4
-
- if (ustar > 1.e-6_r8) then
- lmo = -ustar**3 / ( vonk * bflx )
- zeta = z/lmo
- if (zeta > 0._r8) then
- ustar = vonk*wnd /(lnz + am*zeta)
- else
- x = sqrt( sqrt( 1.0_r8 - bm*zeta ) )
- psi1 = 2._r8*log( 1.0_r8+x ) + log( 1.0_r8+x*x ) - 2._r8*atan( x ) + c1
- ustar = wnd*vonk/(lnz - psi1)
- end if
+ do iterate=1,4
+
+ if (ustar > 1.e-6_r8) then
+ lmo = -ustar**3 / ( vonk * bflx )
+ zeta = z/lmo
+ if (zeta > 0._r8) then
+ ustar = vonk*wnd /(lnz + am*zeta)
+ else
+ x = sqrt( sqrt( 1.0_r8 - bm*zeta ) )
+ psi1 = 2._r8*log( 1.0_r8+x ) + log( 1.0_r8+x*x ) - 2._r8*atan( x ) + c1
+ ustar = wnd*vonk/(lnz - psi1)
+ end if
- endif
+ endif
- end do
+ end do
end if
@@ -1929,7 +2600,7 @@ end function diag_ustar
! =============================================================================== !
#ifdef CLUBB_SGS
-
+
subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
nnzp, nnrad_zt,nnrad_zm, delt )
!
@@ -1942,7 +2613,7 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
use stats_variables, only: &
- zt, & ! Variables
+ stats_zt, & ! Variables
ztscr01, &
ztscr02, &
ztscr03, &
@@ -1966,7 +2637,7 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
ztscr21
use stats_variables, only: &
- zm, &
+ stats_zm, &
zmscr01, &
zmscr02, &
zmscr03, &
@@ -1984,9 +2655,9 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
zmscr15, &
zmscr16, &
zmscr17, &
- rad_zt, &
- rad_zm, &
- sfc, &
+ stats_rad_zt, &
+ stats_rad_zm, &
+ stats_sfc, &
l_stats, &
l_output_rad_files, &
stats_tsamp, &
@@ -1999,18 +2670,18 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
l_netcdf, &
l_grads
- use clubb_precision, only: time_precision !
- use stats_zm, only: nvarmax_zm, stats_init_zm !
- use stats_zt, only: nvarmax_zt, stats_init_zt !
- use stats_rad_zt, only: nvarmax_rad_zt, stats_init_rad_zt !
- use stats_rad_zm, only: nvarmax_rad_zm, stats_init_rad_zm !
- use stats_sfc, only: nvarmax_sfc, stats_init_sfc !
- use error_code, only: clubb_at_least_debug_level !
- use constants_clubb, only: fstderr, var_length !
- use cam_history, only: addfld, phys_decomp
- use namelist_utils,only: find_group_name
- use units,only: getunit, freeunit
- use cam_abortutils,only: endrun
+ use clubb_precision, only: time_precision !
+ use stats_zm_module, only: nvarmax_zm, stats_init_zm !
+ use stats_zt_module, only: nvarmax_zt, stats_init_zt !
+ use stats_rad_zt_module, only: nvarmax_rad_zt, stats_init_rad_zt !
+ use stats_rad_zm_module, only: nvarmax_rad_zm, stats_init_rad_zm !
+ use stats_sfc_module, only: nvarmax_sfc, stats_init_sfc !
+ use error_code, only: clubb_at_least_debug_level !
+ use constants_clubb, only: fstderr, var_length !
+ use cam_history, only: addfld, phys_decomp
+ use namelist_utils, only: find_group_name
+ use units, only: getunit, freeunit
+ use cam_abortutils, only: endrun
implicit none
@@ -2026,28 +2697,18 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
integer, intent(in) :: nnrad_zt ! Grid points in the radiation grid [count]
integer, intent(in) :: nnrad_zm ! Grid points in the radiation grid [count]
- real(kind=time_precision), intent(in) :: &
- delt ! Timestep (dtmain in CLUBB) [s]
+ real(kind=time_precision), intent(in) :: delt ! Timestep (dtmain in CLUBB) [s]
! Local Variables
! Namelist Variables
- character(len=var_length), dimension(nvarmax_zt) :: &
- clubb_vars_zt ! Variables on the thermodynamic levels
-
- character(len=var_length), dimension(nvarmax_zm) :: &
- clubb_vars_zm ! Variables on the momentum levels
-
- character(len=var_length), dimension(nvarmax_rad_zt) :: &
- clubb_vars_rad_zt ! Variables on the radiation levels
-
- character(len=var_length), dimension(nvarmax_rad_zm) :: &
- clubb_vars_rad_zm ! Variables on the radiation levels
-
- character(len=var_length), dimension(nvarmax_sfc) :: &
- clubb_vars_sfc ! Variables at the model surface
+ character(len=var_length), dimension(nvarmax_zt) :: clubb_vars_zt ! Variables on the thermodynamic levels
+ character(len=var_length), dimension(nvarmax_zm) :: clubb_vars_zm ! Variables on the momentum levels
+ character(len=var_length), dimension(nvarmax_rad_zt) :: clubb_vars_rad_zt ! Variables on the radiation levels
+ character(len=var_length), dimension(nvarmax_rad_zm) :: clubb_vars_rad_zm ! Variables on the radiation levels
+ character(len=var_length), dimension(nvarmax_sfc) :: clubb_vars_sfc ! Variables at the model surface
namelist /clubb_stats_nl/ &
clubb_vars_zt, &
@@ -2075,9 +2736,9 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
stats_tout = stats_tout_in
if ( .not. l_stats ) then
- l_stats_samp = .false.
- l_stats_last = .false.
- return
+ l_stats_samp = .false.
+ l_stats_last = .false.
+ return
end if
! Initialize namelist variables
@@ -2090,26 +2751,26 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
! Read variables to compute from the namelist
if (masterproc) then
- iunit= getunit()
- open(unit=iunit,file="atm_in",status='old')
- call find_group_name(iunit, 'clubb_stats_nl', status=read_status)
- if (read_status == 0) then
- read(unit=iunit, nml=clubb_stats_nl, iostat=read_status)
- if (read_status /= 0) then
- call endrun('clubb_tend_cam: error reading namelist')
- end if
- end if
- close(unit=iunit)
- call freeunit(iunit)
+ iunit= getunit()
+ open(unit=iunit,file="atm_in",status='old')
+ call find_group_name(iunit, 'clubb_stats_nl', status=read_status)
+ if (read_status == 0) then
+ read(unit=iunit, nml=clubb_stats_nl, iostat=read_status)
+ if (read_status /= 0) then
+ call endrun('stats_init_clubb: error reading namelist')
+ end if
+ end if
+ close(unit=iunit)
+ call freeunit(iunit)
end if
#ifdef SPMD
- ! Broadcast namelist variables
- call mpibcast(clubb_vars_zt, var_length*nvarmax_zt, mpichar, 0, mpicom)
- call mpibcast(clubb_vars_zm, var_length*nvarmax_zm, mpichar, 0, mpicom)
- call mpibcast(clubb_vars_rad_zt, var_length*nvarmax_rad_zt, mpichar, 0, mpicom)
- call mpibcast(clubb_vars_rad_zm, var_length*nvarmax_rad_zm, mpichar, 0, mpicom)
- call mpibcast(clubb_vars_sfc, var_length*nvarmax_sfc, mpichar, 0, mpicom)
+ ! Broadcast namelist variables
+ call mpibcast(clubb_vars_zt, var_length*nvarmax_zt, mpichar, 0, mpicom)
+ call mpibcast(clubb_vars_zm, var_length*nvarmax_zm, mpichar, 0, mpicom)
+ call mpibcast(clubb_vars_rad_zt, var_length*nvarmax_rad_zt, mpichar, 0, mpicom)
+ call mpibcast(clubb_vars_rad_zm, var_length*nvarmax_rad_zm, mpichar, 0, mpicom)
+ call mpibcast(clubb_vars_sfc, var_length*nvarmax_sfc, mpichar, 0, mpicom)
#endif
! Hardcode these for use in CAM-CLUBB, don't want either
@@ -2120,70 +2781,70 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
! The model time step length, delt (which is dtmain), should multiply
! evenly into the statistical sampling time step length, stats_tsamp.
- if ( abs( stats_tsamp/delt - floor(stats_tsamp/delt) ) &
- > 1.e-8_r8 ) then
- l_error = .true. ! This will cause the run to stop.
- write(fstderr,*) 'Error: stats_tsamp should be an even multiple of ', &
- 'delt (which is dtmain). Check the appropriate ', &
- 'model.in file.'
- write(fstderr,*) 'stats_tsamp = ', stats_tsamp
- write(fstderr,*) 'delt = ', delt
+ if ( abs( stats_tsamp/delt - floor(stats_tsamp/delt) ) > 1.e-8_r8 ) then
+ l_error = .true. ! This will cause the run to stop.
+ write(fstderr,*) 'Error: stats_tsamp should be an even multiple of ', &
+ 'delt (which is dtmain). Check the appropriate ', &
+ 'model.in file.'
+ write(fstderr,*) 'stats_tsamp = ', stats_tsamp
+ write(fstderr,*) 'delt = ', delt
endif
! Initialize zt (mass points)
i = 1
- do while ( ichar(clubb_vars_zt(i)(1:1)) /= 0 &
- .and. len_trim(clubb_vars_zt(i)) /= 0 &
- .and. i <= nvarmax_zt )
+ do while ( ichar(clubb_vars_zt(i)(1:1)) /= 0 .and. &
+ len_trim(clubb_vars_zt(i)) /= 0 .and. &
+ i <= nvarmax_zt )
i = i + 1
enddo
ntot = i - 1
if ( ntot == nvarmax_zt ) then
- write(fstderr,*) "There are more statistical variables listed in ", &
- "clubb_vars_zt than allowed for by nvarmax_zt."
- write(fstderr,*) "Check the number of variables listed for clubb_vars_zt ", &
- "in the stats namelist, or change nvarmax_zt."
- write(fstderr,*) "nvarmax_zt = ", nvarmax_zt
- stop "stats_init_clubb: number of zt statistical variables exceeds limit"
+ write(fstderr,*) "There are more statistical variables listed in ", &
+ "clubb_vars_zt than allowed for by nvarmax_zt."
+ write(fstderr,*) "Check the number of variables listed for clubb_vars_zt ", &
+ "in the stats namelist, or change nvarmax_zt."
+ write(fstderr,*) "nvarmax_zt = ", nvarmax_zt
+ call endrun ("stats_init_clubb: number of zt statistical variables exceeds limit")
endif
- zt%nn = ntot
- zt%kk = nnzp
+ stats_zt%num_output_fields = ntot
+ stats_zt%kk = nnzp
- allocate( zt%z( zt%kk ) )
+ allocate( stats_zt%z( stats_zt%kk ) )
- allocate( zt%x( 1, 1, zt%kk, zt%nn ) )
- allocate( zt%n( 1, 1, zt%kk, zt%nn ) )
- allocate( zt%l_in_update( 1, 1, zt%kk, zt%nn ) )
- call stats_zero( zt%kk, zt%nn, zt%x, zt%n, zt%l_in_update )
+ allocate( stats_zt%accum_field_values( 1, 1, stats_zt%kk, stats_zt%num_output_fields ) )
+ allocate( stats_zt%accum_num_samples( 1, 1, stats_zt%kk, stats_zt%num_output_fields ) )
+ allocate( stats_zt%l_in_update( 1, 1, stats_zt%kk, stats_zt%num_output_fields ) )
+ call stats_zero( stats_zt%kk, stats_zt%num_output_fields, stats_zt%accum_field_values, &
+ stats_zt%accum_num_samples, stats_zt%l_in_update )
- allocate( zt%f%var( zt%nn ) )
- allocate( zt%f%z( zt%kk ) )
+ allocate( stats_zt%file%var( stats_zt%num_output_fields ) )
+ allocate( stats_zt%file%z( stats_zt%kk ) )
! Allocate scratch space
- allocate( ztscr01(zt%kk) )
- allocate( ztscr02(zt%kk) )
- allocate( ztscr03(zt%kk) )
- allocate( ztscr04(zt%kk) )
- allocate( ztscr05(zt%kk) )
- allocate( ztscr06(zt%kk) )
- allocate( ztscr07(zt%kk) )
- allocate( ztscr08(zt%kk) )
- allocate( ztscr09(zt%kk) )
- allocate( ztscr10(zt%kk) )
- allocate( ztscr11(zt%kk) )
- allocate( ztscr12(zt%kk) )
- allocate( ztscr13(zt%kk) )
- allocate( ztscr14(zt%kk) )
- allocate( ztscr15(zt%kk) )
- allocate( ztscr16(zt%kk) )
- allocate( ztscr17(zt%kk) )
- allocate( ztscr18(zt%kk) )
- allocate( ztscr19(zt%kk) )
- allocate( ztscr20(zt%kk) )
- allocate( ztscr21(zt%kk) )
+ allocate( ztscr01(stats_zt%kk) )
+ allocate( ztscr02(stats_zt%kk) )
+ allocate( ztscr03(stats_zt%kk) )
+ allocate( ztscr04(stats_zt%kk) )
+ allocate( ztscr05(stats_zt%kk) )
+ allocate( ztscr06(stats_zt%kk) )
+ allocate( ztscr07(stats_zt%kk) )
+ allocate( ztscr08(stats_zt%kk) )
+ allocate( ztscr09(stats_zt%kk) )
+ allocate( ztscr10(stats_zt%kk) )
+ allocate( ztscr11(stats_zt%kk) )
+ allocate( ztscr12(stats_zt%kk) )
+ allocate( ztscr13(stats_zt%kk) )
+ allocate( ztscr14(stats_zt%kk) )
+ allocate( ztscr15(stats_zt%kk) )
+ allocate( ztscr16(stats_zt%kk) )
+ allocate( ztscr17(stats_zt%kk) )
+ allocate( ztscr18(stats_zt%kk) )
+ allocate( ztscr19(stats_zt%kk) )
+ allocate( ztscr20(stats_zt%kk) )
+ allocate( ztscr21(stats_zt%kk) )
ztscr01 = 0.0_r8
ztscr02 = 0.0_r8
@@ -2214,54 +2875,54 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
! Initialize zm (momentum points)
i = 1
- do while ( ichar(clubb_vars_zm(i)(1:1)) /= 0 &
- .and. len_trim(clubb_vars_zm(i)) /= 0 &
- .and. i <= nvarmax_zm )
- i = i + 1
+ do while ( ichar(clubb_vars_zm(i)(1:1)) /= 0 .and. &
+ len_trim(clubb_vars_zm(i)) /= 0 .and. &
+ i <= nvarmax_zm )
+ i = i + 1
end do
ntot = i - 1
if ( ntot == nvarmax_zm ) then
- write(fstderr,*) "There are more statistical variables listed in ", &
- "clubb_vars_zm than allowed for by nvarmax_zm."
- write(fstderr,*) "Check the number of variables listed for clubb_vars_zm ", &
- "in the stats namelist, or change nvarmax_zm."
- write(fstderr,*) "nvarmax_zm = ", nvarmax_zm
- stop "stats_init_clubb: number of zm statistical variables exceeds limit"
+ write(fstderr,*) "There are more statistical variables listed in ", &
+ "clubb_vars_zm than allowed for by nvarmax_zm."
+ write(fstderr,*) "Check the number of variables listed for clubb_vars_zm ", &
+ "in the stats namelist, or change nvarmax_zm."
+ write(fstderr,*) "nvarmax_zm = ", nvarmax_zm
+ call endrun ("stats_init_clubb: number of zm statistical variables exceeds limit")
endif
- zm%nn = ntot
- zm%kk = nnzp
-
- allocate( zm%z( zm%kk ) )
+ stats_zm%num_output_fields = ntot
+ stats_zm%kk = nnzp
- allocate( zm%x( 1, 1, zm%kk, zm%nn ) )
- allocate( zm%n( 1, 1, zm%kk, zm%nn ) )
- allocate( zm%l_in_update( 1, 1, zm%kk, zm%nn ) )
+ allocate( stats_zm%z( stats_zm%kk ) )
- call stats_zero( zm%kk, zm%nn, zm%x, zm%n, zm%l_in_update )
+ allocate( stats_zm%accum_field_values( 1, 1, stats_zm%kk, stats_zm%num_output_fields ) )
+ allocate( stats_zm%accum_num_samples( 1, 1, stats_zm%kk, stats_zm%num_output_fields ) )
+ allocate( stats_zm%l_in_update( 1, 1, stats_zm%kk, stats_zm%num_output_fields ) )
+ call stats_zero( stats_zm%kk, stats_zm%num_output_fields, stats_zm%accum_field_values, &
+ stats_zm%accum_num_samples, stats_zm%l_in_update )
- allocate( zm%f%var( zm%nn ) )
- allocate( zm%f%z( zm%kk ) )
+ allocate( stats_zm%file%var( stats_zm%num_output_fields ) )
+ allocate( stats_zm%file%z( stats_zm%kk ) )
! Allocate scratch space
- allocate( zmscr01(zm%kk) )
- allocate( zmscr02(zm%kk) )
- allocate( zmscr03(zm%kk) )
- allocate( zmscr04(zm%kk) )
- allocate( zmscr05(zm%kk) )
- allocate( zmscr06(zm%kk) )
- allocate( zmscr07(zm%kk) )
- allocate( zmscr08(zm%kk) )
- allocate( zmscr09(zm%kk) )
- allocate( zmscr10(zm%kk) )
- allocate( zmscr11(zm%kk) )
- allocate( zmscr12(zm%kk) )
- allocate( zmscr13(zm%kk) )
- allocate( zmscr14(zm%kk) )
- allocate( zmscr15(zm%kk) )
- allocate( zmscr16(zm%kk) )
- allocate( zmscr17(zm%kk) )
+ allocate( zmscr01(stats_zm%kk) )
+ allocate( zmscr02(stats_zm%kk) )
+ allocate( zmscr03(stats_zm%kk) )
+ allocate( zmscr04(stats_zm%kk) )
+ allocate( zmscr05(stats_zm%kk) )
+ allocate( zmscr06(stats_zm%kk) )
+ allocate( zmscr07(stats_zm%kk) )
+ allocate( zmscr08(stats_zm%kk) )
+ allocate( zmscr09(stats_zm%kk) )
+ allocate( zmscr10(stats_zm%kk) )
+ allocate( zmscr11(stats_zm%kk) )
+ allocate( zmscr12(stats_zm%kk) )
+ allocate( zmscr13(stats_zm%kk) )
+ allocate( zmscr14(stats_zm%kk) )
+ allocate( zmscr15(stats_zm%kk) )
+ allocate( zmscr16(stats_zm%kk) )
+ allocate( zmscr17(stats_zm%kk) )
zmscr01 = 0.0_r8
zmscr02 = 0.0_r8
@@ -2287,110 +2948,112 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
if (l_output_rad_files) then
- i = 1
- do while ( ichar(clubb_vars_rad_zt(i)(1:1)) /= 0 &
- .and. len_trim(clubb_vars_rad_zt(i)) /= 0 &
- .and. i <= nvarmax_rad_zt )
- i = i + 1
- end do
- ntot = i - 1
- if ( ntot == nvarmax_rad_zt ) then
- write(fstderr,*) "There are more statistical variables listed in ", &
- "clubb_vars_rad_zt than allowed for by nvarmax_rad_zt."
- write(fstderr,*) "Check the number of variables listed for clubb_vars_rad_zt ", &
- "in the stats namelist, or change nvarmax_rad_zt."
- write(fstderr,*) "nvarmax_rad_zt = ", nvarmax_rad_zt
- stop "stats_init_clubb: number of rad_zt statistical variables exceeds limit"
- endif
-
- rad_zt%nn = ntot
- rad_zt%kk = nnrad_zt
-
- allocate( rad_zt%z( rad_zt%kk ) )
-
- allocate( rad_zt%x( 1, 1, rad_zt%kk, rad_zt%nn ) )
- allocate( rad_zt%n( 1, 1, rad_zt%kk, rad_zt%nn ) )
- allocate( rad_zt%l_in_update( 1, 1, rad_zt%kk, rad_zt%nn ) )
-
- call stats_zero( rad_zt%kk, rad_zt%nn, rad_zt%x, rad_zt%n, rad_zt%l_in_update )
+ i = 1
+ do while ( ichar(clubb_vars_rad_zt(i)(1:1)) /= 0 .and. &
+ len_trim(clubb_vars_rad_zt(i)) /= 0 .and. &
+ i <= nvarmax_rad_zt )
+ i = i + 1
+ end do
+ ntot = i - 1
+ if ( ntot == nvarmax_rad_zt ) then
+ write(fstderr,*) "There are more statistical variables listed in ", &
+ "clubb_vars_rad_zt than allowed for by nvarmax_rad_zt."
+ write(fstderr,*) "Check the number of variables listed for clubb_vars_rad_zt ", &
+ "in the stats namelist, or change nvarmax_rad_zt."
+ write(fstderr,*) "nvarmax_rad_zt = ", nvarmax_rad_zt
+ call endrun ("stats_init_clubb: number of rad_zt statistical variables exceeds limit")
+ endif
- allocate( rad_zt%f%var( rad_zt%nn ) )
- allocate( rad_zt%f%z( rad_zt%kk ) )
+ stats_rad_zt%num_output_fields = ntot
+ stats_rad_zt%kk = nnrad_zt
- fname = trim( fname_rad_zt )
+ allocate( stats_rad_zt%z( stats_rad_zt%kk ) )
- call stats_init_rad_zt( clubb_vars_rad_zt, l_error )
+ allocate( stats_rad_zt%accum_field_values( 1, 1, stats_rad_zt%kk, stats_rad_zt%num_output_fields ) )
+ allocate( stats_rad_zt%accum_num_samples( 1, 1, stats_rad_zt%kk, stats_rad_zt%num_output_fields ) )
+ allocate( stats_rad_zt%l_in_update( 1, 1, stats_rad_zt%kk, stats_rad_zt%num_output_fields ) )
- ! Initialize rad_zm (radiation points)
+ call stats_zero( stats_rad_zt%kk, stats_rad_zt%num_output_fields, stats_rad_zt%accum_field_values, &
+ stats_rad_zt%accum_num_samples, stats_rad_zt%l_in_update )
- i = 1
- do while ( ichar(clubb_vars_rad_zm(i)(1:1)) /= 0 &
- .and. len_trim(clubb_vars_rad_zm(i)) /= 0 &
- .and. i <= nvarmax_rad_zm )
- i = i + 1
- end do
- ntot = i - 1
- if ( ntot == nvarmax_rad_zm ) then
- write(fstderr,*) "There are more statistical variables listed in ", &
- "clubb_vars_rad_zm than allowed for by nvarmax_rad_zm."
- write(fstderr,*) "Check the number of variables listed for clubb_vars_rad_zm ", &
- "in the stats namelist, or change nvarmax_rad_zm."
- write(fstderr,*) "nvarmax_rad_zm = ", nvarmax_rad_zm
- stop "stats_init_clubb: number of rad_zm statistical variables exceeds limit"
- endif
+ allocate( stats_rad_zt%file%var( stats_rad_zt%num_output_fields ) )
+ allocate( stats_rad_zt%file%z( stats_rad_zt%kk ) )
- rad_zm%nn = ntot
- rad_zm%kk = nnrad_zm
+ fname = trim( fname_rad_zt )
- allocate( rad_zm%z( rad_zm%kk ) )
+ call stats_init_rad_zt( clubb_vars_rad_zt, l_error )
- allocate( rad_zm%x( 1, 1, rad_zm%kk, rad_zm%nn ) )
- allocate( rad_zm%n( 1, 1, rad_zm%kk, rad_zm%nn ) )
- allocate( rad_zm%l_in_update( 1, 1, rad_zm%kk, rad_zm%nn ) )
+ ! Initialize rad_zm (radiation points)
+
+ i = 1
+ do while ( ichar(clubb_vars_rad_zm(i)(1:1)) /= 0 .and. &
+ len_trim(clubb_vars_rad_zm(i)) /= 0 .and. &
+ i <= nvarmax_rad_zm )
+ i = i + 1
+ end do
+ ntot = i - 1
+ if ( ntot == nvarmax_rad_zm ) then
+ write(fstderr,*) "There are more statistical variables listed in ", &
+ "clubb_vars_rad_zm than allowed for by nvarmax_rad_zm."
+ write(fstderr,*) "Check the number of variables listed for clubb_vars_rad_zm ", &
+ "in the stats namelist, or change nvarmax_rad_zm."
+ write(fstderr,*) "nvarmax_rad_zm = ", nvarmax_rad_zm
+ call endrun ("stats_init_clubb: number of rad_zm statistical variables exceeds limit")
+ endif
- call stats_zero( rad_zm%kk, rad_zm%nn, rad_zm%x, rad_zm%n, rad_zm%l_in_update )
+ stats_rad_zm%num_output_fields = ntot
+ stats_rad_zm%kk = nnrad_zm
- allocate( rad_zm%f%var( rad_zm%nn ) )
- allocate( rad_zm%f%z( rad_zm%kk ) )
+ allocate( stats_rad_zm%z( stats_rad_zm%kk ) )
+ allocate( stats_rad_zm%accum_field_values( 1, 1, stats_rad_zm%kk, stats_rad_zm%num_output_fields ) )
+ allocate( stats_rad_zm%accum_num_samples( 1, 1, stats_rad_zm%kk, stats_rad_zm%num_output_fields ) )
+ allocate( stats_rad_zm%l_in_update( 1, 1, stats_rad_zm%kk, stats_rad_zm%num_output_fields ) )
- fname = trim( fname_rad_zm )
+ call stats_zero( stats_rad_zm%kk, stats_rad_zm%num_output_fields, stats_rad_zm%accum_field_values, &
+ stats_rad_zm%accum_num_samples, stats_rad_zm%l_in_update )
- call stats_init_rad_zm( clubb_vars_rad_zm, l_error )
+ allocate( stats_rad_zm%file%var( stats_rad_zm%num_output_fields ) )
+ allocate( stats_rad_zm%file%z( stats_rad_zm%kk ) )
+
+ fname = trim( fname_rad_zm )
+
+ call stats_init_rad_zm( clubb_vars_rad_zm, l_error )
end if ! l_output_rad_files
! Initialize sfc (surface point)
i = 1
- do while ( ichar(clubb_vars_sfc(i)(1:1)) /= 0 &
- .and. len_trim(clubb_vars_sfc(i)) /= 0 &
- .and. i <= nvarmax_sfc )
- i = i + 1
+ do while ( ichar(clubb_vars_sfc(i)(1:1)) /= 0 .and. &
+ len_trim(clubb_vars_sfc(i)) /= 0 .and. &
+ i <= nvarmax_sfc )
+ i = i + 1
end do
ntot = i - 1
if ( ntot == nvarmax_sfc ) then
- write(fstderr,*) "There are more statistical variables listed in ", &
- "clubb_vars_sfc than allowed for by nvarmax_sfc."
- write(fstderr,*) "Check the number of variables listed for clubb_vars_sfc ", &
- "in the stats namelist, or change nvarmax_sfc."
- write(fstderr,*) "nvarmax_sfc = ", nvarmax_sfc
- stop "stats_init_clubb: number of sfc statistical variables exceeds limit"
+ write(fstderr,*) "There are more statistical variables listed in ", &
+ "clubb_vars_sfc than allowed for by nvarmax_sfc."
+ write(fstderr,*) "Check the number of variables listed for clubb_vars_sfc ", &
+ "in the stats namelist, or change nvarmax_sfc."
+ write(fstderr,*) "nvarmax_sfc = ", nvarmax_sfc
+ call endrun ("stats_init_clubb: number of sfc statistical variables exceeds limit")
endif
- sfc%nn = ntot
- sfc%kk = 1
+ stats_sfc%num_output_fields = ntot
+ stats_sfc%kk = 1
- allocate( sfc%z( sfc%kk ) )
+ allocate( stats_sfc%z( stats_sfc%kk ) )
- allocate( sfc%x( 1, 1, sfc%kk, sfc%nn ) )
- allocate( sfc%n( 1, 1, sfc%kk, sfc%nn ) )
- allocate( sfc%l_in_update( 1, 1, sfc%kk, sfc%nn ) )
+ allocate( stats_sfc%accum_field_values( 1, 1, stats_sfc%kk, stats_sfc%num_output_fields ) )
+ allocate( stats_sfc%accum_num_samples( 1, 1, stats_sfc%kk, stats_sfc%num_output_fields ) )
+ allocate( stats_sfc%l_in_update( 1, 1, stats_sfc%kk, stats_sfc%num_output_fields ) )
- call stats_zero( sfc%kk, sfc%nn, sfc%x, sfc%n, sfc%l_in_update )
+ call stats_zero( stats_sfc%kk, stats_sfc%num_output_fields, stats_sfc%accum_field_values, &
+ stats_sfc%accum_num_samples, stats_sfc%l_in_update )
- allocate( sfc%f%var( sfc%nn ) )
- allocate( sfc%f%z( sfc%kk ) )
+ allocate( stats_sfc%file%var( stats_sfc%num_output_fields ) )
+ allocate( stats_sfc%file%z( stats_sfc%kk ) )
fname = trim( fname_sfc )
@@ -2399,46 +3062,45 @@ subroutine stats_init_clubb( l_stats_in, stats_tsamp_in, stats_tout_in, &
! Check for errors
if ( l_error ) then
- write(fstderr,*) 'stats_init: errors found'
- stop
+ call endrun ('stats_init: errors found')
endif
! Now call add fields
- do i = 1, zt%nn
+ do i = 1, stats_zt%num_output_fields
- temp1 = trim(zt%f%var(i)%name)
+ temp1 = trim(stats_zt%file%var(i)%name)
sub = temp1
if (len(temp1) .gt. 16) sub = temp1(1:16)
- call addfld(trim(sub),trim(zt%f%var(i)%units),nnzp,&
- 'A',trim(zt%f%var(i)%description),phys_decomp)
+ call addfld(trim(sub),trim(stats_zt%file%var(i)%units),nnzp,&
+ 'A',trim(stats_zt%file%var(i)%description),phys_decomp)
enddo
- do i = 1, zm%nn
+ do i = 1, stats_zm%num_output_fields
- temp1 = trim(zm%f%var(i)%name)
+ temp1 = trim(stats_zm%file%var(i)%name)
sub = temp1
if (len(temp1) .gt. 16) sub = temp1(1:16)
- call addfld(trim(sub),trim(zm%f%var(i)%units),nnzp,&
- 'A',trim(zm%f%var(i)%description),phys_decomp)
+ call addfld(trim(sub),trim(stats_zm%file%var(i)%units),nnzp,&
+ 'A',trim(stats_zm%file%var(i)%description),phys_decomp)
enddo
if (l_output_rad_files) then
- do i = 1, rad_zt%nn
- call addfld(trim(rad_zt%f%var(i)%name),trim(rad_zt%f%var(i)%units),nnzp,&
- 'A',trim(rad_zt%f%var(i)%description),phys_decomp)
+ do i = 1, stats_rad_zt%num_output_fields
+ call addfld(trim(stats_rad_zt%file%var(i)%name),trim(stats_rad_zt%file%var(i)%units),nnzp,&
+ 'A',trim(stats_rad_zt%file%var(i)%description),phys_decomp)
enddo
- do i = 1, rad_zm%nn
- call addfld(trim(rad_zm%f%var(i)%name),trim(rad_zm%f%var(i)%units),nnzp,&
- 'A',trim(rad_zm%f%var(i)%description),phys_decomp)
+ do i = 1, stats_rad_zm%num_output_fields
+ call addfld(trim(stats_rad_zm%file%var(i)%name),trim(stats_rad_zm%file%var(i)%units),nnzp,&
+ 'A',trim(stats_rad_zm%file%var(i)%description),phys_decomp)
enddo
endif
- do i = 1, sfc%nn
- call addfld(trim(sfc%f%var(i)%name),trim(sfc%f%var(i)%units),1,&
- 'A',trim(sfc%f%var(i)%description),phys_decomp)
+ do i = 1, stats_sfc%num_output_fields
+ call addfld(trim(stats_sfc%file%var(i)%name),trim(stats_sfc%file%var(i)%units),1,&
+ 'A',trim(stats_sfc%file%var(i)%description),phys_decomp)
enddo
return
@@ -2467,11 +3129,11 @@ subroutine stats_end_timestep_clubb(lchnk,thecol,out_zt,out_zm,out_radzt,out_rad
fstderr ! Constant(s)
use stats_variables, only: &
- zt, & ! Variable(s)
- zm, &
- rad_zt, &
- rad_zm, &
- sfc, &
+ stats_zt, & ! Variable(s)
+ stats_zm, &
+ stats_rad_zt, &
+ stats_rad_zm, &
+ stats_sfc, &
l_stats_last, &
stats_tsamp, &
stats_tout, &
@@ -2479,10 +3141,12 @@ subroutine stats_end_timestep_clubb(lchnk,thecol,out_zt,out_zm,out_radzt,out_rad
use error_code, only: &
clubb_at_least_debug_level ! Procedure(s)
-
- use cam_history, only: outfld
+
+ use cam_history, only: outfld
- use ppgrid, only: pcols, pverp
+ use ppgrid, only: pcols, pverp
+
+ use cam_abortutils, only: endrun
implicit none
@@ -2513,19 +3177,19 @@ subroutine stats_end_timestep_clubb(lchnk,thecol,out_zt,out_zm,out_radzt,out_rad
! Look for errors by checking the number of sampling points
! for each variable in the zt statistics at each vertical level.
- do i = 1, zt%nn
- do k = 1, zt%kk
+ do i = 1, stats_zt%num_output_fields
+ do k = 1, stats_zt%kk
- if ( zt%n(1,1,k,i) /= 0 .and. &
- zt%n(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
+ if ( stats_zt%accum_num_samples(1,1,k,i) /= 0 .and. &
+ stats_zt%accum_num_samples(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
l_error = .true. ! This will stop the run
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) 'Possible sampling error for variable ', &
- trim(zt%f%var(i)%name), ' in zt ', &
+ trim(stats_zt%file%var(i)%name), ' in zt ', &
'at k = ', k, &
- '; zt%n(',k,',',i,') = ', zt%n(1,1,k,i)
+ '; stats_zt%accum_num_samples(',k,',',i,') = ', stats_zt%accum_num_samples(1,1,k,i)
endif
endif
@@ -2535,19 +3199,19 @@ subroutine stats_end_timestep_clubb(lchnk,thecol,out_zt,out_zm,out_radzt,out_rad
! Look for errors by checking the number of sampling points
! for each variable in the zm statistics at each vertical level.
- do i = 1, zm%nn
- do k = 1, zm%kk
+ do i = 1, stats_zm%num_output_fields
+ do k = 1, stats_zm%kk
- if ( zm%n(1,1,k,i) /= 0 .and. &
- zm%n(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
+ if ( stats_zm%accum_num_samples(1,1,k,i) /= 0 .and. &
+ stats_zm%accum_num_samples(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
l_error = .true. ! This will stop the run
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) 'Possible sampling error for variable ', &
- trim(zm%f%var(i)%name), ' in zm ', &
+ trim(stats_zm%file%var(i)%name), ' in zm ', &
'at k = ', k, &
- '; zm%n(',k,',',i,') = ', zm%n(1,1,k,i)
+ '; stats_zm%accum_num_samples(',k,',',i,') = ', stats_zm%accum_num_samples(1,1,k,i)
endif
endif
@@ -2558,19 +3222,19 @@ subroutine stats_end_timestep_clubb(lchnk,thecol,out_zt,out_zm,out_radzt,out_rad
if (l_output_rad_files) then
! Look for errors by checking the number of sampling points
! for each variable in the rad_zt statistics at each vertical level.
- do i = 1, rad_zt%nn
- do k = 1, rad_zt%kk
+ do i = 1, stats_rad_zt%num_output_fields
+ do k = 1, stats_rad_zt%kk
- if ( rad_zt%n(1,1,k,i) /= 0 .and. &
- rad_zt%n(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
+ if ( stats_rad_zt%accum_num_samples(1,1,k,i) /= 0 .and. &
+ stats_rad_zt%accum_num_samples(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
l_error = .true. ! This will stop the run
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) 'Possible sampling error for variable ', &
- trim(rad_zt%f%var(i)%name), ' in rad_zt ', &
+ trim(stats_rad_zt%file%var(i)%name), ' in rad_zt ', &
'at k = ', k, &
- '; rad_zt%n(',k,',',i,') = ', rad_zt%n(1,1,k,i)
+ '; stats_rad_zt%accum_num_samples(',k,',',i,') = ', stats_rad_zt%accum_num_samples(1,1,k,i)
endif
endif
@@ -2580,42 +3244,42 @@ subroutine stats_end_timestep_clubb(lchnk,thecol,out_zt,out_zm,out_radzt,out_rad
! Look for errors by checking the number of sampling points
! for each variable in the rad_zm statistics at each vertical level.
- do i = 1, rad_zm%nn
- do k = 1, rad_zm%kk
+ do i = 1, stats_rad_zm%num_output_fields
+ do k = 1, stats_rad_zm%kk
- if ( rad_zm%n(1,1,k,i) /= 0 .and. &
- rad_zm%n(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
+ if ( stats_rad_zm%accum_num_samples(1,1,k,i) /= 0 .and. &
+ stats_rad_zm%accum_num_samples(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
l_error = .true. ! This will stop the run
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) 'Possible sampling error for variable ', &
- trim(rad_zm%f%var(i)%name), ' in rad_zm ', &
+ trim(stats_rad_zm%file%var(i)%name), ' in rad_zm ', &
'at k = ', k, &
- '; rad_zm%n(',k,',',i,') = ', rad_zm%n(1,1,k,i)
+ '; stats_rad_zm%accum_num_samples(',k,',',i,') = ', stats_rad_zm%accum_num_samples(1,1,k,i)
endif
endif
enddo
enddo
- end if ! l_output_rad_files
+ end if ! l_output_rad_files
! Look for errors by checking the number of sampling points
! for each variable in the sfc statistics at each vertical level.
- do i = 1, sfc%nn
- do k = 1, sfc%kk
+ do i = 1, stats_sfc%num_output_fields
+ do k = 1, stats_sfc%kk
- if ( sfc%n(1,1,k,i) /= 0 .and. &
- sfc%n(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
+ if ( stats_sfc%accum_num_samples(1,1,k,i) /= 0 .and. &
+ stats_sfc%accum_num_samples(1,1,k,i) /= floor(stats_tout/stats_tsamp) ) then
l_error = .true. ! This will stop the run
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) 'Possible sampling error for variable ', &
- trim(sfc%f%var(i)%name), ' in sfc ', &
+ trim(stats_sfc%file%var(i)%name), ' in sfc ', &
'at k = ', k, &
- '; sfc%n(',k,',',i,') = ', sfc%n(1,1,k,i)
+ '; stats_sfc%accum_num_samples(',k,',',i,') = ', stats_sfc%accum_num_samples(1,1,k,i)
endif
endif
@@ -2625,68 +3289,74 @@ subroutine stats_end_timestep_clubb(lchnk,thecol,out_zt,out_zm,out_radzt,out_rad
! Stop the run if errors are found.
if ( l_error ) then
- write(fstderr,*) 'Possible statistical sampling error'
- write(fstderr,*) 'For details, set debug_level to a value of at ', &
- 'least 1 in the appropriate model.in file.'
- stop 'stats_end_timestep: error(s) found'
+ write(fstderr,*) 'Possible statistical sampling error'
+ write(fstderr,*) 'For details, set debug_level to a value of at ', &
+ 'least 1 in the appropriate model.in file.'
+ call endrun ('stats_end_timestep: error(s) found')
endif
! Compute averages
- call stats_avg( zt%kk, zt%nn, zt%x, zt%n )
- call stats_avg( zm%kk, zm%nn, zm%x, zm%n )
+ call stats_avg( stats_zt%kk, stats_zt%num_output_fields, stats_zt%accum_field_values, stats_zt%accum_num_samples )
+ call stats_avg( stats_zm%kk, stats_zm%num_output_fields, stats_zm%accum_field_values, stats_zm%accum_num_samples )
if (l_output_rad_files) then
- call stats_avg( rad_zt%kk, rad_zt%nn, rad_zt%x, rad_zt%n )
- call stats_avg( rad_zm%kk, rad_zm%nn, rad_zm%x, rad_zm%n )
+ call stats_avg( stats_rad_zt%kk, stats_rad_zt%num_output_fields, stats_rad_zt%accum_field_values, &
+ stats_rad_zt%accum_num_samples )
+ call stats_avg( stats_rad_zm%kk, stats_rad_zm%num_output_fields, stats_rad_zm%accum_field_values, &
+ stats_rad_zm%accum_num_samples )
end if
- call stats_avg( sfc%kk, sfc%nn, sfc%x, sfc%n )
+ call stats_avg( stats_sfc%kk, stats_sfc%num_output_fields, stats_sfc%accum_field_values, stats_sfc%accum_num_samples )
! Here we are not outputting the data, rather reading the stats into
! arrays which are conformable to CAM output. Also, the data is "flipped"
! in the vertical level to be the same as CAM output.
- do i = 1, zt%nn
- do k = 1, zt%kk
- out_zt(thecol,k,i) = zt%x(1,1,zt%kk-k+1,i)
- if(out_zt(thecol,k,i) .ne. out_zt(thecol,k,i)) out_zt(thecol,k,i) = 0.0_r8
+ do i = 1, stats_zt%num_output_fields
+ do k = 1, stats_zt%kk
+ out_zt(thecol,k,i) = stats_zt%accum_field_values(1,1,stats_zt%kk-k+1,i)
+ if(out_zt(thecol,k,i) .ne. out_zt(thecol,k,i)) out_zt(thecol,k,i) = 0.0_r8
enddo
enddo
- do i = 1, zm%nn
- do k = 1, zt%kk
- out_zm(thecol,k,i) = zm%x(1,1,zt%kk-k+1,i)
- if(out_zm(thecol,k,i) .ne. out_zm(thecol,k,i)) out_zm(thecol,k,i) = 0.0_r8
+ do i = 1, stats_zm%num_output_fields
+ do k = 1, stats_zt%kk
+ out_zm(thecol,k,i) = stats_zm%accum_field_values(1,1,stats_zt%kk-k+1,i)
+ if(out_zm(thecol,k,i) .ne. out_zm(thecol,k,i)) out_zm(thecol,k,i) = 0.0_r8
enddo
enddo
if (l_output_rad_files) then
- do i = 1, rad_zt%nn
- do k = 1, rad_zt%kk
- out_radzt(thecol,k,i) = rad_zt%x(1,1,zt%kk-k+1,i)
- if(out_radzt(thecol,k,i) .ne. out_radzt(thecol,k,i)) out_radzt(thecol,k,i) = 0.0_r8
+ do i = 1, stats_rad_zt%num_output_fields
+ do k = 1, stats_rad_zt%kk
+ out_radzt(thecol,k,i) = stats_rad_zt%accum_field_values(1,1,stats_zt%kk-k+1,i)
+ if(out_radzt(thecol,k,i) .ne. out_radzt(thecol,k,i)) out_radzt(thecol,k,i) = 0.0_r8
enddo
enddo
- do i = 1, rad_zm%nn
- do k = 1, rad_zm%kk
- out_radzm(thecol,k,i) = rad_zm%x(1,1,zt%kk-k+1,i)
- if(out_radzm(thecol,k,i) .ne. out_radzm(thecol,k,i)) out_radzm(thecol,k,i) = 0.0_r8
+ do i = 1, stats_rad_zm%num_output_fields
+ do k = 1, stats_rad_zm%kk
+ out_radzm(thecol,k,i) = stats_rad_zm%accum_field_values(1,1,stats_zt%kk-k+1,i)
+ if(out_radzm(thecol,k,i) .ne. out_radzm(thecol,k,i)) out_radzm(thecol,k,i) = 0.0_r8
enddo
enddo
endif
- do i = 1, sfc%nn
- out_sfc(thecol,1,i) = sfc%x(1,1,1,i)
+ do i = 1, stats_sfc%num_output_fields
+ out_sfc(thecol,1,i) = stats_sfc%accum_field_values(1,1,1,i)
if(out_sfc(thecol,1,i) .ne. out_sfc(thecol,1,i)) out_sfc(thecol,1,i) = 0.0_r8
enddo
! Reset sample fields
- call stats_zero( zt%kk, zt%nn, zt%x, zt%n, zt%l_in_update )
- call stats_zero( zm%kk, zm%nn, zm%x, zm%n, zm%l_in_update )
+ call stats_zero( stats_zt%kk, stats_zt%num_output_fields, stats_zt%accum_field_values, &
+ stats_zt%accum_num_samples, stats_zt%l_in_update )
+ call stats_zero( stats_zm%kk, stats_zm%num_output_fields, stats_zm%accum_field_values, &
+ stats_zm%accum_num_samples, stats_zm%l_in_update )
if (l_output_rad_files) then
- call stats_zero( rad_zt%kk, rad_zt%nn, rad_zt%x, rad_zt%n, rad_zt%l_in_update )
- call stats_zero( rad_zm%kk, rad_zm%nn, rad_zm%x, rad_zm%n, rad_zm%l_in_update )
+ call stats_zero( stats_rad_zt%kk, stats_rad_zt%num_output_fields, stats_rad_zt%accum_field_values, &
+ stats_rad_zt%accum_num_samples, stats_rad_zt%l_in_update )
+ call stats_zero( stats_rad_zm%kk, stats_rad_zm%num_output_fields, stats_rad_zm%accum_field_values, &
+ stats_rad_zm%accum_num_samples, stats_rad_zm%l_in_update )
end if
- call stats_zero( sfc%kk, sfc%nn, sfc%x, sfc%n, sfc%l_in_update )
-
+ call stats_zero( stats_sfc%kk, stats_sfc%num_output_fields, stats_sfc%accum_field_values, &
+ stats_sfc%accum_num_samples, stats_sfc%l_in_update )
return
@@ -2719,16 +3389,16 @@ subroutine stats_zero( kk, nn, x, n, l_in_update )
integer, intent(in) :: kk, nn
! Output
- real(kind=stat_rknd), dimension(1,1,kk,nn), intent(out) :: x
+ real(kind=stat_rknd), dimension(1,1,kk,nn), intent(out) :: x
integer(kind=stat_nknd), dimension(1,1,kk,nn), intent(out) :: n
- logical, dimension(1,1,kk,nn), intent(out) :: l_in_update
+ logical, dimension(1,1,kk,nn), intent(out) :: l_in_update
! Zero out arrays
if ( nn > 0 ) then
- x(:,:,:,:) = 0.0_r8
- n(:,:,:,:) = 0
- l_in_update(:,:,:,:) = .false.
+ x(:,:,:,:) = 0.0_r8
+ n(:,:,:,:) = 0
+ l_in_update(:,:,:,:) = .false.
end if
return
@@ -2769,13 +3439,13 @@ subroutine stats_avg( kk, nn, x, n )
! Compute averages
do m=1,nn
- do k=1,kk
+ do k=1,kk
- if ( n(1,1,k,m) > 0 ) then
- x(1,1,k,m) = x(1,1,k,m) / real( n(1,1,k,m) )
- end if
+ if ( n(1,1,k,m) > 0 ) then
+ x(1,1,k,m) = x(1,1,k,m) / real( n(1,1,k,m) )
+ end if
- end do
+ end do
end do
return
diff --git a/models/atm/cam/src/physics/cam/convect_deep.F90 b/models/atm/cam/src/physics/cam/convect_deep.F90
index fe67671d14c4..bf72b911af46 100644
--- a/models/atm/cam/src/physics/cam/convect_deep.F90
+++ b/models/atm/cam/src/physics/cam/convect_deep.F90
@@ -131,6 +131,8 @@ subroutine convect_deep_init(pref_edge)
select case ( deep_scheme )
case('off') ! ==> no deep convection
if (masterproc) write(iulog,*)'convect_deep: no deep convection selected'
+ case('CLUBB_SGS')
+ if (masterproc) write(iulog,*)'convect_deep: CLUBB_SGS selected'
case('ZM') ! 1 ==> Zhang-McFarlane (default)
if (masterproc) write(iulog,*)'convect_deep initializing Zhang-McFarlane convection'
call zm_conv_init(pref_edge)
@@ -202,18 +204,19 @@ subroutine convect_deep_tend( &
real(r8), pointer :: pblh(:) ! Planetary boundary layer height
real(r8), pointer :: tpert(:) ! Thermal temperature excess
- real(r8) zero(pcols, pver)
+ ! Temperature tendency from deep convection (pbuf pointer).
+ real(r8), pointer, dimension(:,:) :: ttend_dp
- integer i, k
+ real(r8) zero(pcols, pver)
- real(r8), pointer, dimension(:,:) :: ttend_dp
+ integer i, k
call pbuf_get_field(pbuf, cldtop_idx, jctop )
call pbuf_get_field(pbuf, cldbot_idx, jcbot )
call pbuf_get_field(pbuf, icwmrdp_idx, ql )
select case ( deep_scheme )
- case('off') ! 0 ==> no deep convection
+ case('off', 'CLUBB_SGS') ! 0 ==> no deep convection
zero = 0
mcon = 0
dlf = 0
@@ -274,7 +277,7 @@ end subroutine convect_deep_tend
subroutine convect_deep_tend_2( state, ptend, ztodt, pbuf)
- use physics_types, only: physics_state, physics_ptend
+ use physics_types, only: physics_state, physics_ptend, physics_ptend_init
use physics_buffer, only: physics_buffer_desc
use constituents, only: pcnst
@@ -290,6 +293,8 @@ subroutine convect_deep_tend_2( state, ptend, ztodt, pbuf)
if ( deep_scheme .eq. 'ZM' ) then ! 1 ==> Zhang-McFarlane (default)
call zm_conv_tend_2( state, ptend, ztodt, pbuf)
+ else
+ call physics_ptend_init(ptend, state%psetcols, 'convect_deep')
end if
diff --git a/models/atm/cam/src/physics/cam/convect_shallow.F90 b/models/atm/cam/src/physics/cam/convect_shallow.F90
index 7d735e0691a8..5f4de1c30ac0 100644
--- a/models/atm/cam/src/physics/cam/convect_shallow.F90
+++ b/models/atm/cam/src/physics/cam/convect_shallow.F90
@@ -14,7 +14,7 @@ module convect_shallow
use physconst, only : cpair, zvir
use ppgrid, only : pver, pcols, pverp
use zm_conv, only : zm_conv_evap
- use cam_history, only : outfld, addfld, add_default, phys_decomp
+ use cam_history, only : outfld, addfld, phys_decomp
use cam_logfile, only : iulog
use phys_control, only : phys_getopts
@@ -57,6 +57,7 @@ module convect_shallow
integer :: pblh_idx = 0
integer :: prec_sh_idx = 0
integer :: snow_sh_idx = 0
+ integer :: cmfmc_sh_idx = 0
integer :: & ! field index in physics buffer
sh_flxprc_idx, &
@@ -78,8 +79,6 @@ subroutine convect_shallow_register
use physics_buffer, only : pbuf_add_field, dtype_r8, dyn_time_lvls
- implicit none
-
call phys_getopts( shallow_scheme_out = shallow_scheme, microp_scheme_out = microp_scheme)
@@ -92,6 +91,8 @@ subroutine convect_shallow_register
call pbuf_add_field('NEVAPR_SHCU','physpkg' ,dtype_r8,(/pcols,pver/), nevapr_shcu_idx )
call pbuf_add_field('PREC_SH', 'physpkg' ,dtype_r8,(/pcols/), prec_sh_idx )
call pbuf_add_field('SNOW_SH', 'physpkg' ,dtype_r8,(/pcols/), snow_sh_idx )
+ ! Updraft mass flux by shallow convection [ kg/s/m2 ]
+ call pbuf_add_field('CMFMC_SH', 'physpkg' ,dtype_r8,(/pcols,pverp/), cmfmc_sh_idx )
if( shallow_scheme .eq. 'UW' ) then
call pbuf_add_field('shfrc','physpkg' ,dtype_r8,(/pcols,pver/),shfrc_idx )
@@ -136,8 +137,6 @@ subroutine convect_shallow_init(pref_edge)
use physics_buffer, only : pbuf_get_index, physics_buffer_desc, pbuf_set_field
use time_manager, only : is_first_step
- implicit none
-
real(r8), intent(in) :: pref_edge(plevp) ! Reference pressures at interfaces
integer limcnv ! Top interface level limit for convection
@@ -200,7 +199,7 @@ subroutine convect_shallow_init(pref_edge)
call addfld( 'PRECSH ' , 'm/s ', 1, 'A' , &
'Shallow Convection precipitation rate' , phys_decomp )
call addfld( 'CMFMC ' , 'kg/m2/s ', pverp, 'A' , &
- 'Moist shallow convection mass flux' , phys_decomp )
+ 'Moist convection (deep+shallow) mass flux' , phys_decomp )
call addfld( 'CMFSL ' , 'W/m2 ', pverp, 'A' , &
'Moist shallow convection liquid water static energy flux' , phys_decomp )
call addfld( 'CMFLQ ' , 'W/m2 ', pverp, 'A' , &
@@ -461,6 +460,8 @@ subroutine convect_shallow_tend( ztodt , cmfmc , cmfmc2 , &
real(r8), pointer, dimension(:,:) :: sh_cldliq
real(r8), pointer, dimension(:,:) :: sh_cldice
+ real(r8), pointer, dimension(:,:) :: cmfmc2_sh ! (pcols,pverp) Updraft mass flux by shallow convection [ kg/s/m2 ]
+
logical :: lq(pcnst)
! ----------------------- !
@@ -501,6 +502,8 @@ subroutine convect_shallow_tend( ztodt , cmfmc , cmfmc2 , &
call pbuf_get_field(pbuf, shfrc_idx, shfrc )
endif
+ call pbuf_get_field(pbuf, cmfmc_sh_idx, cmfmc2_sh)
+
! Initialization
@@ -625,13 +628,15 @@ subroutine convect_shallow_tend( ztodt , cmfmc , cmfmc2 , &
! Convective fluxes of 'sl' and 'qt' in energy unit !
! ------------------------------------------------- !
- cmfsl(:ncol,:pverp) = slflx(:ncol,:pverp)
- cmflq(:ncol,:pverp) = qtflx(:ncol,:pverp) * latvap
+ cmfsl(:ncol,:) = slflx(:ncol,:)
+ cmflq(:ncol,:) = qtflx(:ncol,:) * latvap
call outfld( 'PRECSH' , precc , pcols, lchnk )
end select
+ cmfmc2_sh = cmfmc2
+
! --------------------------------------------------------!
! Calculate fractional occurance of shallow convection !
! --------------------------------------------------------!
diff --git a/models/atm/cam/src/physics/cam/dynamic_vector_procdef.inc b/models/atm/cam/src/physics/cam/dynamic_vector_procdef.inc
new file mode 100644
index 000000000000..81d71dce48c0
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/dynamic_vector_procdef.inc
@@ -0,0 +1,583 @@
+! Type-bound procedures for a dynamic vector.
+
+#ifdef USE_PURE
+#define PURE pure
+#else
+#define PURE
+#endif
+
+! Construct an empty vector.
+PURE function new_vector_default() result(new_vec)
+ ! Create an empty vector
+ type( VECTOR_NAME ) :: new_vec
+
+ ! Currently, this does nothing. But some compilers may do weird things if
+ ! you don't "define" new_vec somehow, and clearing the vector is safe.
+ call new_vec%clear()
+
+end function new_vector_default
+
+! Construct a vector from another vector.
+PURE function new_vector_copy(vec) result(new_vec)
+ ! Create a vector from a pre-existing array.
+ type( VECTOR_NAME ), intent(in) :: vec
+ type( VECTOR_NAME ) :: new_vec
+
+ new_vec = vec
+
+end function new_vector_copy
+
+! Construct a vector from an array.
+PURE function new_vector_array(array) result(new_vec)
+ ! Create a vector from a pre-existing array.
+ TYPE_NAME, intent(in) :: array(:)
+ type( VECTOR_NAME ) :: new_vec
+
+ new_vec = array
+
+end function new_vector_array
+
+! Query if the vector is empty.
+PURE function empty_vec(self) result(is_empty)
+ class( VECTOR_NAME ), intent(in) :: self
+ logical :: is_empty
+
+ is_empty = (self%vec_size == 0)
+
+end function empty_vec
+
+! Get size of the vector.
+PURE function size_vec(self) result(vec_size)
+ class( VECTOR_NAME ), intent(in) :: self
+ integer :: vec_size
+
+ vec_size = self%vec_size
+
+end function size_vec
+
+! Get maximum size the vector can have.
+PURE function max_size_vec(self) result(max_size)
+ class( VECTOR_NAME ), intent(in) :: self
+ integer :: max_size
+
+ ! The only theoretical limitation that can be determined without a system
+ ! call is the maximum size of an integer.
+ max_size = huge(self%vec_size)
+
+end function max_size_vec
+
+! Query current memory capacity of vector.
+PURE function capacity_vec(self) result(capacity)
+ class( VECTOR_NAME ), intent(in) :: self
+ integer :: capacity
+
+ if (allocated(self%data)) then
+ capacity = size(self%data)
+ else
+ capacity = 0
+ end if
+
+end function capacity_vec
+
+! Get one item based on an index.
+PURE function get_single_vec(self, index) result(item)
+ class( VECTOR_NAME ), intent(in) :: self
+ integer, intent(in) :: index
+ TYPE_NAME, allocatable :: item
+
+ if (index > self%vec_size .or. index < 1) then
+ THROW(OOBMsg("get", [1, self%vec_size], index))
+ ! Purely to satisfy uninitialized data checks.
+ allocate(item)
+ return
+ end if
+
+ allocate(item, source=self%data(index))
+
+end function get_single_vec
+
+! Get items within a certain range.
+PURE function get_range_vec(self, begin, end, stride) result(items)
+ class( VECTOR_NAME ), intent(in) :: self
+ integer, intent(in) :: begin
+ integer, intent(in) :: end
+ integer, intent(in), optional :: stride
+
+ ! Have to use an allocatable, because we have to check if stride is
+ ! present before we know what the size should be.
+ TYPE_NAME, allocatable :: items(:)
+
+ ! An oddity: since in Fortran function results must be "defined", we have
+ ! to allocate "items" to portably avoid a segfault and allow the user to
+ ! recover from an error. This is true regardless of what the function
+ ! result is assigned to.
+ if (end > self%vec_size) then
+ allocate(items(0))
+ THROW(OOBMsg("get", [1, self%vec_size], end))
+ return
+ end if
+ if (begin < 1) then
+ allocate(items(0))
+ THROW(OOBMsg("get", [1, self%vec_size], begin))
+ return
+ end if
+
+ if (present(stride)) then
+ allocate(items(end+1-begin/stride))
+ items = self%data(begin:end:stride)
+ else
+ allocate(items(end+1-begin))
+ items = self%data(begin:end)
+ end if
+
+end function get_range_vec
+
+! Get an array containing a copy of the vector's elements.
+! If array is not allocated, returns a size zero array.
+PURE function get_array_vec(self) result(array)
+ class( VECTOR_NAME ), intent(in) :: self
+ TYPE_NAME :: array(self%vec_size)
+
+ if (allocated(self%data)) then
+ array = self%data(:self%vec_size)
+ end if
+
+end function get_array_vec
+
+! Get first item in the array
+PURE function front_vec(self) result(item)
+ class( VECTOR_NAME ), intent(in) :: self
+ TYPE_NAME :: item
+
+ item = self%get(1)
+
+end function front_vec
+
+! Get last item in the array
+PURE function back_vec(self) result(item)
+ class( VECTOR_NAME ), intent(in) :: self
+ TYPE_NAME :: item
+
+ item = self%get(self%vec_size)
+
+end function back_vec
+
+! Declare the vector to have zero size.
+! Does not change vector capacity.
+PURE subroutine clear_vec(self)
+ class( VECTOR_NAME ), intent(inout) :: self
+
+ call self%resize(0)
+
+end subroutine clear_vec
+
+! Declare the vector to have different size.
+! Does not reduce vector capacity, but will enforce size <= capacity by
+! growing array if necessary.
+! Resizing to negative value is equivalent to resizing to 0.
+PURE subroutine resize_vec(self, new_size, fill_value)
+ class( VECTOR_NAME ), intent(inout) :: self
+ integer, intent(in) :: new_size
+ TYPE_NAME, intent(in), optional :: fill_value
+
+ integer :: request_capacity
+
+ ! If not big enough, request capacity twice as big
+ ! as we have now (or 4 or 8 or... times, if necessary).
+ if (new_size > self%capacity()) then
+ request_capacity = max(self%capacity(),1)
+
+ do while (request_capacity < new_size)
+ request_capacity = request_capacity * 2
+ end do
+
+ call self%reserve(request_capacity)
+ end if
+
+ if (present(fill_value)) then
+ self%data((self%vec_size+1):new_size) = fill_value
+ end if
+
+ self%vec_size = max(new_size,0)
+
+end subroutine resize_vec
+
+! Set one item based on an index.
+PURE subroutine set_single_vec(self, item, index)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, intent(in) :: item
+ integer, intent(in) :: index
+
+ if (index > self%vec_size .or. index < 1) then
+ THROW(OOBMsg("set", [1, self%vec_size], index))
+ return
+ end if
+
+ self%data(index) = item
+
+end subroutine set_single_vec
+
+! Set range in array.
+PURE subroutine set_range_vec(self, array, begin, end, stride)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, intent(in) :: array(:)
+ integer, intent(in) :: begin
+ integer, intent(in) :: end
+ integer, intent(in), optional :: stride
+
+ if (end > self%vec_size) then
+ THROW(OOBMsg("set", [1, self%vec_size], end))
+ return
+ end if
+ if (begin < 1) then
+ THROW(OOBMsg("set", [1, self%vec_size], begin))
+ return
+ end if
+
+ if (present(stride)) then
+ self%data(begin:end:stride) = array
+ else
+ self%data(begin:end) = array
+ end if
+
+end subroutine set_range_vec
+
+! Set range in array with a fill value.
+PURE subroutine set_range_fill_vec(self, fill_value, begin, end, stride)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, intent(in) :: fill_value
+ integer, intent(in) :: begin
+ integer, intent(in) :: end
+ integer, intent(in), optional :: stride
+
+ if (end > self%vec_size) then
+ THROW(OOBMsg("set", [1, self%vec_size], end))
+ return
+ end if
+ if (begin < 1) then
+ THROW(OOBMsg("set", [1, self%vec_size], begin))
+ return
+ end if
+
+ if (present(stride)) then
+ self%data(begin:end:stride) = fill_value
+ else
+ self%data(begin:end) = fill_value
+ end if
+
+end subroutine set_range_fill_vec
+
+! Set array from an array.
+PURE subroutine set_array_vec(self, array)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, intent(in) :: array(:)
+
+ if (size(array) /= self%vec_size) then
+ THROW("Input array is not the same size as the vector it sets.")
+ end if
+
+ if (self%vec_size > 0) then
+ self%data(:self%vec_size) = array(:self%vec_size)
+ end if
+
+end subroutine set_array_vec
+
+! Set array from a fill value.
+! Bounds-checking unnecessary; empty arrays are left empty.
+PURE subroutine set_fill_vec(self, fill_value)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, intent(in) :: fill_value
+
+ if (allocated(self%data)) then
+ self%data(:self%vec_size) = fill_value
+ end if
+
+end subroutine set_fill_vec
+
+! Add new object as last element.
+PURE subroutine push_back_vec(self, item)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, intent(in) :: item
+
+ call self%resize(self%vec_size+1)
+
+ call self%set(item, self%vec_size)
+
+end subroutine push_back_vec
+
+! Remove last element.
+PURE subroutine pop_back_vec(self)
+ class( VECTOR_NAME ), intent(inout) :: self
+
+ if (self%empty()) then
+ THROW("Attempted to pop an element from an empty vector.")
+ end if
+
+ call self%resize(self%vec_size-1)
+
+end subroutine pop_back_vec
+
+! Insert element
+! Valid values are 1 to self%vec_size+1.
+! Inserting at self%vec_size+1 is equivalent to push_back.
+PURE subroutine insert_single_vec(self, index, item)
+ class( VECTOR_NAME ), intent(inout) :: self
+ integer, intent(in) :: index
+ TYPE_NAME, intent(in) :: item
+
+ if (index > self%vec_size+1 .or. index < 1) then
+ THROW(OOBMsg("insert", [1, self%vec_size], index))
+ return
+ end if
+
+ call self%resize(self%vec_size+1)
+
+ ! Move everything forward
+ self%data(index+1:self%vec_size) = &
+ self%data(index:self%vec_size-1)
+
+ call self%set(item, index)
+
+end subroutine insert_single_vec
+
+! Insert array
+PURE subroutine insert_array_vec(self, index, items)
+ class( VECTOR_NAME ), intent(inout) :: self
+ integer, intent(in) :: index
+ TYPE_NAME, intent(in) :: items(:)
+
+ if (index > self%vec_size+1 .or. index < 1) then
+ THROW(OOBMsg("insert", [1, self%vec_size], index))
+ return
+ end if
+
+ call self%resize(self%vec_size+size(items))
+
+ ! Move everything forward
+ self%data(index+size(items):self%vec_size) = &
+ self%data(index:self%vec_size-size(items))
+
+ call self%set(items, index, index+size(items)-1)
+
+end subroutine insert_array_vec
+
+! Insert repeated value
+PURE subroutine insert_repeat_vec(self, index, item, repeats)
+ class( VECTOR_NAME ), intent(inout) :: self
+ integer, intent(in) :: index
+ TYPE_NAME, intent(in) :: item
+ integer, intent(in) :: repeats
+
+ if (index > self%vec_size+1 .or. index < 1) then
+ THROW(OOBMsg("insert", [1, self%vec_size], index))
+ return
+ end if
+
+ call self%resize(self%vec_size+repeats)
+
+ ! Move everything forward
+ self%data(index+repeats:self%vec_size) = &
+ self%data(index:self%vec_size-repeats)
+
+ call self%set(item, index, index+repeats-1)
+
+end subroutine insert_repeat_vec
+
+! Erase element
+PURE subroutine erase_single_vec(self, index)
+ class( VECTOR_NAME ), intent(inout) :: self
+ integer, intent(in) :: index
+
+ if (index > self%vec_size .or. index < 1) then
+ THROW(OOBMsg("erase", [1, self%vec_size], index))
+ return
+ end if
+
+ ! Move everything back
+ self%data(index:(self%vec_size-1)) = self%data((index+1):self%vec_size)
+
+ call self%pop_back()
+
+end subroutine erase_single_vec
+
+! Erase "repeats" elements at index.
+PURE subroutine erase_range_vec(self, begin, end)
+ class( VECTOR_NAME ), intent(inout) :: self
+ integer, intent(in) :: begin
+ integer, intent(in) :: end
+
+ if (end > self%vec_size) then
+ THROW(OOBMsg("erase", [1, self%vec_size], end))
+ return
+ end if
+ if (begin < 1) then
+ THROW(OOBMsg("erase", [1, self%vec_size], begin))
+ return
+ end if
+
+ ! Move everything back
+ self%data(begin:self%vec_size-end+begin-1) = &
+ self%data(end+1:self%vec_size)
+
+ call self%resize(self%vec_size - end + begin-1)
+
+end subroutine erase_range_vec
+
+! Shrink vector to minimum size necessary to hold all elements.
+PURE subroutine shrink_to_fit_vec(self)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, allocatable :: tmp_array(:)
+
+ ! Don't do anything unless we have to.
+ if (self%vec_size < self%capacity()) then
+ ! If size is zero, just deallocate array.
+ if (self%vec_size == 0) then
+ if (allocated(self%data)) deallocate(self%data)
+ else
+ ! Allocate temporary at minimum size
+ allocate(tmp_array(self%vec_size))
+ tmp_array = self%data(:self%vec_size)
+
+ deallocate(self%data)
+ call move_alloc(tmp_array, self%data)
+ end if
+ end if
+
+end subroutine shrink_to_fit_vec
+
+! Reserve a certain size, if vector is not already that big.
+PURE subroutine reserve_vec(self, capacity)
+ class( VECTOR_NAME ), intent(inout) :: self
+ integer, intent(in) :: capacity
+
+ TYPE_NAME, allocatable :: tmp_array(:)
+
+ ! Only do anything if we need to get bigger.
+ if (capacity > self%capacity()) then
+
+ if (self%empty()) then
+ ! No data to copy
+ if (allocated(self%data)) deallocate(self%data)
+ allocate(self%data(capacity))
+ else
+ ! Allocate new size
+ allocate(tmp_array(capacity))
+ ! Copy data
+ tmp_array(:self%vec_size) = self%data(:self%vec_size)
+
+ ! Replace array with new copy.
+ deallocate(self%data)
+ call move_alloc(tmp_array, self%data)
+ end if
+ end if
+
+end subroutine reserve_vec
+
+! Move allocatable array into self
+! Note: Declaring self as intent(out) automatically empties the vector the
+! moment we enter this procedure!
+PURE subroutine move_in_vec(self, array)
+ class( VECTOR_NAME ), intent(out) :: self
+ TYPE_NAME, allocatable, intent(inout) :: array(:)
+
+ if (allocated(array)) then
+ call move_alloc(array, self%data)
+ self%vec_size = size(self%data)
+ end if
+
+end subroutine move_in_vec
+
+! Move self into output allocatable array.
+! For empty vector, do not allocate output.
+PURE subroutine move_out_vec(self, array)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, allocatable, intent(out) :: array(:)
+
+ call self%shrink_to_fit()
+
+ if (.not. self%empty()) then
+ call move_alloc(self%data, array)
+ end if
+
+ call self%clear()
+
+end subroutine move_out_vec
+
+! Efficient swapping (no de/reallocation)
+PURE subroutine swap_vec(self, other)
+ class( VECTOR_NAME ), intent(inout) :: self
+ class( VECTOR_NAME ), intent(inout) :: other
+
+ integer :: tmp_size
+ TYPE_NAME, allocatable :: tmp_array(:)
+
+ ! The following order is designed to work even if self and other are the
+ ! same vector.
+ if (allocated(other%data)) then
+ call move_alloc(other%data, tmp_array)
+ end if
+
+ if (allocated(self%data)) then
+#ifndef CPRPGI
+ call move_alloc(self%data, other%data)
+#else
+ ! The above should work, but a PGI bug forces us to copy and
+ ! deallocate.
+ allocate(other%data, source=self%data)
+ deallocate(self%data)
+#endif
+ end if
+
+ if (allocated(tmp_array)) then
+#ifndef CPRPGI
+ call move_alloc(tmp_array, self%data)
+#else
+ ! The above should work, but a PGI bug forces us to copy and
+ ! deallocate.
+ allocate(self%data, source=tmp_array)
+ deallocate(tmp_array)
+#endif
+ end if
+
+ tmp_size = other%vec_size
+ other%vec_size = self%vec_size
+ self%vec_size = tmp_size
+
+end subroutine swap_vec
+
+! Assign self from an array
+PURE subroutine array_assign_vec(self, array)
+ class( VECTOR_NAME ), intent(inout) :: self
+ TYPE_NAME, intent(in) :: array(:)
+
+ call self%resize(size(array))
+
+ call self%set(array)
+
+end subroutine array_assign_vec
+
+! Assign self from another vector.
+! Copy-and-swap is used to ensure that at most one copy of the array is
+! performed.
+! This would allow assignment to self in other languages, but Fortran 2003
+! is vague about whether this should work, since "other" must be
+! "intent(in)" for an assignment, and this routine would modify it if it is
+! the same as "self".
+! Use of the "target" attribute is intended to mitigate the risk of a
+! problem, warning the compiler that the two objects may overlap with other
+! variables.
+PURE subroutine vector_assign_vec(self, other)
+ class( VECTOR_NAME ), intent(inout), target :: self
+ class( VECTOR_NAME ), intent(in), target :: other
+
+ class( VECTOR_NAME ), allocatable :: temp
+
+ allocate(temp, source=other)
+
+ call self%swap(temp)
+
+ deallocate(temp)
+
+end subroutine vector_assign_vec
+
+#undef PURE
diff --git a/models/atm/cam/src/physics/cam/dynamic_vector_typedef.inc b/models/atm/cam/src/physics/cam/dynamic_vector_typedef.inc
new file mode 100644
index 000000000000..d9cd1b3a2b5c
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/dynamic_vector_typedef.inc
@@ -0,0 +1,266 @@
+!
+! Clone of C++ standard library vectors
+!
+! This type is a wrapper for an allocatable array, which provides
+! efficient utilities for dynamic array operations, such as appending new
+! elements, truncation, and reserving/retaining memory independently from
+! changes to the array's apparent size.
+!
+! Dynamic arrays allocate a somewhat larger buffer of contiguous memory
+! (the "capacity") than is actually being used at any given time (the
+! "size"). This allow elements to be efficiently added to one end, with the
+! object automatically reallocating a new buffer as necessary whenever the
+! current capacity is exhausted. The capacity increases geometrically,
+! wasting O(N) space, but requiring only O(1) time (amortized) to add each
+! element.
+!
+! One downside is that this wrapper class does not support many of
+! Fortran's intrinsic array operations. For instance, if you have a
+! vector of reals, and you want to take the sine, you have to either
+! iterate in a loop (slow), or set the upper bound yourself (without the
+! safety of bounds checking). The latter looks like this:
+!
+! x = sin(vec%data(:vec%size()))
+!
+! Because of this, it's probably preferable to use a standard array instead
+! of a vector of reals for numerical work.
+!
+! Because this type uses an allocatable instead of a pointer, it should not
+! cause a memory leak. However, deallocation can be forced by using "clear"
+! followed by "shrink_to_fit", or by explicit deallocation of the data
+! component.
+!
+! How to create a vector type:
+! ----------------------------
+!
+! Define VECTOR_NAME and TYPE_NAME in a module, then include this file
+! to create the type. Include this file before "contains" in the module,
+! and the "procdef" file afterward.
+!
+! There must be a function in scope called OOBMsg (or a function macro of
+! this name). This must accept a string representing the operation, a size
+! 2 integer array representing the bounds of the array, and an integer
+! representing an index into the array. It should return a string
+! representing an error message for out-of-bounds access.
+!
+! Finally, define the function macro THROW to an error handling mechanism.
+! THROW accepts one argument, a string representing an error message.
+!
+! Some tips:
+! ----------
+!
+! - Do not directly use the "data" component, unless it's unavoidable to
+! get decent efficiency.
+!
+! - The data is assumed to always have lower bound 1.
+!
+! - If you are finished with adding/removing elements, you can convert
+! this type into a standard allocatable array with the "move_out"
+! method. (You can do the reverse conversion cheaply with "move_in".)
+!
+! - Don't include these files twice in the same module, as this will cause
+! name clashes.
+!
+! - Don't use this type if you need pointers into the array to remain
+! valid as you add and remove elements. As with the C++ type, the array
+! is often reallocated if you are adding elements, and this invalidates
+! pointers into it.
+!
+! Advanced features:
+! ------------------
+!
+! - Define the macro "USE_PURE" if you need to mark all methods as pure.
+! This effectively requires errors to be silent (because THROW cannot do
+! anything useful if it has no side effects).
+!
+! Developer's notes:
+! ------------------
+!
+! 1) The main difference from the C++ types is that we use Fortran array
+! indexing conventions:
+! - Indexing starts at 1, not 0.
+! - The last element of a range is included in the range. E.g. using
+! "vec%erase(2,3)" erases two elements, not just one.
+! - When an array size would be negative, it is treated as size 0.
+! - When an operation's ending index is smaller than the beginning
+! index, it is a no-op (unless a negative stride is provided).
+!
+! 2) We could have iterator types like in C++, but they don't really give
+! you anything more than integer indices. Other types, like linked
+! lists, will likely require companion iterator types.
+!
+! 3) For access with bounds-checking, C++ uses the "at" method to provide
+! references to individual elements. To avoid working with pointers, and
+! to provide an interface somewhat closer to Fortran array conventions,
+! this type uses set/get methods instead.
+!
+! These methods are likely to produce extra copies, which may negatively
+! impact performance compared to direct access of the underlying data.
+! This is one reason why the data component is public, not private.
+!
+! 4) All vectors with vec_size = 0 are valid empty vectors, regardless of
+! whether or not "data" is allocated, and regardless of its size. This
+! slightly complicates some of the methods. However, it means that the
+! user does not have to initialize vectors, or treat empty vectors
+! differently depending on how they became empty.
+!
+! 5) Dynamic arrays have a time/space tradeoff parameter, which is the
+! factor by which the array's capacity grows whenever it is
+! automatically reallocated to hold more elements. In this code, the
+! factor is 2, which is a common, simple, and reasonably fast choice.
+!
+! If there is too much wasted memory over a wide range of use cases,
+! however, it may be reasonable to consider using 1.5 or even lower
+! (with appropriate attention given to rounding issues).
+
+type VECTOR_NAME
+
+ TYPE_NAME, allocatable :: data(:)
+
+ integer, private :: vec_size = 0
+ contains
+
+ !------------------------
+ ! Query functions
+ !------------------------
+
+ ! Test whether there are any elements present
+ procedure, pass(self) :: empty => empty_vec
+ ! Return current size
+ procedure, pass(self) :: vsize => size_vec
+ ! Estimate maximum possible size
+ procedure, pass(self) :: max_size => max_size_vec
+ ! Return maximum number of elements that can be held before the data
+ ! array will be reallocated to a larger size.
+ procedure, pass(self) :: capacity => capacity_vec
+
+ !------------------------
+ ! Retrieving data
+ !------------------------
+
+ ! Get the value of the element at a particular index
+ procedure, pass(self), private :: get_single_vec
+ ! Get an array of values of all the elements within a range
+ procedure, pass(self), private :: get_range_vec
+ ! Get a copy of all the data
+ procedure, pass(self), private :: get_array_vec
+ ! Generic for all of the above.
+ generic :: get => get_single_vec, get_range_vec, get_array_vec
+
+ ! Get the value of the first element
+ procedure, pass(self) :: front => front_vec
+ ! Get the value of the last element
+ procedure, pass(self) :: back => back_vec
+
+ !------------------------
+ ! Modifying data
+ !------------------------
+
+ ! Reset the vector to size 0 (without changing capacity)
+ procedure, pass(self) :: clear => clear_vec
+
+ ! Resize the vector (will not reduce capacity)
+ ! Resizing to a larger size than the capacity causes reallocation of the
+ ! data array.
+ procedure, pass(self) :: resize => resize_vec
+
+ ! None of the "set" routines below will grow the array. Setting elements
+ ! past the end of the vector will result in an out-of-bounds error; use
+ ! "insert", "push_back", or explicit resizing to add elements.
+
+ ! Set the element at a particular index
+ procedure, pass(self), private :: set_single_vec
+ ! Set the elements in a range from an array
+ procedure, pass(self), private :: set_range_vec
+ ! Fill all the elements in a range with a scalar value
+ procedure, pass(self), private :: set_range_fill_vec
+ ! Set the data to a copy of some array
+ procedure, pass(self), private :: set_array_vec
+ ! Fill the data will a scalar value
+ procedure, pass(self), private :: set_fill_vec
+ ! Generic for all of the above.
+ generic :: set => set_single_vec, set_range_vec, set_range_fill_vec, &
+ set_array_vec, set_fill_vec
+
+ ! Add an element to the back of the vector
+ procedure, pass(self) :: push_back => push_back_vec
+ ! Remove the element at the back of the vector
+ procedure, pass(self) :: pop_back => pop_back_vec
+
+ ! All of the insert routines add elements; the vector will be expanded
+ ! and data shuffled to ensure that this is non-destructive. For a vector
+ ! of size n, new elements can be inserted anywhere from 1 to n+1.
+ ! Inserting at point n+1 is equivalent to adding the new elements one-
+ ! by-one with push_back.
+
+ ! Insert one element at a particular point
+ procedure, pass(self), private :: insert_single_vec
+ ! Insert all elements from an array at a particular point
+ procedure, pass(self), private :: insert_array_vec
+ ! Insert multiple copies of the same value at a particular point.
+ procedure, pass(self), private :: insert_repeat_vec
+ ! Generic for all of the above.
+ generic :: insert => insert_single_vec, insert_array_vec, insert_repeat_vec
+
+ ! Erase the element at a particular point
+ procedure, pass(self), private :: erase_single_vec
+ ! Erase all the elements between two points (inclusive)
+ procedure, pass(self), private :: erase_range_vec
+ ! Generic for all of the above.
+ generic :: erase => erase_single_vec, erase_range_vec
+
+ !------------------------
+ ! Adjusting capacity
+ !------------------------
+
+ ! Shrink the vector's capacity to fit its size, releasing unneeded
+ ! memory
+ procedure, pass(self) :: shrink_to_fit => shrink_to_fit_vec
+
+ ! Expand the vector to have at least as much capacity as requested
+ ! Mostly useful to avoid unnecessary reallocation when you know that the
+ ! data is unlikely to exceed some upper bound on its size.
+ procedure, pass(self) :: reserve => reserve_vec
+
+ !------------------------
+ ! Move operations
+ !------------------------
+
+ ! Convert an allocatable array into a dynamic vector
+ ! No copies or reallocations are performed, but afterward the array is
+ ! no longer allocated.
+ procedure, pass(self) :: move_in => move_in_vec
+
+ ! Convert a dynamic vector to an allocatable array
+ ! An empty vector is converted to an unallocated array. A reallocation
+ ! and copy is often performed otherwise. Afterward the vector is empty.
+ procedure, pass(self) :: move_out => move_out_vec
+
+ ! Swap the contents of this vector with another one
+ ! No copies or reallocations are performed.
+ procedure, pass(self) :: swap => swap_vec
+
+ !------------------------
+ ! Copy/assignment
+ !------------------------
+
+ ! Overwrite contents of this vector with those of an array
+ procedure, pass(self), private :: array_assign_vec
+ ! Overwrite contents of this vector with those of another vector
+ procedure, pass(self), private :: vector_assign_vec
+ generic :: assignment(=) => array_assign_vec, vector_assign_vec
+
+end type VECTOR_NAME
+
+!------------------------
+! Constructors
+!------------------------
+
+interface VECTOR_NAME
+ ! Construct empty vector
+ module procedure new_vector_default
+ ! Construct vector as a copy of another vector
+ module procedure new_vector_copy
+ ! Construct vector with contents from an array
+ module procedure new_vector_array
+end interface
diff --git a/models/atm/cam/src/physics/cam/hetfrz_classnuc.F90 b/models/atm/cam/src/physics/cam/hetfrz_classnuc.F90
new file mode 100644
index 000000000000..dc27dcbc75e1
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/hetfrz_classnuc.F90
@@ -0,0 +1,689 @@
+module hetfrz_classnuc
+
+!-----------------------------------------------------------------------
+!
+! Purpose: Calculate heterogeneous freezing rates from classical nucleation theory
+!
+! Public interfaces:
+!
+! hetfrz_classnuc_init
+! hetfrz_classnuc_calc
+!
+! Author:
+! Corinna Hoose, UiO, May 2009
+! Yong Wang and Xiaohong Liu, UWyo, 12/2012,
+! implement in CAM5 and constrain uncertain parameters using natural dust and
+! 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.
+!
+!-----------------------------------------------------------------------
+
+use shr_kind_mod, only: r8 => shr_kind_r8
+use wv_saturation, only: svp_water, svp_ice
+use shr_spfn_mod, only: erf => shr_spfn_erf
+
+implicit none
+private
+save
+
+public :: hetfrz_classnuc_init, hetfrz_classnuc_calc
+
+real(r8) :: rair
+real(r8) :: cpair
+real(r8) :: rh2o
+real(r8) :: rhoh2o
+real(r8) :: mwh2o
+real(r8) :: tmelt
+real(r8) :: pi
+
+integer :: iulog
+
+!===================================================================================================
+contains
+!===================================================================================================
+
+subroutine hetfrz_classnuc_init( &
+ rair_in, cpair_in, rh2o_in, rhoh2o_in, mwh2o_in, &
+ tmelt_in, pi_in, iulog_in)
+
+ real(r8), intent(in) :: rair_in
+ real(r8), intent(in) :: cpair_in
+ real(r8), intent(in) :: rh2o_in
+ real(r8), intent(in) :: rhoh2o_in
+ real(r8), intent(in) :: mwh2o_in
+ real(r8), intent(in) :: tmelt_in
+ real(r8), intent(in) :: pi_in
+ integer, intent(in) :: iulog_in
+
+ rair = rair_in
+ cpair = cpair_in
+ rh2o = rh2o_in
+ rhoh2o = rhoh2o_in
+ mwh2o = mwh2o_in
+ tmelt = tmelt_in
+ pi = pi_in
+ iulog = iulog_in
+
+end subroutine hetfrz_classnuc_init
+
+!===================================================================================================
+
+subroutine hetfrz_classnuc_calc( &
+ deltat, t, p, supersatice, &
+ fn, &
+ r3lx, icnlx, &
+ frzbcimm, frzduimm, &
+ frzbccnt, frzducnt, &
+ frzbcdep, frzdudep, &
+ hetraer, awcam, awfacm, dstcoat, &
+ total_aer_num, coated_aer_num, uncoated_aer_num, &
+ total_interstitial_aer_num, total_cloudborne_aer_num, errstring)
+
+ real(r8), intent(in) :: deltat ! timestep [s]
+ real(r8), intent(in) :: t ! temperature [K]
+ real(r8), intent(in) :: p ! pressure [Pa]
+ real(r8), intent(in) :: supersatice ! supersaturation ratio wrt ice at 100%rh over water [ ]
+ real(r8), intent(in) :: r3lx ! volume mean drop radius [m]
+ real(r8), intent(in) :: icnlx ! in-cloud droplet concentration [cm-3]
+
+ real(r8), intent(in) :: fn(3) ! fraction activated [ ] for cloud borne aerosol number
+ ! index values are 1:bc, 2:dust_a1, 3:dust_a3
+ real(r8), intent(in) :: hetraer(3) ! bc and dust mass mean radius [m]
+ real(r8), intent(in) :: awcam(3) ! modal added mass [mug m-3]
+ real(r8), intent(in) :: awfacm(3) ! (OC+BC)/(OC+BC+SO4)
+ real(r8), intent(in) :: dstcoat(3) ! coated fraction
+ real(r8), intent(in) :: total_aer_num(3) ! total bc and dust number concentration(interstitial+cloudborne) [#/cm^3]
+ real(r8), intent(in) :: coated_aer_num(3) ! coated bc and dust number concentration(interstitial)
+ real(r8), intent(in) :: uncoated_aer_num(3) ! uncoated bc and dust number concentration(interstitial)
+ real(r8), intent(in) :: total_interstitial_aer_num(3) ! total bc and dust concentration(interstitial)
+ real(r8), intent(in) :: total_cloudborne_aer_num(3) ! total bc and dust concentration(cloudborne)
+
+ real(r8), intent(out) :: frzbcimm ! het. frz by BC immersion nucleation [cm-3 s-1]
+ real(r8), intent(out) :: frzduimm ! het. frz by dust immersion nucleation [cm-3 s-1]
+ real(r8), intent(out) :: frzbccnt ! het. frz by BC contact nucleation [cm-3 s-1]
+ real(r8), intent(out) :: frzducnt ! het. frz by dust contact nucleation [cm-3 s-1]
+ real(r8), intent(out) :: frzbcdep ! het. frz by BC deposition nucleation [cm-3 s-1]
+ real(r8), intent(out) :: frzdudep ! het. frz by dust deposition nucleation [cm-3 s-1]
+
+ character(len=*), intent(out) :: errstring
+
+ ! local variables
+
+ real(r8) :: aw(3) ! water activity [ ]
+ real(r8) :: molal(3) ! molality [moles/kg]
+ real(r8), parameter :: Mso4 = 96.06_r8
+
+ integer, parameter :: id_bc = 1
+ integer, parameter :: id_dst1 = 2
+ integer, parameter :: id_dst3 = 3
+ 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 :: 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 :: 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), parameter :: pi = 4._r8*atan(1.0_r8)
+ 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) :: 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) :: Jcnt_bc
+ real(r8) :: Jcnt_dust_a1,Jcnt_dust_a3
+ integer :: i
+
+ !********************************************************
+ ! Hoose et al., 2010 fitting parameters
+ !********************************************************
+ !freezing parameters for immersion freezing
+ !real(r8),parameter :: theta_imm_bc = 40.17 ! contact angle [deg], converted to rad later
+ !real(r8),parameter :: dga_imm_bc = 14.4E-20 ! activation energy [J]
+ !real(r8),parameter :: theta_imm_dust = 30.98 ! contact angle [deg], converted to rad later
+ !real(r8),parameter :: dga_imm_dust = 15.7E-20 ! activation energy [J]
+ !freezing parameters for deposition nucleation
+ !real(r8),parameter :: theta_dep_dust = 12.7 ! contact angle [deg], converted to rad later !Zimmermann et al (2008), illite
+ !real(r8),parameter :: dga_dep_dust = -6.21E-21 ! activation energy [J]
+ !real(r8),parameter :: theta_dep_bc = 28. ! contact angle [deg], converted to rad later !Moehler et al (2005), soot
+ !real(r8),parameter :: dga_dep_bc = -2.E-19 ! activation energy [J]
+ !********************************************************
+ ! Wang et al., 2014 fitting parameters
+ !********************************************************
+ ! freezing parameters for immersion freezing
+ real(r8),parameter :: theta_imm_bc = 48.0_r8 ! contact angle [deg], converted to rad later !DeMott et al (1990)
+ real(r8),parameter :: dga_imm_bc = 14.15E-20_r8 ! activation energy [J]
+ real(r8),parameter :: theta_imm_dust = 46.0_r8 ! contact angle [deg], converted to rad later !DeMott et al (2011) SD
+ real(r8),parameter :: dga_imm_dust = 14.75E-20_r8 ! activation energy [J]
+ ! freezing parameters for deposition nucleation
+ real(r8),parameter :: theta_dep_dust = 20.0_r8 ! contact angle [deg], converted to rad later !Koehler et al (2010) SD
+ real(r8),parameter :: dga_dep_dust = -8.1E-21_r8 ! activation energy [J]
+ real(r8),parameter :: theta_dep_bc = 28._r8 ! contact angle [deg], converted to rad later !Moehler et al (2005), soot
+ real(r8),parameter :: dga_dep_bc = -2.E-19_r8 ! activation energy [J]
+
+ real(r8) :: Kcoll_bc ! collision kernel [cm3 s-1]
+ real(r8) :: Kcoll_dust_a1 ! collision kernel [cm3 s-1]
+ real(r8) :: Kcoll_dust_a3 ! collision kernel [cm3 s-1]
+
+ logical :: tot_in = .false.
+
+ !*****************************************************************************
+ ! PDF theta model
+ !*****************************************************************************
+ ! some variables for PDF theta model
+ ! immersion freezing
+ real(r8),parameter :: theta_min = 1._r8/180._r8*pi
+ real(r8),parameter :: theta_max = 179._r8/180._r8*pi
+ real(r8) :: x1_imm
+ real(r8) :: x2_imm
+ real(r8) :: norm_theta_imm
+ real(r8),parameter :: imm_dust_mean_theta = 46.0_r8/180.0_r8*pi
+ real(r8),parameter :: imm_dust_var_theta = 0.01_r8
+ real(r8) :: pdf_d_theta
+ integer,parameter :: pdf_n_theta = 101
+ real(r8) :: dim_theta(pdf_n_theta)
+ real(r8) :: dim_f_imm_dust_a1(pdf_n_theta), dim_f_imm_dust_a3(pdf_n_theta)
+ real(r8) :: dim_Jimm_dust_a1(pdf_n_theta), dim_Jimm_dust_a3(pdf_n_theta)
+ real(r8) :: pdf_imm_theta(pdf_n_theta)
+ real(r8) :: sum_imm_dust_a1, sum_imm_dust_a3
+ logical :: pdf_imm_in = .true.
+ !------------------------------------------------------------------------------------------------
+
+ errstring = ' '
+
+ if (pdf_imm_in) then
+ pdf_d_theta = (179._r8-1._r8)/180._r8*pi/(pdf_n_theta-1)
+ ! calculate the integral in the denominator
+ x1_imm = (LOG(theta_min)-LOG(imm_dust_mean_theta))/(sqrt(2.0_r8)*imm_dust_var_theta)
+ x2_imm = (LOG(theta_max)-LOG(imm_dust_mean_theta))/(sqrt(2.0_r8)*imm_dust_var_theta)
+ norm_theta_imm = (ERF(x2_imm)-ERF(x1_imm))*0.5_r8
+ do i = 1, pdf_n_theta
+ dim_theta(i) = 1._r8/180._r8*pi+(i-1)*pdf_d_theta
+ pdf_imm_theta(i) = exp(-((LOG(dim_theta(i))-LOG(imm_dust_mean_theta))**2._r8)/(2._r8*imm_dust_var_theta**2._r8))/ &
+ (dim_theta(i)*imm_dust_var_theta*SQRT(2*pi))/norm_theta_imm
+ end do
+ end if
+
+ ! get saturation vapor pressures
+ eswtr = svp_water(t) ! 0 for liquid
+ esice = svp_ice(t) ! 1 for ice
+
+ tc = t - tmelt
+ rhoice = 916.7_r8-0.175_r8*tc-5.e-4_r8*tc**2
+ vwice = mwh2o*amu/rhoice
+ sigma_iw = (28.5_r8+0.25_r8*tc)*1E-3_r8
+ 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)
+
+ ! calculate collision kernels as a function of environmental parameters and aerosol/droplet sizes
+ call collkernel(t, p, eswtr, rhwincloud, r3lx, &
+ r_bc, & ! BC modes
+ 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
+ !*****************************************************************************
+ ! solute effect
+ aw(:) = 1._r8
+ molal(:) = 0._r8
+
+ ! The heterogeneous ice freezing temperatures of all IN generally decrease with
+ ! 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.
+ ! If the index of IN is 0, it means three freezing modes of this aerosol are depressed.
+
+ do i = 1, 3
+ !calculate molality
+ if ( total_interstitial_aer_num(i) > 0._r8 ) then
+ molal(i) = (1.e-6_r8*awcam(i)*(1._r8-awfacm(i))/(Mso4*total_interstitial_aer_num(i)*1.e6_r8))/ &
+ (4*pi/3*rhoh2o*(MAX(r3lx,4.e-6_r8))**3)
+ aw(i) = 1._r8/(1._r8+2.9244948e-2_r8*molal(i)+2.3141243e-3_r8*molal(i)**2+7.8184854e-7_r8*molal(i)**3)
+ end if
+ end do
+
+ !*****************************************************************************
+ ! immersion freezing begin
+ !*****************************************************************************
+
+ frzbcimm = 0._r8
+ frzduimm = 0._r8
+ frzbccnt = 0._r8
+ frzducnt = 0._r8
+ frzbcdep = 0._r8
+ frzdudep = 0._r8
+
+ ! critical germ size
+ rgimm = 2*vwice*sigma_iw/(kboltz*t*LOG(supersatice))
+ ! take solute effect into account
+ rgimm_bc = rgimm
+ rgimm_dust_a1 = rgimm
+ rgimm_dust_a3 = rgimm
+
+ ! if aw*Si<=1, the freezing point depression is strong enough to prevent freezing
+
+ if (aw(id_bc)*supersatice > 1._r8 ) then
+ do_bc = .true.
+ rgimm_bc = 2*vwice*sigma_iw/(kboltz*t*LOG(aw(id_bc)*supersatice))
+ else
+ do_bc = .false.
+ end if
+
+ if (aw(id_dst1)*supersatice > 1._r8 ) then
+ do_dst1 = .true.
+ rgimm_dust_a1 = 2*vwice*sigma_iw/(kboltz*t*LOG(aw(id_dst1)*supersatice))
+ else
+ do_dst1 = .false.
+ end if
+
+ if (aw(id_dst3)*supersatice > 1._r8 ) then
+ do_dst3 = .true.
+ rgimm_dust_a3 = 2*vwice*sigma_iw/(kboltz*t*LOG(aw(id_dst3)*supersatice))
+ else
+ do_dst3 = .false.
+ end if
+
+ ! form factor
+ ! only consider flat surfaces due to uncertainty of curved surfaces
+
+ m = COS(theta_imm_bc*pi/180._r8)
+ f_imm_bc = (2+m)*(1-m)**2/4._r8
+ if (.not. pdf_imm_in) then
+ m = COS(theta_imm_dust*pi/180._r8)
+ f_imm_dust_a1 = (2+m)*(1-m)**2/4._r8
+
+ m = COS(theta_imm_dust*pi/180._r8)
+ f_imm_dust_a3 = (2+m)*(1-m)**2/4._r8
+ else
+ do i = 1, pdf_n_theta
+ m = cos(dim_theta(i))
+ dim_f_imm_dust_a1(i) = (2+m)*(1-m)**2/4._r8
+
+ m = cos(dim_theta(i))
+ dim_f_imm_dust_a3(i) = (2+m)*(1-m)**2/4._r8
+ end do
+ end if
+
+ ! homogeneous energy of germ formation
+ dg0imm_bc = 4*pi/3._r8*sigma_iw*rgimm_bc**2
+ dg0imm_dust_a1 = 4*pi/3._r8*sigma_iw*rgimm_dust_a1**2
+ dg0imm_dust_a3 = 4*pi/3._r8*sigma_iw*rgimm_dust_a3**2
+
+ ! prefactor
+ Aimm_bc = n1*((vwice*rhplanck)/(rgimm_bc**3)*SQRT(3._r8/pi*kboltz*T*dg0imm_bc))
+ Aimm_dust_a1 = n1*((vwice*rhplanck)/(rgimm_dust_a1**3)*SQRT(3._r8/pi*kboltz*T*dg0imm_dust_a1))
+ Aimm_dust_a3 = n1*((vwice*rhplanck)/(rgimm_dust_a3**3)*SQRT(3._r8/pi*kboltz*T*dg0imm_dust_a3))
+
+ ! nucleation rate per particle
+
+ Jimm_bc = Aimm_bc*r_bc**2/SQRT(f_imm_bc)*EXP((-dga_imm_bc-f_imm_bc*dg0imm_bc)/(kboltz*T))
+ if (.not. pdf_imm_in) then
+ ! 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).
+ 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
+
+ if (pdf_imm_in) then
+ do i = 1, pdf_n_theta
+ ! 1/sqrt(f)
+ dim_Jimm_dust_a1(i) = Aimm_dust_a1*r_dust_a1**2/SQRT(dim_f_imm_dust_a1(i))*EXP((-dga_imm_dust-dim_f_imm_dust_a1(i)* &
+ dg0imm_dust_a1)/(kboltz*T))
+ dim_Jimm_dust_a1(i) = max(dim_Jimm_dust_a1(i), 0._r8)
+
+ dim_Jimm_dust_a3(i) = Aimm_dust_a3*r_dust_a3**2/SQRT(dim_f_imm_dust_a3(i))*EXP((-dga_imm_dust-dim_f_imm_dust_a3(i)* &
+ dg0imm_dust_a3)/(kboltz*T))
+ dim_Jimm_dust_a3(i) = max(dim_Jimm_dust_a3(i), 0._r8)
+ end do
+ end if
+
+ ! 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
+ do i = 1, pdf_n_theta-1
+ sum_imm_dust_a1 = sum_imm_dust_a1+0.5_r8*((pdf_imm_theta(i)*exp(-dim_Jimm_dust_a1(i)*deltat)+ &
+ pdf_imm_theta(i+1)*exp(-dim_Jimm_dust_a1(i+1)*deltat)))*pdf_d_theta
+ sum_imm_dust_a3 = sum_imm_dust_a3+0.5_r8*((pdf_imm_theta(i)*exp(-dim_Jimm_dust_a3(i)*deltat)+ &
+ pdf_imm_theta(i+1)*exp(-dim_Jimm_dust_a3(i+1)*deltat)))*pdf_d_theta
+ 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)))
+
+ if (.not. pdf_imm_in) then
+ if (do_dst1) frzduimm = frzduimm+MIN(1*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, &
+ 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, &
+ 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, &
+ 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 (.not. pdf_imm_in) then
+ if (do_dst1) frzduimm = frzduimm+MIN(1*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, &
+ 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, &
+ 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, &
+ fn(id_dst3)*total_aer_num(id_dst3)/deltat*(1._r8-sum_imm_dust_a3))
+ end if
+ end if
+
+ if (t > 263.15_r8) then
+ frzduimm = 0._r8
+ frzbcimm = 0._r8
+ end if
+
+ !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ ! Deposition nucleation
+ !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ ! critical germ size
+ ! assume 98% RH in mixed-phase clouds (Korolev & Isaac, JAS 2006)
+ rgdep=2*vwice*sigma_iv/(kboltz*t*LOG(rhwincloud*supersatice))
+
+ ! form factor
+ m = COS(theta_dep_bc*pi/180._r8)
+ f_dep_bc = (2+m)*(1-m)**2/4._r8
+
+ m = COS(theta_dep_dust*pi/180._r8)
+ f_dep_dust_a1 = (2+m)*(1-m)**2/4._r8
+
+ m = COS(theta_dep_dust*pi/180._r8)
+ f_dep_dust_a3 = (2+m)*(1-m)**2/4._r8
+
+ ! homogeneous energy of germ formation
+ dg0dep = 4*pi/3._r8*sigma_iv*rgdep**2
+
+ ! prefactor
+ ! attention: division of small numbers
+ Adep = (rhwincloud*eswtr)**2*(vwice/(mwh2o*amu))/(kboltz*T*nus)*SQRT(sigma_iv/(kboltz*T))
+
+ ! nucleation rate per particle
+ if (rgdep > 0) then
+ Jdep_bc = Adep*r_bc**2/SQRT(f_dep_bc)*EXP((-dga_dep_bc-f_dep_bc*dg0dep)/(kboltz*T))
+ Jdep_dust_a1 = Adep*r_dust_a1**2/SQRT(f_dep_dust_a1)*EXP((-dga_dep_dust-f_dep_dust_a1*dg0dep)/(kboltz*T))
+ Jdep_dust_a3 = Adep*r_dust_a3**2/SQRT(f_dep_dust_a3)*EXP((-dga_dep_dust-f_dep_dust_a3*dg0dep)/(kboltz*T))
+ else
+ Jdep_bc = 0._r8
+ Jdep_dust_a1 = 0._r8
+ Jdep_dust_a3 = 0._r8
+ end if
+
+ ! Limit to 1% of available potential IN (for BC), no limit for 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, &
+ 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, &
+ 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-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-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)))
+ end if
+
+ !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ ! contact nucleation
+ !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ ! form factor
+ m = COS(theta_dep_bc*pi/180._r8)
+ f_cnt_bc = (2+m)*(1-m)**2/4._r8
+
+ m = COS(theta_dep_dust*pi/180._r8)
+ f_cnt_dust_a1 = (2+m)*(1-m)**2/4._r8
+
+ m = COS(theta_dep_dust*pi/180._r8)
+ f_cnt_dust_a3 = (2+m)*(1-m)**2/4._r8
+
+ ! homogeneous energy of germ formation
+ dg0cnt = 4*pi/3._r8*sigma_iv*rgimm**2
+
+ ! prefactor
+ ! attention: division of small numbers
+ Acnt = rhwincloud*eswtr*4*pi/(nus*SQRT(2*pi*mwh2o*amu*kboltz*T))
+
+ ! nucleation rate per particle
+ Jcnt_bc = Acnt*r_bc**2*EXP((-dga_dep_bc-f_cnt_bc*dg0cnt)/(kboltz*T))*Kcoll_bc*icnlx
+ 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
+ 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, &
+ 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, &
+ 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-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, &
+ (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, &
+ Kcoll_dust_a1, Kcoll_dust_a3
+ errstring = 'ERROR in hetfrz_classnuc_calc::frzducnt'
+ return
+ end if
+
+end subroutine hetfrz_classnuc_calc
+
+!===================================================================================================
+
+!-----------------------------------------------------------------------
+!
+! Purpose: calculate collision kernels as a function of environmental parameters and aerosol/droplet sizes
+!
+! Author: Corinna Hoose, UiO, October 2009
+!
+! Modifications: Yong Wang and Xiaohong Liu, UWyo, 12/2012
+!-----------------------------------------------------------------------
+
+subroutine collkernel( &
+ t, pres, eswtr, rhwincloud, r3lx, &
+ r_bc, & ! BC modes
+ r_dust_a1, r_dust_a3, & ! dust modes
+ Kcoll_bc, & ! collision kernel [cm3 s-1]
+ Kcoll_dust_a1, Kcoll_dust_a3)
+
+ real(r8), intent(in) :: t ! temperature [K]
+ real(r8), intent(in) :: pres ! pressure [Pa]
+ real(r8), intent(in) :: eswtr ! saturation vapor pressure of water [Pa]
+ real(r8), intent(in) :: r3lx ! volume mean drop radius [m]
+ real(r8), intent(in) :: rhwincloud ! in-cloud relative humidity over water [ ]
+ real(r8), intent(in) :: r_bc ! model radii of BC modes [m]
+ real(r8), intent(in) :: r_dust_a1 ! model radii of dust modes [m]
+ real(r8), intent(in) :: r_dust_a3 ! model radii of dust modes [m]
+
+ real(r8), intent(out) :: Kcoll_bc ! collision kernel [cm3 s-1]
+ real(r8), intent(out) :: Kcoll_dust_a1
+ real(r8), intent(out) :: Kcoll_dust_a3
+
+ ! local variables
+ real(r8) :: a, b, c, a_f, b_f, c_f, f
+ real(r8) :: tc ! temperature [deg C]
+ real(r8) :: rho_air ! air density [kg m-3]
+ real(r8) :: viscos_air ! dynamic viscosity of air [kg m-1 s-1]
+ real(r8) :: Ktherm_air ! thermal conductivity of air [J/(m s K)]
+ real(r8) :: lambda ! mean free path [m]
+ real(r8) :: Kn ! Knudsen number [ ]
+ real(r8) :: Re ! Reynolds number [ ]
+ real(r8) :: Pr ! Prandtl number [ ]
+ real(r8) :: Sc ! Schmidt number [ ]
+ real(r8) :: vterm ! terminal velocity [m s-1]
+ real(r8) :: Ktherm ! thermal conductivity of aerosol [J/(m s K)]
+ real(r8) :: Dvap ! water vapor diffusivity [m2 s-1]
+ real(r8) :: Daer ! aerosol diffusivity [m2 s-1]
+ real(r8) :: latvap ! latent heat of vaporization [J kg-1]
+ real(r8) :: kboltz ! Boltzmann constant [J K-1]
+ real(r8) :: G ! thermodynamic function in Cotton et al. [kg m-1 s-1]
+ real(r8) :: r_a ! aerosol radius [m]
+ real(r8) :: f_t ! factor by Waldmann & Schmidt [ ]
+ real(r8) :: Q_heat ! heat flux [J m-2 s-1]
+ real(r8) :: Tdiff_cotton ! temperature difference between droplet and environment [K]
+ real(r8) :: K_brownian,K_thermo_cotton,K_diffusio_cotton ! collision kernels [m3 s-1]
+ 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
+
+ tc = t - tmelt
+ kboltz = 1.38065e-23_r8
+
+ ! air viscosity for tc<0, from depvel_part.F90
+ viscos_air = (1.718_r8+0.0049_r8*tc-1.2e-5_r8*tc*tc)*1.e-5_r8
+ ! air density
+ rho_air = pres/(rair*t)
+ ! mean free path: Seinfeld & Pandis 8.6
+ lambda = 2*viscos_air/(pres*SQRT(8/(pi*rair*t)))
+ ! latent heat of vaporization, varies with T
+ latvap = 1000*(-0.0000614342_r8*tc**3 + 0.00158927_r8*tc**2 - 2.36418_r8*tc + 2500.79_r8)
+ ! droplet terminal velocity after Chen & Liu, QJRMS 2004
+ a = 8.8462e2_r8
+ b = 9.7593e7_r8
+ c = -3.4249e-11_r8
+ a_f = 3.1250e-1_r8
+ b_f = 1.0552e-3_r8
+ c_f = -2.4023_r8
+ f = EXP(EXP(a_f + b_f*(LOG(r3lx))**3 + c_f*rho_air**1.5_r8))
+ vterm = (a+ (b + c*r3lx)*r3lx)*r3lx*f
+
+ ! Reynolds number
+ Re = 2*vterm*r3lx*rho_air/viscos_air
+ ! thermal conductivity of air: Seinfeld & Pandis eq. 15.75
+ Ktherm_air = 1.e-3_r8*(4.39_r8+0.071_r8*t) !J/(m s K)
+ ! 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)
+ ! 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
+ if (i == 1) r_a = r_bc
+ if (i == 2) r_a = r_dust_a1
+ if (i == 3) r_a = r_dust_a3
+ ! Knudsen number (Seinfeld & Pandis 8.1)
+ Kn = lambda/r_a
+ ! aerosol diffusivity
+ Daer = kboltz*t*(1 + Kn)/(6*pi*r_a*viscos_air)
+ ! Schmidt number
+ Sc = viscos_air/(Daer*rho_air)
+
+ ! Young (1974) first equ. on page 771
+ K_brownian = 4*pi*r3lx*Daer*(1 + 0.3_r8*Re**0.5_r8*Sc**0.33_r8)
+
+ ! thermal conductivities from Seinfeld & Pandis, Table 8.6
+ if (i == 1) Ktherm = 4.2_r8 ! Carbon
+ if (i == 2 .or. i == 3) Ktherm = 0.72_r8 ! clay
+ ! form factor
+ f_t = 0.4_r8*(1._r8 + 1.45_r8*Kn + 0.4_r8*Kn*EXP(-1._r8/Kn)) &
+ *(Ktherm_air + 2.5_r8*Kn*Ktherm) &
+ /((1._r8 + 3._r8*Kn)*(2._r8*Ktherm_air + 5._r8*Kn*Ktherm+Ktherm))
+ ! calculate T-Tc as in Cotton et al.
+ Tdiff_cotton = -G*(rhwincloud - 1._r8)*latvap/Ktherm_air
+ Q_heat = Ktherm_air/r3lx*(1._r8 + 0.3_r8*Re**0.5_r8*Pr**0.33_r8)*Tdiff_cotton
+ K_thermo_cotton = 4._r8*pi*r3lx*r3lx*f_t*Q_heat/pres
+ K_diffusio_cotton = -(1._r8/f_t)*(rh2o*t/latvap)*K_thermo_cotton
+ K_total = 1.e6_r8*(K_brownian + K_thermo_cotton + K_diffusio_cotton) ! convert m3/s -> cm3/s
+ ! set K to 0 if negative
+ if (K_total .lt. 0._r8) K_total = 0._r8
+
+ 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
+
+!===================================================================================================
+
+
+end module hetfrz_classnuc
diff --git a/models/atm/cam/src/physics/cam/hetfrz_classnuc_cam.F90 b/models/atm/cam/src/physics/cam/hetfrz_classnuc_cam.F90
new file mode 100644
index 000000000000..9b071c269eac
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/hetfrz_classnuc_cam.F90
@@ -0,0 +1,1293 @@
+module hetfrz_classnuc_cam
+
+!---------------------------------------------------------------------------------
+!
+! CAM Interfaces for hetfrz_classnuc module.
+!
+!---------------------------------------------------------------------------------
+
+use shr_kind_mod, only: r8=>shr_kind_r8
+use spmd_utils, only: masterproc
+use ppgrid, only: pcols, pver, begchunk, endchunk
+use physconst, only: rair, cpair, rh2o, rhoh2o, mwh2o, tmelt, pi
+use constituents, only: cnst_get_ind
+use physics_types, only: physics_state
+use physics_buffer, only: physics_buffer_desc, pbuf_get_index, pbuf_old_tim_idx, pbuf_get_field
+use phys_control, only: phys_getopts, use_hetfrz_classnuc
+use rad_constituents, only: rad_cnst_get_info, rad_cnst_get_mode_idx, rad_cnst_get_spec_idx, &
+ rad_cnst_get_aer_mmr, rad_cnst_get_aer_props, &
+ rad_cnst_get_mode_num, rad_cnst_get_mode_props
+
+use physics_buffer, only: pbuf_add_field, dtype_r8, pbuf_old_tim_idx, &
+ pbuf_get_index, pbuf_get_field
+use cam_history, only: addfld, phys_decomp, add_default, outfld
+
+use ref_pres, only: top_lev => trop_cloud_top_lev
+use wv_saturation, only: svp_water, svp_ice
+
+use cam_logfile, only: iulog
+use error_messages, only: handle_errmsg, alloc_err
+use cam_abortutils, only: endrun
+
+use hetfrz_classnuc, only: hetfrz_classnuc_init, hetfrz_classnuc_calc
+
+implicit none
+private
+save
+
+public :: &
+ hetfrz_classnuc_cam_readnl, &
+ hetfrz_classnuc_cam_register, &
+ hetfrz_classnuc_cam_init, &
+ hetfrz_classnuc_cam_calc, &
+ hetfrz_classnuc_cam_save_cbaero
+
+! Namelist variables
+logical :: hist_hetfrz_classnuc = .false.
+
+! Vars set via init method.
+real(r8) :: mincld ! minimum allowed cloud fraction
+
+! constituent indices
+integer :: &
+ cldliq_idx = -1, &
+ cldice_idx = -1, &
+ numliq_idx = -1, &
+ numice_idx = -1
+
+! pbuf indices for fields provided by heterogeneous freezing
+integer :: &
+ frzimm_idx, &
+ frzcnt_idx, &
+ frzdep_idx
+
+! pbuf indices for fields needed by heterogeneous freezing
+integer :: &
+ ast_idx = -1
+
+! modal aerosols
+integer, parameter :: MAM3_nmodes = 3
+integer, parameter :: MAM7_nmodes = 7
+integer :: nmodes = -1 ! number of aerosol modes
+
+! mode indices
+integer :: mode_accum_idx = -1 ! accumulation mode
+integer :: mode_coarse_idx = -1 ! coarse mode
+integer :: mode_finedust_idx = -1 ! fine dust mode
+integer :: mode_coardust_idx = -1 ! coarse dust mode
+integer :: mode_pcarbon_idx = -1 ! primary carbon mode
+
+! mode properties
+real(r8) :: alnsg_mode_accum
+real(r8) :: alnsg_mode_coarse
+real(r8) :: alnsg_mode_finedust
+real(r8) :: alnsg_mode_coardust
+real(r8) :: alnsg_mode_pcarbon
+
+! specie properties
+real(r8) :: specdens_dust
+real(r8) :: specdens_so4
+real(r8) :: specdens_bc
+real(r8) :: specdens_soa
+real(r8) :: specdens_pom
+
+! List all species
+integer :: ncnst = 0 ! Total number of constituents (mass and number) needed
+ ! by the parameterization (depends on aerosol model used)
+
+integer :: so4_accum ! sulfate in accumulation mode
+integer :: bc_accum ! black-c in accumulation mode
+integer :: pom_accum ! p-organic in accumulation mode
+integer :: soa_accum ! s-organic in accumulation mode
+integer :: dst_accum ! dust in accumulation mode
+integer :: ncl_accum ! seasalt in accumulation mode
+integer :: num_accum ! number in accumulation mode
+
+integer :: dst_coarse ! dust in coarse mode
+integer :: ncl_coarse ! seasalt in coarse mode
+integer :: so4_coarse ! sulfate in coarse mode
+integer :: num_coarse ! number in coarse mode
+
+integer :: dst_finedust ! dust in finedust mode
+integer :: so4_finedust ! sulfate in finedust mode
+integer :: num_finedust ! number in finedust mode
+
+integer :: dst_coardust ! dust in coardust mode
+integer :: so4_coardust ! sulfate in coardust mode
+integer :: num_coardust ! number in coardust mode
+
+integer :: bc_pcarbon ! black-c in primary carbon mode
+integer :: pom_pcarbon ! p-organic in primary carbon mode
+integer :: num_pcarbon ! number in primary carbon mode
+
+! Index arrays for looping over all constituents
+integer, allocatable :: mode_idx(:)
+integer, allocatable :: spec_idx(:)
+
+! Copy of cloud borne aerosols before modification by droplet nucleation
+! The basis is converted from mass to volume.
+real(r8), allocatable :: aer_cb(:,:,:,:)
+
+! Copy of interstitial aerosols with basis converted from mass to volume.
+real(r8), allocatable :: aer(:,:,:,:)
+
+!===============================================================================
+contains
+!===============================================================================
+
+subroutine hetfrz_classnuc_cam_readnl(nlfile)
+
+ use namelist_utils, only: find_group_name
+ use units, only: getunit, freeunit
+ use mpishorthand
+
+ character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
+
+ ! Local variables
+ integer :: unitn, ierr
+ character(len=*), parameter :: subname = 'hetfrz_classnuc_cam_readnl'
+
+ namelist /hetfrz_classnuc_nl/ hist_hetfrz_classnuc
+
+ !-----------------------------------------------------------------------------
+
+ if (masterproc) then
+ unitn = getunit()
+ open( unitn, file=trim(nlfile), status='old' )
+ call find_group_name(unitn, 'hetfrz_classnuc_nl', status=ierr)
+ if (ierr == 0) then
+ read(unitn, hetfrz_classnuc_nl, iostat=ierr)
+ if (ierr /= 0) then
+ call endrun(subname // ':: ERROR reading namelist')
+ end if
+ end if
+ close(unitn)
+ call freeunit(unitn)
+
+ end if
+
+#ifdef SPMD
+ ! Broadcast namelist variables
+ call mpibcast(hist_hetfrz_classnuc, 1, mpilog, 0, mpicom)
+#endif
+
+end subroutine hetfrz_classnuc_cam_readnl
+
+!================================================================================================
+
+subroutine hetfrz_classnuc_cam_register()
+
+ if (.not. use_hetfrz_classnuc) return
+
+ ! pbuf fields provided by hetfrz_classnuc
+ call pbuf_add_field('FRZIMM', 'physpkg', dtype_r8, (/pcols,pver/), frzimm_idx)
+ call pbuf_add_field('FRZCNT', 'physpkg', dtype_r8, (/pcols,pver/), frzcnt_idx)
+ call pbuf_add_field('FRZDEP', 'physpkg', dtype_r8, (/pcols,pver/), frzdep_idx)
+
+end subroutine hetfrz_classnuc_cam_register
+
+!================================================================================================
+
+subroutine hetfrz_classnuc_cam_init(mincld_in)
+
+ real(r8), intent(in) :: mincld_in
+
+ ! local variables
+ logical :: prog_modal_aero
+ integer :: m, n, nspec
+ integer :: istat
+
+ real(r8) :: sigma_logr_aer
+
+ character(len=32) :: str32
+ character(len=*), parameter :: routine = 'hetfrz_classnuc_cam_init'
+ !--------------------------------------------------------------------------------------------
+
+ if (.not. use_hetfrz_classnuc) return
+
+ ! This parameterization currently assumes that prognostic modal aerosols are on. Check...
+ call phys_getopts(prog_modal_aero_out=prog_modal_aero)
+ if (.not. prog_modal_aero) call endrun(routine//': cannot use hetfrz_classnuc without prognostic modal aerosols')
+
+ mincld = mincld_in
+
+ call cnst_get_ind('CLDLIQ', cldliq_idx)
+ call cnst_get_ind('CLDICE', cldice_idx)
+ call cnst_get_ind('NUMLIQ', numliq_idx)
+ call cnst_get_ind('NUMICE', numice_idx)
+
+ ! pbuf fields used by hetfrz_classnuc
+ ast_idx = pbuf_get_index('AST')
+
+ call addfld('bc_num', '#/cm3', pver, 'A', 'total bc number', phys_decomp)
+ call addfld('dst1_num', '#/cm3', pver, 'A', 'total dst1 number', phys_decomp)
+ call addfld('dst3_num', '#/cm3', pver, 'A', 'total dst3 number', phys_decomp)
+ call addfld('bcc_num', '#/cm3', pver, 'A', 'coated bc number', phys_decomp)
+ call addfld('dst1c_num', '#/cm3', pver, 'A', 'coated dst1 number', phys_decomp)
+ call addfld('dst3c_num', '#/cm3', pver, 'A', 'coated dst3 number', phys_decomp)
+ call addfld('bcuc_num', '#/cm3', pver, 'A', 'uncoated bc number', phys_decomp)
+ call addfld('dst1uc_num', '#/cm3', pver, 'A', 'uncoated dst1 number', phys_decomp)
+ call addfld('dst3uc_num', '#/cm3', pver, 'A', 'uncoated dst3 number', phys_decomp)
+
+ call addfld('bc_a1_num', '#/cm3', pver, 'A', 'interstitial bc number', phys_decomp)
+ call addfld('dst_a1_num', '#/cm3', pver, 'A', 'interstitial dst1 number', phys_decomp)
+ call addfld('dst_a3_num', '#/cm3', pver, 'A', 'interstitial dst3 number', phys_decomp)
+ call addfld('bc_c1_num', '#/cm3', pver, 'A', 'cloud borne bc number', phys_decomp)
+ call addfld('dst_c1_num', '#/cm3', pver, 'A', 'cloud borne dst1 number', phys_decomp)
+ call addfld('dst_c3_num', '#/cm3', pver, 'A', 'cloud borne dst3 number', phys_decomp)
+
+ call addfld('fn_bc_c1_num', '#/cm3', pver, 'A', 'cloud borne bc number derived from fn', phys_decomp)
+ call addfld('fn_dst_c1_num', '#/cm3', pver, 'A', 'cloud borne dst1 number derived from fn', phys_decomp)
+ call addfld('fn_dst_c3_num', '#/cm3', pver, 'A', 'cloud borne dst3 number derived from fn', phys_decomp)
+
+ call addfld('na500', '#/cm3', pver, 'A', 'interstitial aerosol number with D>500 nm', phys_decomp)
+ call addfld('totna500', '#/cm3', pver, 'A', 'total aerosol number with D>500 nm', phys_decomp)
+
+ call addfld('FREQIMM', 'fraction', pver, 'A', 'Fractional occurance of immersion freezing', phys_decomp)
+ call addfld('FREQCNT', 'fraction', pver, 'A', 'Fractional occurance of contact freezing', phys_decomp)
+ call addfld('FREQDEP', 'fraction', pver, 'A', 'Fractional occurance of deposition freezing', phys_decomp)
+ call addfld('FREQMIX', 'fraction', pver, 'A', 'Fractional occurance of mixed-phase clouds' , phys_decomp)
+
+ call addfld('DSTFREZIMM', 'm-3s-1', pver, 'A', 'dust immersion freezing rate', phys_decomp)
+ call addfld('DSTFREZCNT', 'm-3s-1', pver, 'A', 'dust contact freezing rate', phys_decomp)
+ call addfld('DSTFREZDEP', 'm-3s-1', pver, 'A', 'dust deposition freezing rate', phys_decomp)
+
+ call addfld('BCFREZIMM', 'm-3s-1', pver, 'A', 'bc immersion freezing rate', phys_decomp)
+ call addfld('BCFREZCNT', 'm-3s-1', pver, 'A', 'bc contact freezing rate', phys_decomp)
+ call addfld('BCFREZDEP', 'm-3s-1', pver, 'A', 'bc deposition freezing rate', phys_decomp)
+
+ call addfld('NIMIX_IMM', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to het immersion freezing in Mixed Clouds', phys_decomp)
+ call addfld('NIMIX_CNT', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to het contact freezing in Mixed Clouds', phys_decomp)
+ call addfld('NIMIX_DEP', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to het deposition freezing in Mixed Clouds', phys_decomp)
+
+ call addfld('DSTNIDEP', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to dst dep freezing in Mixed Clouds', phys_decomp)
+ call addfld('DSTNICNT', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to dst cnt freezing in Mixed Clouds', phys_decomp)
+ call addfld('DSTNIIMM', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to dst imm freezing in Mixed Clouds', phys_decomp)
+
+ call addfld('BCNIDEP', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to bc dep freezing in Mixed Clouds', phys_decomp)
+ call addfld('BCNICNT', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to bc cnt freezing in Mixed Clouds', phys_decomp)
+ call addfld('BCNIIMM', '#/m3', pver, 'A', &
+ 'Activated Ice Number Concentration due to bc imm freezing in Mixed Clouds', phys_decomp)
+
+ call addfld('NUMICE10s', '#/m3', pver, 'A', &
+ 'Ice Number Concentration due to het freezing in Mixed Clouds during 10-s period', phys_decomp)
+ call addfld('NUMIMM10sDST', '#/m3', pver, 'A', &
+ 'Ice Number Concentration due to imm freezing by dst in Mixed Clouds during 10-s period', phys_decomp)
+ call addfld('NUMIMM10sBC', '#/m3', pver, 'A', &
+ 'Ice Number Concentration due to imm freezing by bc in Mixed Clouds during 10-s period', phys_decomp)
+
+ if (hist_hetfrz_classnuc) then
+
+ call add_default('bc_num', 1, ' ')
+ call add_default('dst1_num', 1, ' ')
+ call add_default('dst3_num', 1, ' ')
+ call add_default('bcc_num', 1, ' ')
+ call add_default('dst1c_num', 1, ' ')
+ call add_default('dst3c_num', 1, ' ')
+ call add_default('bcuc_num', 1, ' ')
+ call add_default('dst1uc_num', 1, ' ')
+ call add_default('dst3uc_num', 1, ' ')
+
+ call add_default('bc_a1_num', 1, ' ')
+ call add_default('dst_a1_num', 1, ' ')
+ call add_default('dst_a3_num', 1, ' ')
+ 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, ' ')
+
+ call add_default('na500', 1, ' ')
+ call add_default('totna500', 1, ' ')
+
+ call add_default('FREQIMM', 1, ' ')
+ call add_default('FREQCNT', 1, ' ')
+ call add_default('FREQDEP', 1, ' ')
+ call add_default('FREQMIX', 1, ' ')
+
+ call add_default('DSTFREZIMM', 1, ' ')
+ call add_default('DSTFREZCNT', 1, ' ')
+ call add_default('DSTFREZDEP', 1, ' ')
+
+ call add_default('BCFREZIMM', 1, ' ')
+ call add_default('BCFREZCNT', 1, ' ')
+ call add_default('BCFREZDEP', 1, ' ')
+
+ call add_default('NIMIX_IMM', 1, ' ')
+ call add_default('NIMIX_CNT', 1, ' ')
+ call add_default('NIMIX_DEP', 1, ' ')
+
+ call add_default('DSTNIDEP', 1, ' ')
+ call add_default('DSTNICNT', 1, ' ')
+ call add_default('DSTNIIMM', 1, ' ')
+
+ call add_default('BCNIDEP', 1, ' ')
+ call add_default('BCNICNT', 1, ' ')
+ call add_default('BCNIIMM', 1, ' ')
+
+ call add_default('NUMICE10s', 1, ' ')
+ call add_default('NUMIMM10sDST', 1, ' ')
+ call add_default('NUMIMM10sBC', 1, ' ')
+
+ end if
+
+ ! The following code sets indices of the mode specific species used
+ ! in the module. Having a list of the species needed allows us to
+ ! allocate temporary space for just those species rather than for all the
+ ! CAM species (pcnst) which may be considerably more than needed.
+ !
+ ! The indices set below are for use with the CAM rad_constituents
+ ! interfaces. Using the rad_constituents interfaces isolates the physics
+ ! parameterization which requires constituent information from the chemistry
+ ! code which provides that information.
+
+ ! nmodes is the total number of modes
+ call rad_cnst_get_info(0, nmodes=nmodes)
+
+ ! Determine mode indices for all modes referenced in this module.
+ mode_accum_idx = rad_cnst_get_mode_idx(0, 'accum')
+ mode_coarse_idx = rad_cnst_get_mode_idx(0, 'coarse')
+ mode_finedust_idx = rad_cnst_get_mode_idx(0, 'fine_dust')
+ mode_coardust_idx = rad_cnst_get_mode_idx(0, 'coarse_dust')
+ mode_pcarbon_idx = rad_cnst_get_mode_idx(0, 'primary_carbon')
+
+ ! Check that required mode types were found
+ if (nmodes == MAM3_nmodes) then
+ if (mode_accum_idx == -1 .or. mode_coarse_idx == -1) then
+ write(iulog,*) routine//': ERROR required mode type not found - mode idx:', &
+ mode_accum_idx, mode_coarse_idx
+ call endrun(routine//': ERROR required mode type not found')
+ end if
+
+ else if (nmodes == MAM7_nmodes) then
+ if (mode_coardust_idx == -1 .or. mode_finedust_idx == -1 .or. mode_pcarbon_idx == -1) then
+ write(iulog,*) routine//': ERROR required mode type not found - mode idx:', &
+ mode_coardust_idx, mode_finedust_idx, mode_pcarbon_idx
+ call endrun(routine//': ERROR required mode type not found')
+ end if
+ end if
+
+ ! Set some mode properties
+
+ 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)
+
+ else if (nmodes == MAM7_nmodes) then
+ call rad_cnst_get_mode_props(0, mode_finedust_idx, sigmag=sigma_logr_aer)
+ alnsg_mode_finedust = log(sigma_logr_aer)
+
+ call rad_cnst_get_mode_props(0, mode_coardust_idx, sigmag=sigma_logr_aer)
+ alnsg_mode_coardust = log(sigma_logr_aer)
+
+ call rad_cnst_get_mode_props(0, mode_pcarbon_idx, sigmag=sigma_logr_aer)
+ alnsg_mode_pcarbon = log(sigma_logr_aer)
+ 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
+ ! constituents in these lists is arbitrary.
+
+ if (nmodes == MAM3_nmodes) then
+ ncnst = 11
+ so4_accum = 1
+ bc_accum = 2
+ pom_accum = 3
+ soa_accum = 4
+ dst_accum = 5
+ ncl_accum = 6
+ num_accum = 7
+ dst_coarse = 8
+ ncl_coarse = 9
+ so4_coarse = 10
+ num_coarse = 11
+ else if (nmodes == MAM7_nmodes) then
+ ncnst = 15
+ so4_accum = 1
+ bc_accum = 2
+ pom_accum = 3
+ soa_accum = 4
+ ncl_accum = 6
+ num_accum = 7
+ dst_finedust = 8
+ so4_finedust = 9
+ num_finedust = 10
+ dst_coardust = 11
+ so4_coardust = 12
+ num_coardust = 13
+ bc_pcarbon = 5
+ pom_pcarbon = 14
+ num_pcarbon = 15
+ end if
+
+ ! 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)
+ mode_idx = -1
+ spec_idx = -1
+
+ ! Allocate space for copy of cloud borne aerosols before modification by droplet nucleation.
+ allocate(aer_cb(pcols,pver,ncnst,begchunk:endchunk), stat=istat)
+ call alloc_err(istat, routine, 'aer_cb', pcols*pver*ncnst*(endchunk-begchunk+1))
+
+ ! Allocate space for copy of interstitial aerosols with modified basis
+ allocate(aer(pcols,pver,ncnst,begchunk:endchunk), stat=istat)
+ call alloc_err(istat, routine, 'aer', pcols*pver*ncnst*(endchunk-begchunk+1))
+
+ ! The following code sets the species and mode indices for each constituent
+ ! in the list. The indices are identical in the interstitial and the cloud
+ ! borne phases.
+ ! Specie index 0 is used to indicate the mode number mixing ratio
+
+ ! Indices for species in accumulation mode (so4, bc, pom, soa, nacl, dust)
+ spec_idx(num_accum) = 0
+ mode_idx(num_accum) = mode_accum_idx
+ spec_idx(so4_accum) = rad_cnst_get_spec_idx(0, mode_accum_idx, 'sulfate')
+ mode_idx(so4_accum) = mode_accum_idx
+ spec_idx(bc_accum) = rad_cnst_get_spec_idx(0, mode_accum_idx, 'black-c')
+ mode_idx(bc_accum) = mode_accum_idx
+ spec_idx(pom_accum) = rad_cnst_get_spec_idx(0, mode_accum_idx, 'p-organic')
+ mode_idx(pom_accum) = mode_accum_idx
+ spec_idx(soa_accum) = rad_cnst_get_spec_idx(0, mode_accum_idx, 's-organic')
+ mode_idx(soa_accum) = mode_accum_idx
+ spec_idx(ncl_accum) = rad_cnst_get_spec_idx(0, mode_accum_idx, 'seasalt')
+ mode_idx(ncl_accum) = mode_accum_idx
+ if (nmodes == MAM3_nmodes) then
+ spec_idx(dst_accum) = rad_cnst_get_spec_idx(0, mode_accum_idx, 'dust')
+ mode_idx(dst_accum) = mode_accum_idx
+ end if
+
+ ! Indices for species in coarse mode (dust, nacl, so4)
+ if (mode_coarse_idx > 0) then
+ spec_idx(num_coarse) = 0
+ mode_idx(num_coarse) = mode_coarse_idx
+ spec_idx(ncl_coarse) = rad_cnst_get_spec_idx(0, mode_coarse_idx, 'seasalt')
+ mode_idx(ncl_coarse) = mode_coarse_idx
+ spec_idx(dst_coarse) = rad_cnst_get_spec_idx(0, mode_coarse_idx, 'dust')
+ mode_idx(dst_coarse) = mode_coarse_idx
+ spec_idx(so4_coarse) = rad_cnst_get_spec_idx(0, mode_coarse_idx, 'sulfate')
+ mode_idx(so4_coarse) = mode_coarse_idx
+ end if
+
+ ! Indices for species in fine dust mode (dust, so4)
+ if (mode_finedust_idx > 0) then
+ spec_idx(num_finedust) = 0
+ mode_idx(num_finedust) = mode_finedust_idx
+ spec_idx(dst_finedust) = rad_cnst_get_spec_idx(0, mode_finedust_idx, 'dust')
+ mode_idx(dst_finedust) = mode_finedust_idx
+ spec_idx(so4_finedust) = rad_cnst_get_spec_idx(0, mode_finedust_idx, 'sulfate')
+ mode_idx(so4_finedust) = mode_finedust_idx
+ end if
+
+ ! Indices for species in coarse dust mode (dust, so4)
+ if (mode_coardust_idx > 0) then
+ spec_idx(num_coardust) = 0
+ mode_idx(num_coardust) = mode_coardust_idx
+ spec_idx(dst_coardust) = rad_cnst_get_spec_idx(0, mode_coardust_idx, 'dust')
+ mode_idx(dst_coardust) = mode_coardust_idx
+ spec_idx(so4_coardust) = rad_cnst_get_spec_idx(0, mode_coardust_idx, 'sulfate')
+ mode_idx(so4_coardust) = mode_coardust_idx
+ end if
+
+ ! Indices for species in primary carbon mode (bc, pom)
+ if (mode_pcarbon_idx > 0) then
+ spec_idx(num_pcarbon) = 0
+ mode_idx(num_pcarbon) = mode_pcarbon_idx
+ spec_idx(bc_pcarbon) = rad_cnst_get_spec_idx(0, mode_pcarbon_idx, 'black-c')
+ mode_idx(bc_pcarbon) = mode_pcarbon_idx
+ 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
+ call endrun(routine//': ERROR required species type not found')
+ end if
+
+ ! Get some specie specific properties.
+ if (nmodes == MAM3_nmodes) then
+ call rad_cnst_get_aer_props(0, mode_idx(dst_accum), spec_idx(dst_accum), density_aer=specdens_dust)
+ else if (nmodes == MAM7_nmodes) then
+ call rad_cnst_get_aer_props(0, mode_idx(dst_finedust), spec_idx(dst_finedust), density_aer=specdens_dust)
+ end if
+ call rad_cnst_get_aer_props(0, mode_idx(so4_accum), spec_idx(so4_accum), density_aer=specdens_so4)
+ call rad_cnst_get_aer_props(0, mode_idx(bc_accum), spec_idx(bc_accum), density_aer=specdens_bc)
+ 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)
+
+end subroutine hetfrz_classnuc_cam_init
+
+!================================================================================================
+
+subroutine hetfrz_classnuc_cam_calc( &
+ state, deltatin, factnum, pbuf)
+
+ ! arguments
+ type(physics_state), target, intent(in) :: state
+ 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
+ real(r8), pointer :: frzimm(:,:)
+ real(r8), pointer :: frzcnt(:,:)
+ real(r8), pointer :: frzdep(:,:)
+
+ integer :: itim_old
+ integer :: i, k
+
+ real(r8) :: rho(pcols,pver) ! air density (kg m-3)
+
+ real(r8), pointer :: ast(:,:)
+
+ real(r8) :: lcldm(pcols,pver)
+
+ real(r8), pointer :: ptr2d(:,:)
+
+ real(r8) :: fn(3)
+ real(r8) :: awcam(pcols,pver,3)
+ real(r8) :: awfacm(pcols,pver,3)
+ real(r8) :: hetraer(pcols,pver,3)
+ real(r8) :: dstcoat(pcols,pver,3)
+ real(r8) :: total_interstitial_aer_num(pcols,pver,3)
+ real(r8) :: total_cloudborne_aer_num(pcols,pver,3)
+ real(r8) :: total_aer_num(pcols,pver,3)
+ real(r8) :: coated_aer_num(pcols,pver,3)
+ real(r8) :: uncoated_aer_num(pcols,pver,3)
+
+ real(r8) :: fn_cloudborne_aer_num(pcols,pver,3)
+
+
+ real(r8) :: con1, r3lx, supersatice
+
+ real(r8) :: qcic
+ real(r8) :: ncic
+
+ real(r8) :: frzbcimm(pcols,pver), frzduimm(pcols,pver)
+ real(r8) :: frzbccnt(pcols,pver), frzducnt(pcols,pver)
+ real(r8) :: frzbcdep(pcols,pver), frzdudep(pcols,pver)
+
+ real(r8) :: freqimm(pcols,pver), freqcnt(pcols,pver), freqdep(pcols,pver), freqmix(pcols,pver)
+ real(r8) :: nnuccc_bc(pcols,pver), nnucct_bc(pcols,pver), nnudep_bc(pcols,pver)
+ real(r8) :: nnuccc_dst(pcols,pver), nnucct_dst(pcols,pver), nnudep_dst(pcols,pver)
+ real(r8) :: niimm_bc(pcols,pver), nicnt_bc(pcols,pver), nidep_bc(pcols,pver)
+ real(r8) :: niimm_dst(pcols,pver), nicnt_dst(pcols,pver), nidep_dst(pcols,pver)
+ real(r8) :: numice10s(pcols,pver)
+ real(r8) :: numice10s_imm_dst(pcols,pver)
+ real(r8) :: numice10s_imm_bc(pcols,pver)
+
+ real(r8) :: na500(pcols,pver)
+ real(r8) :: tot_na500(pcols,pver)
+
+ character(128) :: errstring ! Error status
+ !-------------------------------------------------------------------------------
+
+ associate( &
+ lchnk => state%lchnk, &
+ ncol => state%ncol, &
+ t => state%t, &
+ qc => state%q(:,:,cldliq_idx), &
+ nc => state%q(:,:,numliq_idx), &
+ pmid => state%pmid )
+
+ itim_old = pbuf_old_tim_idx()
+ call pbuf_get_field(pbuf, ast_idx, ast, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+
+ do k = top_lev, pver
+ do i = 1, ncol
+ rho(i,k) = pmid(i,k)/(rair*t(i,k))
+ end do
+ end do
+
+ do k = top_lev, pver
+ do i = 1, ncol
+ lcldm(i,k) = max(ast(i,k), mincld)
+ end do
+ end do
+
+ ! 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)
+ else
+ 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
+
+ ! Init top levels of outputs of get_aer_num
+ total_aer_num = 0._r8
+ coated_aer_num = 0._r8
+ uncoated_aer_num = 0._r8
+ total_interstitial_aer_num = 0._r8
+ total_cloudborne_aer_num = 0._r8
+ hetraer = 0._r8
+ awcam = 0._r8
+ awfacm = 0._r8
+ dstcoat = 0._r8
+ na500 = 0._r8
+ tot_na500 = 0._r8
+
+ ! output aerosols as reference information for heterogeneous freezing
+ do i = 1, ncol
+ do k = top_lev, pver
+ call get_aer_num(i, k, ncnst, aer(:,:,:,lchnk), aer_cb(:,:,:,lchnk), rho(i,k), &
+ total_aer_num(i,k,:), coated_aer_num(i,k,:), uncoated_aer_num(i,k,:), &
+ total_interstitial_aer_num(i,k,:), total_cloudborne_aer_num(i,k,:), &
+ hetraer(i,k,:), awcam(i,k,:), awfacm(i,k,:), dstcoat(i,k,:), &
+ na500(i,k), tot_na500(i,k))
+
+ fn_cloudborne_aer_num(i,k,1) = total_aer_num(i,k,1)*factnum(i,k,mode_accum_idx) ! bc
+ if (nmodes == MAM3_nmodes) then
+ 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)
+ end if
+ end do
+ end do
+
+ call outfld('bc_num', total_aer_num(:,:,1), pcols, lchnk)
+ call outfld('dst1_num', total_aer_num(:,:,2), pcols, lchnk)
+ call outfld('dst3_num', total_aer_num(:,:,3), pcols, lchnk)
+
+ call outfld('bcc_num', coated_aer_num(:,:,1), pcols, lchnk)
+ call outfld('dst1c_num', coated_aer_num(:,:,2), pcols, lchnk)
+ call outfld('dst3c_num', coated_aer_num(:,:,3), pcols, lchnk)
+
+ call outfld('bcuc_num', uncoated_aer_num(:,:,1), pcols, lchnk)
+ call outfld('dst1uc_num', uncoated_aer_num(:,:,2), pcols, lchnk)
+ call outfld('dst3uc_num', uncoated_aer_num(:,:,3), pcols, lchnk)
+
+ call outfld('bc_a1_num', total_interstitial_aer_num(:,:,1), pcols, lchnk)
+ call outfld('dst_a1_num', total_interstitial_aer_num(:,:,2), pcols, lchnk)
+ call outfld('dst_a3_num', total_interstitial_aer_num(:,:,3), pcols, lchnk)
+
+ call outfld('bc_c1_num', total_cloudborne_aer_num(:,:,1), pcols, lchnk)
+ call outfld('dst_c1_num', total_cloudborne_aer_num(:,:,2), pcols, lchnk)
+ call outfld('dst_c3_num', total_cloudborne_aer_num(:,:,3), pcols, lchnk)
+
+ 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)
+
+ ! frzimm, frzcnt, frzdep are the outputs of this parameterization used by the microphysics
+ 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
+
+ frzbcimm(:ncol,:) = 0._r8
+ frzduimm(:ncol,:) = 0._r8
+ frzbccnt(:ncol,:) = 0._r8
+ frzducnt(:ncol,:) = 0._r8
+ frzbcdep(:ncol,:) = 0._r8
+ frzdudep(:ncol,:) = 0._r8
+
+ freqimm(:ncol,:) = 0._r8
+ freqcnt(:ncol,:) = 0._r8
+ freqdep(:ncol,:) = 0._r8
+ freqmix(:ncol,:) = 0._r8
+
+ numice10s(:ncol,:) = 0._r8
+ numice10s_imm_dst(:ncol,:) = 0._r8
+ numice10s_imm_bc(:ncol,:) = 0._r8
+
+ do i = 1, ncol
+ do k = top_lev, pver
+
+ if (t(i,k) > 235.15_r8 .and. t(i,k) < 269.15_r8) then
+ qcic = min(qc(i,k)/lcldm(i,k), 5.e-3_r8)
+ ncic = max(nc(i,k)/lcldm(i,k), 0._r8)
+
+ con1 = 1._r8/(1.333_r8*pi)**0.333_r8
+ r3lx = con1*(rho(i,k)*qcic/(rhoh2o*max(ncic*rho(i,k), 1.0e6_r8)))**0.333_r8 ! in m
+ r3lx = max(4.e-6_r8, r3lx)
+ supersatice = svp_water(t(i,k))/svp_ice(t(i,k))
+
+ fn(1) = factnum(i,k,mode_accum_idx) ! bc accumulation mode
+ if (nmodes == MAM3_nmodes) then
+ 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)
+ end if
+
+ call hetfrz_classnuc_calc( &
+ deltatin, t(i,k), pmid(i,k), supersatice, &
+ fn, r3lx, ncic*rho(i,k)*1.0e-6_r8, frzbcimm(i,k), frzduimm(i,k), &
+ frzbccnt(i,k), frzducnt(i,k), frzbcdep(i,k), frzdudep(i,k), hetraer(i,k,:), &
+ awcam(i,k,:), awfacm(i,k,:), dstcoat(i,k,:), total_aer_num(i,k,:), &
+ coated_aer_num(i,k,:), uncoated_aer_num(i,k,:), total_interstitial_aer_num(i,k,:), &
+ total_cloudborne_aer_num(i,k,:), errstring)
+
+ call handle_errmsg(errstring, subname="hetfrz_classnuc_calc")
+
+ frzimm(i,k) = frzbcimm(i,k) + frzduimm(i,k)
+ frzcnt(i,k) = frzbccnt(i,k) + frzducnt(i,k)
+ frzdep(i,k) = frzbcdep(i,k) + frzdudep(i,k)
+
+ if (frzimm(i,k) > 0._r8) freqimm(i,k) = 1._r8
+ if (frzcnt(i,k) > 0._r8) freqcnt(i,k) = 1._r8
+ if (frzdep(i,k) > 0._r8) freqdep(i,k) = 1._r8
+ if ((frzimm(i,k) + frzcnt(i,k) + frzdep(i,k)) > 0._r8) freqmix(i,k) = 1._r8
+ else
+ frzimm(i,k) = 0._r8
+ frzcnt(i,k) = 0._r8
+ frzdep(i,k) = 0._r8
+ end if
+
+ nnuccc_bc(i,k) = frzbcimm(i,k)*1.0e6_r8*ast(i,k)
+ nnucct_bc(i,k) = frzbccnt(i,k)*1.0e6_r8*ast(i,k)
+ 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)
+ nnudep_dst(i,k) = frzdudep(i,k)*1.0e6_r8*ast(i,k)
+
+ niimm_bc(i,k) = frzbcimm(i,k)*1.0e6_r8*deltatin
+ nicnt_bc(i,k) = frzbccnt(i,k)*1.0e6_r8*deltatin
+ nidep_bc(i,k) = frzbcdep(i,k)*1.0e6_r8*deltatin
+
+ niimm_dst(i,k) = frzduimm(i,k)*1.0e6_r8*deltatin
+ nicnt_dst(i,k) = frzducnt(i,k)*1.0e6_r8*deltatin
+ nidep_dst(i,k) = frzdudep(i,k)*1.0e6_r8*deltatin
+
+ numice10s(i,k) = (frzimm(i,k)+frzcnt(i,k)+frzdep(i,k))*1.0e6_r8*deltatin*(10._r8/deltatin)
+ numice10s_imm_dst(i,k) = frzduimm(i,k)*1.0e6_r8*deltatin*(10._r8/deltatin)
+ numice10s_imm_bc(i,k) = frzbcimm(i,k)*1.0e6_r8*deltatin*(10._r8/deltatin)
+ end do
+ end do
+
+ call outfld('FREQIMM', freqimm, pcols, lchnk)
+ call outfld('FREQCNT', freqcnt, pcols, lchnk)
+ call outfld('FREQDEP', freqdep, pcols, lchnk)
+ call outfld('FREQMIX', freqmix, pcols, lchnk)
+
+ call outfld('DSTFREZIMM', nnuccc_dst, pcols, lchnk)
+ call outfld('DSTFREZCNT', nnucct_dst, pcols, lchnk)
+ call outfld('DSTFREZDEP', nnudep_dst, pcols, lchnk)
+
+ call outfld('BCFREZIMM', nnuccc_bc, pcols, lchnk)
+ call outfld('BCFREZCNT', nnucct_bc, pcols, lchnk)
+ 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_DEP', nidep_bc+nidep_dst, pcols, lchnk)
+
+ call outfld('DSTNICNT', nicnt_dst, pcols, lchnk)
+ call outfld('DSTNIDEP', nidep_dst, pcols, lchnk)
+ call outfld('DSTNIIMM', niimm_dst, pcols, lchnk)
+
+ call outfld('BCNICNT', nicnt_bc, pcols, lchnk)
+ call outfld('BCNIDEP', nidep_bc, pcols, lchnk)
+ call outfld('BCNIIMM', niimm_bc, pcols, lchnk)
+
+ call outfld('NUMICE10s', numice10s, pcols, lchnk)
+ call outfld('NUMIMM10sDST', numice10s_imm_dst, pcols, lchnk)
+ call outfld('NUMIMM10sBC', numice10s_imm_bc, pcols, lchnk)
+
+ end associate
+
+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, &
+ uncoated_aer_num, &
+ total_interstial_aer_num, &
+ 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
+ !
+ ! Author: Yong Wang and Xiaohong Liu, UWyo, 12/2012
+ !*****************************************************************************
+
+ ! input
+ integer, intent(in) :: ii, kk, ncnst
+ real(r8), intent(in) :: aer(pcols,pver,ncnst) ! interstitial aerosols, volume basis
+ real(r8), intent(in) :: aer_cb(pcols,pver,ncnst) ! cloud borne aerosols, volume basis
+ real(r8), intent(in) :: rhoair ! air density (kg/m3)
+
+ ! The interstitial and cloud borne aerosol concentrations are accessed from
+ ! module variables local to this module.
+
+ ! output
+ 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) :: 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]
+ real(r8), intent(out) :: awfacm(3) ! (OC+BC)/(OC+BC+SO4)
+ real(r8), intent(out) :: dstcoat(3) ! coated fraction
+ real(r8), intent(out) :: na500 ! #/cm^3 interstitial aerosol number with D>500 nm (#/cm^3)
+ real(r8), intent(out) :: tot_na500 ! #/cm^3 total aerosol number with D>500 nm (#/cm^3)
+
+
+ !local variables
+ !------------coated variables--------------------
+ real(r8), parameter :: n_so4_monolayers_dust = 1.0_r8 ! number of so4(+nh4) monolayers needed to coat a dust particle
+ real(r8), parameter :: dr_so4_monolayers_dust = n_so4_monolayers_dust * 4.76e-10_r8
+ real(r8), parameter :: spechygro_so4 = 0.507_r8 ! Sulfate hygroscopicity
+ real(r8), parameter :: spechygro_soa = 0.14_r8 ! SOA hygroscopicity
+ real(r8), parameter :: spechygro_pom = 0.1_r8 ! POM hygroscopicity
+ 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) :: 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
+ ! bc number in accumulation and primary carbon mode for MAM7
+ 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
+ logical :: num_to_mass_in = .true.
+ 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) :: 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) :: 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]
+
+ integer :: i
+ real(r8) :: dst1_scale
+ !-------------------------------------------------------------------------------
+
+ ! init output vars
+ total_aer_num = 0._r8
+ total_interstial_aer_num = 0._r8
+ total_cloudborne_aer_num = 0._r8
+ coated_aer_num = 0._r8
+ uncoated_aer_num = 0._r8
+ hetraer = 0._r8
+ awcam = 0._r8
+ awfacm = 0._r8
+ dstcoat = 0._r8
+ na500 = 0._r8
+ tot_na500 = 0._r8
+
+ !*****************************************************************************
+ ! calculate intersitial aerosol
+ !*****************************************************************************
+
+ if (nmodes == MAM3_nmodes) then
+
+ if (.not. num_to_mass_in) then
+
+ as_so4 = aer(ii,kk,so4_accum)
+ as_bc = aer(ii,kk,bc_accum)
+ as_pom = aer(ii,kk,pom_accum)
+ as_soa = aer(ii,kk,soa_accum)
+ as_ss = aer(ii,kk,ncl_accum)
+ as_du = aer(ii,kk,dst_accum)
+
+ if (as_du > 0._r8) then
+ dst1_num = as_du/(as_so4+as_bc+as_pom+as_soa+as_ss+as_du) &
+ * aer(ii,kk,num_accum)*1.0e-6_r8 ! #/cm^3
+ else
+ dst1_num = 0.0_r8
+ end if
+
+ if (as_bc > 0._r8) then
+ bc_num = as_bc/(as_so4+as_bc+as_pom+as_soa+as_ss+as_du) &
+ * aer(ii,kk,num_accum)*1.0e-6_r8 ! #/cm^3
+ else
+ bc_num = 0.0_r8
+ end if
+
+ else
+
+ dst1_num = aer(ii,kk,dst_accum) * dst1_num_to_mass*1.0e-6_r8 ! #/cm^3, dust # in accumulation mode
+ bc_num = aer(ii,kk,bc_accum) * bc_num_to_mass*1.0e-6_r8 ! #/cm^3
+ end if
+ dmc = aer(ii,kk,dst_coarse)
+ ssmc = aer(ii,kk,ncl_coarse)
+
+ if (dmc > 0._r8 ) then
+ dst3_num = dmc/(ssmc+dmc) * aer(ii,kk,num_coarse)*1.0e-6_r8 ! #/cm^3
+ else
+ dst3_num = 0.0_r8
+ 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
+ end if
+
+ !*****************************************************************************
+ ! calculate cloud borne aerosol
+ !*****************************************************************************
+
+ if (nmodes == MAM3_nmodes) then
+
+ as_so4 = aer_cb(ii,kk,so4_accum)
+ as_bc = aer_cb(ii,kk,bc_accum)
+ as_pom = aer_cb(ii,kk,pom_accum)
+ as_soa = aer_cb(ii,kk,soa_accum)
+ as_ss = aer_cb(ii,kk,ncl_accum)
+ as_du = aer_cb(ii,kk,dst_accum)
+
+ if (as_du > 0._r8) then
+ dst1_num_imm = as_du/(as_so4+as_bc+as_pom+as_soa+as_ss+as_du) &
+ * aer_cb(ii,kk,num_accum)*1.0e-6_r8 ! #/cm^3
+ else
+ dst1_num_imm = 0.0_r8
+ end if
+
+ if (as_bc > 0._r8) then
+ bc_num_imm = as_bc/(as_so4+as_bc+as_pom+as_soa+as_ss+as_du) &
+ * aer_cb(ii,kk,num_accum)*1.0e-6_r8 ! #/cm^3
+ 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)
+
+ 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
+ else
+ dst3_num_imm = 0.0_r8
+ end if
+
+ else if (nmodes == MAM7_nmodes) then
+ ! primary carbon mode is insoluble and thus don't consider its cloud-borne state
+ as_so4 = aer_cb(ii,kk,so4_accum)
+ as_bc = aer_cb(ii,kk,bc_accum)
+ as_pom = aer_cb(ii,kk,pom_accum)
+ as_soa = aer_cb(ii,kk,soa_accum)
+ as_ss = aer_cb(ii,kk,ncl_accum)
+ if (as_bc > 0._r8) then
+ bc_num_imm = as_bc/(as_so4+as_bc+as_pom+as_soa+as_ss) &
+ * aer_cb(ii,kk,num_accum)*1.0e-6_r8 ! #/cm^3
+ else
+ bc_num_imm = 0.0_r8
+ end if
+ dst1_num_imm = aer_cb(ii,kk,num_finedust)*1.0e-6_r8 ! #/cm^3
+ dst3_num_imm = aer_cb(ii,kk,num_coardust)*1.0e-6_r8 ! #/cm^3
+ end if
+
+ total_interstial_aer_num(1) = bc_num
+ total_interstial_aer_num(2) = dst1_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(3) = dst3_num_imm
+
+ !*****************************************************************************
+ ! calculate mass mean radius
+ !*****************************************************************************
+
+ if (nmodes == MAM3_nmodes) then
+
+ if (aer(ii,kk,bc_accum)*1.0e-3_r8 > 1.0e-30_r8 .and. bc_num > 1.0e-3_r8) then
+ r_bc = ( 3._r8/(4*pi*specdens_bc)*aer(ii,kk,bc_accum)/(bc_num*1.0e6_r8) )**(1._r8/3._r8)
+ else
+ r_bc = 0.04e-6_r8
+ end if
+
+ if (aer(ii,kk,dst_accum)*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_accum)/(dst1_num*1.0e6_r8) )**(1._r8/3._r8)
+ else
+ r_dust_a1 = 0.258e-6_r8
+ end if
+
+ if (aer(ii,kk,dst_coarse)*1.0e-3_r8 > 1.0e-30_r8 .and. dst3_num > 1.0e-3_r8) then
+ r_dust_a3 = ( 3._r8/(4*pi*specdens_dust)*aer(ii,kk,dst_coarse)/(dst3_num*1.0e6_r8) )**(1._r8/3._r8)
+ else
+ r_dust_a3 = 1.576e-6_r8
+ end if
+
+ else if (nmodes == MAM7_nmodes) then
+
+ if ((aer(ii,kk,bc_accum)+aer(ii,kk,bc_pcarbon))*1.0e-3_r8 > 1.0e-30_r8 &
+ .and. bc_num > 1.0e-3_r8) then
+ r_bc = ( 3._r8/(4*pi*specdens_bc)*(aer(ii,kk,bc_accum)+aer(ii,kk,bc_pcarbon))/ &
+ (bc_num*1.0e6_r8) )**(1._r8/3._r8)
+ 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
+ r_dust_a1 = 0.258e-6_r8
+ end if
+
+ if (aer(ii,kk,dst_coardust)*1.0e-3_r8 > 1.0e-30_r8 .and. dst3_num > 1.0e-3_r8) then
+ r_dust_a3 = ( 3._r8/(4*pi*specdens_dust)*aer(ii,kk,dst_coardust)/(dst3_num*1.0e6_r8) )**(1._r8/3._r8)
+ else
+ r_dust_a3 = 1.576e-6_r8
+ end if
+ end if
+
+ hetraer(1) = r_bc
+ hetraer(2) = r_dust_a1
+ hetraer(3) = r_dust_a3
+
+ !*****************************************************************************
+ ! calculate coated fraction
+ !*****************************************************************************
+
+ if (nmodes == MAM3_nmodes) then
+
+ fac_volsfc_bc = exp(2.5_r8*alnsg_mode_accum**2)
+ fac_volsfc_dust_a1 = exp(2.5_r8*alnsg_mode_accum**2)
+ fac_volsfc_dust_a3 = exp(2.5_r8*alnsg_mode_coarse**2)
+
+ vol_shell(2) = ( aer(ii,kk,so4_accum)/specdens_so4 + &
+ aer(ii,kk,pom_accum)*pom_equivso4_factor/specdens_pom + &
+ aer(ii,kk,soa_accum)*soa_equivso4_factor/specdens_soa )/rhoair
+
+ vol_core(2) = aer(ii,kk,dst_accum)/(specdens_dust*rhoair)
+
+ ! 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
+ ! 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
+
+ ! bc
+ vol_shell(1) = vol_shell(2)
+ vol_core(1) = aer(ii,kk,bc_accum)/(specdens_bc*rhoair)
+ tmp1 = vol_shell(1)*(r_bc*2._r8)*fac_volsfc_bc
+ tmp2 = max(6.0_r8*dr_so4_monolayers_dust*vol_core(1), 0.0_r8)
+ dstcoat(1) = tmp1/tmp2
+
+ ! dust_a1
+ tmp1 = vol_shell(2)*(r_dust_a1*2._r8)*fac_volsfc_dust_a1
+ tmp2 = max(6.0_r8*dr_so4_monolayers_dust*vol_core(2), 0.0_r8)
+ dstcoat(2) = tmp1/tmp2
+
+ ! dust_a3
+ vol_shell(3) = aer(ii,kk,so4_coarse)/(specdens_so4*rhoair)
+ vol_core(3) = aer(ii,kk,dst_coarse)/(specdens_dust*rhoair)
+ 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
+
+ else if (nmodes == MAM7_nmodes) then
+
+ ! for BC, only consider primary carbon mode,
+ ! because most of particles in this mode are uncoated
+ ! and nearly all particles in accumulation mode are coated
+ fac_volsfc_bc = exp(2.5_r8*alnsg_mode_pcarbon**2)
+
+ vol_shell(1) = ( aer(ii,kk,pom_pcarbon)*pom_equivso4_factor/specdens_pom )/rhoair
+ vol_core(1) = aer(ii,kk,bc_pcarbon)/(specdens_bc*rhoair)
+ tmp1 = vol_shell(1)*(r_bc*2._r8)*fac_volsfc_bc
+ tmp2 = max(6.0_r8*dr_so4_monolayers_dust*vol_core(1), 0.0_r8)
+ dstcoat(1) = tmp1/tmp2
+
+ fac_volsfc_dust_a1 = exp(2.5_r8*alnsg_mode_finedust**2)
+ fac_volsfc_dust_a3 = exp(2.5_r8*alnsg_mode_coardust**2)
+
+ vol_shell(2) = aer(ii,kk,so4_finedust)/(specdens_so4*rhoair)
+ vol_core(2) = aer(ii,kk,dst_finedust)/(specdens_dust*rhoair)
+
+ tmp1 = vol_shell(2)*(r_dust_a1*2._r8)*fac_volsfc_dust_a1
+ tmp2 = max(6.0_r8*dr_so4_monolayers_dust*vol_core(2), 0.0_r8)
+ dstcoat(2) = tmp1/tmp2
+
+ 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
+ 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
+ if (dstcoat(1) < 0.001_r8) dstcoat(1) = 0.001_r8
+ if (dstcoat(2) > 1._r8) dstcoat(2) = 1._r8
+ 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 == MAM7_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))
+ end if
+
+ if (nmodes == MAM3_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
+ dst1_scale = 0.566_r8 ! scaled for D>0.5-2 um from 0.1-2 um
+ end if
+
+ tot_na500 = total_aer_num(1)*0.0256_r8 & ! scaled for D>0.5 um using Clarke et al., 1997; 2004; 2007: rg=0.1um, sig=1.6
+ + total_aer_num(2)*dst1_scale + total_aer_num(3)
+
+ na500 = total_interstial_aer_num(1)*0.0256_r8 & ! scaled for D>0.5 um using Clarke et al., 1997; 2004; 2007: rg=0.1um, sig=1.6
+ + total_interstial_aer_num(2)*dst1_scale + total_interstial_aer_num(3)
+
+ !*****************************************************************************
+ ! prepare some variables for water activity
+ !*****************************************************************************
+
+ if (nmodes == MAM3_nmodes) 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]
+ else
+ awcam(2) = 0._r8
+ end if
+
+ 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
+ awfacm(2) = 0._r8
+ end if
+
+ ! accumulation mode for bc
+ if (aer(ii,kk,num_accum) > 0._r8) then
+ awcam(1) = (bc_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]
+ else
+ awcam(1) = 0._r8
+ end if
+ awfacm(1) = awfacm(2)
+
+ ! coarse mode for dust_a3
+ if (aer(ii,kk,num_coarse) > 0._r8) then
+ awcam(3) = (dst3_num*1.0e6_r8)/aer(ii,kk,num_coarse)* aer(ii,kk,so4_coarse)*1.0e9_r8
+ else
+ awcam(3) = 0._r8
+ end if
+ awfacm(3) = 0._r8
+
+ else if (nmodes == MAM7_nmodes) then
+
+ ! accumulation mode for bc (primary carbon mode is insoluble)
+ if (aer(ii,kk,num_accum) > 0._r8) then
+ awcam(1) = (bc_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]
+ else
+ awcam(1) = 0._r8
+ end if
+
+ if (awcam(1) > 0._r8) then
+ awfacm(1) = ( 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
+ awfacm(1) = 0._r8
+ end if
+
+ if (aer(ii,kk,num_finedust) > 0._r8) then
+ awcam(2) = (dst1_num*1.0e6_r8)/aer(ii,kk,num_finedust)* aer(ii,kk,so4_finedust)*1.0e9_r8
+ else
+ awcam(2) = 0._r8
+ end if
+ awfacm(2) = 0._r8
+
+ 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
+ awcam(3) = 0._r8
+ end if
+ awfacm(3) = 0._r8
+
+ end if
+
+end subroutine get_aer_num
+
+!====================================================================================================
+
+end module hetfrz_classnuc_cam
diff --git a/models/atm/cam/src/physics/cam/macrop_driver.F90 b/models/atm/cam/src/physics/cam/macrop_driver.F90
index bc42e1fb274e..046c48938d3a 100644
--- a/models/atm/cam/src/physics/cam/macrop_driver.F90
+++ b/models/atm/cam/src/physics/cam/macrop_driver.F90
@@ -13,11 +13,14 @@ module macrop_driver
use shr_kind_mod, only: r8=>shr_kind_r8
use spmd_utils, only: masterproc
use ppgrid, only: pcols, pver, pverp
- use physconst, only: latice
+ use physconst, only: latice, latvap
use phys_control, only: phys_getopts
use constituents, only: cnst_get_ind, pcnst
- use perf_mod, only: t_startf, t_stopf
- use cam_logfile, only: iulog
+ use physics_buffer, only: physics_buffer_desc, pbuf_set_field, pbuf_get_field, pbuf_old_tim_idx
+ use time_manager, only: is_first_step
+ use cldwat2m_macro, only: ini_macro
+ use perf_mod, only: t_startf, t_stopf
+ use cam_logfile, only: iulog
use cam_abortutils, only: endrun
implicit none
@@ -28,6 +31,7 @@ module macrop_driver
public :: macrop_driver_register
public :: macrop_driver_init
public :: macrop_driver_tend
+ public :: ice_macro_tend
logical, public :: do_cldice ! .true., park macrophysics is prognosing cldice
logical, public :: do_cldliq ! .true., park macrophysics is prognosing cldliq
@@ -42,13 +46,17 @@ module macrop_driver
! evaporate cumulus liquid condensate. This option only influences the treatment of cumulus
! liquid condensate, not cumulus ice condensate.
- logical, private, parameter :: cu_det_st = .false.
+ logical, parameter :: cu_det_st = .false.
- ! -------------------------------- !
- ! End of Private Module Parameters !
- ! -------------------------------- !
+ logical :: micro_do_icesupersat
- logical :: use_shfrc ! Local copy of flag from convect_shallow_use_shfrc
+ ! Parameters used for selecting generalized critical RH for liquid and ice stratus
+ integer :: rhminl_opt = 0
+ integer :: rhmini_opt = 0
+
+
+ character(len=16) :: shallow_scheme
+ logical :: use_shfrc ! Local copy of flag from convect_shallow_use_shfrc
integer :: &
ixcldliq, &! cloud liquid amount index
@@ -77,8 +85,16 @@ module macrop_driver
concld_idx, &! concld index in physics buffer
fice_idx, &
cmeliq_idx, &
- shfrc_idx
-
+ shfrc_idx, &
+ naai_idx
+
+ integer :: &
+ tke_idx = -1, &! tke defined at the model interfaces
+ qtl_flx_idx = -1, &! overbar(w'qtl' where qtl = qv + ql) from the PBL scheme
+ qti_flx_idx = -1, &! overbar(w'qti' where qti = qv + qi) from the PBL scheme
+ cmfr_det_idx = -1, &! detrained convective mass flux from UNICON
+ qlr_det_idx = -1, &! detrained convective ql from UNICON
+ qir_det_idx = -1 ! detrained convective qi from UNICON
contains
@@ -92,16 +108,15 @@ subroutine macrop_driver_readnl(nlfile)
character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
! Namelist variables
- logical :: macro_park_do_cldice = .true. ! do_cldice = .true., park macrophysics is prognosing cldice
- logical :: macro_park_do_cldliq = .true. ! do_cldliq = .true., park macrophysics is prognosing cldliq
- logical :: macro_park_do_detrain = .true. ! do_detrain = .true., park macrophysics is detraining ice into stratiform
+ logical :: macro_park_do_cldice = .true. ! do_cldice = .true., park macrophysics is prognosing cldice
+ logical :: macro_park_do_cldliq = .true. ! do_cldliq = .true., park macrophysics is prognosing cldliq
+ logical :: macro_park_do_detrain = .true. ! do_detrain = .true., park macrophysics is detraining ice into stratiform
! Local variables
integer :: unitn, ierr
character(len=*), parameter :: subname = 'macrop_driver_readnl'
namelist /macro_park_nl/ macro_park_do_cldice, macro_park_do_cldliq, macro_park_do_detrain
-
!-----------------------------------------------------------------------------
if (masterproc) then
@@ -125,13 +140,11 @@ subroutine macrop_driver_readnl(nlfile)
end if
-
-
#ifdef SPMD
! Broadcast namelist variables
- call mpibcast(do_cldice, 1, mpilog, 0, mpicom)
- call mpibcast(do_cldliq, 1, mpilog, 0, mpicom)
- call mpibcast(do_detrain, 1, mpilog, 0, mpicom)
+ call mpibcast(do_cldice, 1, mpilog, 0, mpicom)
+ call mpibcast(do_cldliq, 1, mpilog, 0, mpicom)
+ call mpibcast(do_detrain, 1, mpilog, 0, mpicom)
#endif
end subroutine macrop_driver_readnl
@@ -152,6 +165,8 @@ subroutine macrop_driver_register
!-----------------------------------------------------------------------
+ call phys_getopts(shallow_scheme_out=shallow_scheme)
+
call pbuf_add_field('AST', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), ast_idx)
call pbuf_add_field('AIST', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), aist_idx)
call pbuf_add_field('ALST', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), alst_idx)
@@ -177,7 +192,7 @@ end subroutine macrop_driver_register
! !
!============================================================================ !
- subroutine macrop_driver_init()
+ subroutine macrop_driver_init(pbuf2d)
!-------------------------------------------- !
! !
@@ -188,21 +203,25 @@ subroutine macrop_driver_init()
use cam_history, only: addfld, add_default, phys_decomp
use convect_shallow, only: convect_shallow_use_shfrc
-
+ type(physics_buffer_desc), pointer :: pbuf2d(:,:)
logical :: history_aerosol ! Output the MAM aerosol tendencies
logical :: history_budget ! Output tendencies and state variables for CAM4
! temperature, water vapor, cloud ice and cloud
! liquid budgets.
integer :: history_budget_histfile_num ! output history file number for budget fields
+ integer :: istat
+ character(len=*), parameter :: subname = 'macrop_driver_init'
+ !-----------------------------------------------------------------------
- !-----------------------------------------------------------------------
-
- call phys_getopts( history_aerosol_out = history_aerosol , &
- history_budget_out = history_budget , &
- history_budget_histfile_num_out = history_budget_histfile_num)
+ ! Initialization routine for cloud macrophysics
+ if (shallow_scheme .eq. 'UNICON') rhminl_opt = 1
+ call ini_macro(rhminl_opt, rhmini_opt)
- ! Initialization routine for cloud macrophysics
+ call phys_getopts(history_aerosol_out = history_aerosol , &
+ history_budget_out = history_budget , &
+ history_budget_histfile_num_out = history_budget_histfile_num, &
+ micro_do_icesupersat_out = micro_do_icesupersat)
! Find out whether shfrc from convect_shallow will be used in cldfrc
@@ -213,7 +232,6 @@ subroutine macrop_driver_init()
use_shfrc = .false.
endif
-
call addfld ('DPDLFLIQ ', 'kg/kg/s ', pver, 'A', 'Detrained liquid water from deep convection' ,phys_decomp)
call addfld ('DPDLFICE ', 'kg/kg/s ', pver, 'A', 'Detrained ice from deep convection' ,phys_decomp)
call addfld ('SHDLFLIQ ', 'kg/kg/s ', pver, 'A', 'Detrained liquid water from shallow convection' ,phys_decomp)
@@ -246,15 +264,21 @@ subroutine macrop_driver_init()
call addfld ('CLDST ', 'fraction', pver, 'A', 'Stratus cloud fraction' ,phys_decomp)
call addfld ('CONCLD ', 'fraction', pver, 'A', 'Convective cloud cover' ,phys_decomp)
+ call addfld ('CLR_LIQ', 'fraction', pver, 'A', 'Clear sky fraction for liquid stratus' , phys_decomp)
+ call addfld ('CLR_ICE', 'fraction', pver, 'A', 'Clear sky fraction for ice stratus' , phys_decomp)
+
call addfld ('CLDLIQSTR ', 'kg/kg', pver, 'A', 'Stratiform CLDLIQ' ,phys_decomp)
call addfld ('CLDICESTR ', 'kg/kg', pver, 'A', 'Stratiform CLDICE' ,phys_decomp)
call addfld ('CLDLIQCON ', 'kg/kg', pver, 'A', 'Convective CLDLIQ' ,phys_decomp)
call addfld ('CLDICECON ', 'kg/kg', pver, 'A', 'Convective CLDICE' ,phys_decomp)
call addfld ('CLDSICE ', 'kg/kg ', pver, 'A', 'CloudSat equivalent ice mass mixing ratio' ,phys_decomp)
-
call addfld ('CMELIQ ', 'kg/kg/s ', pver, 'A', 'Rate of cond-evap of liq within the cloud' ,phys_decomp)
+ call addfld ('TTENDICE', 'K/s ', pver, 'A', 'T tendency from Ice Saturation Adjustment' ,phys_decomp)
+ call addfld ('QVTENDICE', 'kg/kg/s ', pver, 'A', 'Q tendency from Ice Saturation Adjustment' ,phys_decomp)
+ call addfld ('QITENDICE', 'kg/kg/s ', pver, 'A', 'CLDICE tendency from Ice Saturation Adjustment' ,phys_decomp)
+ call addfld ('NITENDICE', 'kg/kg/s ', pver, 'A', 'NUMICE tendency from Ice Saturation Adjustment' ,phys_decomp)
if ( history_budget ) then
call add_default ('DPDLFLIQ ', history_budget_histfile_num, ' ')
@@ -297,6 +321,49 @@ subroutine macrop_driver_init()
CC_ni_idx = pbuf_get_index('CC_ni')
CC_qlst_idx = pbuf_get_index('CC_qlst')
+ if (micro_do_icesupersat) then
+ naai_idx = pbuf_get_index('NAAI')
+ endif
+
+ if (rhminl_opt > 0 .or. rhmini_opt > 0) then
+ cmfr_det_idx = pbuf_get_index('cmfr_det', istat)
+ if (istat < 0) call endrun(subname//': macrop option requires cmfr_det in pbuf')
+ if (rhminl_opt > 0) then
+ qlr_det_idx = pbuf_get_index('qlr_det', istat)
+ if (istat < 0) call endrun(subname//': macrop option requires qlr_det in pbuf')
+ end if
+ if (rhmini_opt > 0) then
+ qir_det_idx = pbuf_get_index('qir_det', istat)
+ if (istat < 0) call endrun(subname//': macrop option requires qir_det in pbuf')
+ end if
+ end if
+
+ if (rhminl_opt == 2 .or. rhmini_opt == 2) then
+ tke_idx = pbuf_get_index('tke')
+ if (rhminl_opt == 2) then
+ qtl_flx_idx = pbuf_get_index('qtl_flx', istat)
+ if (istat < 0) call endrun(subname//': macrop option requires qtl_flx in pbuf')
+ end if
+ if (rhmini_opt == 2) then
+ qti_flx_idx = pbuf_get_index('qti_flx', istat)
+ if (istat < 0) call endrun(subname//': macrop option requires qti_flx in pbuf')
+ end if
+ end if
+
+ ! Init pbuf fields. Note that the fields CLD, CONCLD, QCWAT, LCWAT,
+ ! ICCWAT, and TCWAT are initialized in phys_inidat.
+ if (is_first_step()) then
+ call pbuf_set_field(pbuf2d, ast_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, aist_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, alst_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, qist_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, qlst_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, nlwat_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, niwat_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, fice_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cmeliq_idx, 0._r8)
+ end if
+
end subroutine macrop_driver_init
!============================================================================ !
@@ -310,7 +377,7 @@ subroutine macrop_driver_tend( &
dlf, dlf2, cmfmc, cmfmc2, ts, &
sst, zdu, &
pbuf, &
- det_s, det_ice)
+ det_s, det_ice)
!-------------------------------------------------------- !
! !
@@ -324,14 +391,12 @@ subroutine macrop_driver_tend( &
! !
!-------------------------------------------------------- !
- use shr_kind_mod, only: r8 => shr_kind_r8
use cloud_fraction, only: cldfrc, cldfrc_fice
use physics_types, only: physics_state, physics_ptend
use physics_types, only: physics_ptend_init, physics_update
use physics_types, only: physics_ptend_sum, physics_state_copy
use physics_types, only: physics_state_dealloc
use cam_history, only: outfld
- use physics_buffer, only : physics_buffer_desc, pbuf_get_field, pbuf_old_tim_idx
use constituents, only: cnst_get_ind, pcnst
use cldwat2m_macro, only: mmacro_pcond
use physconst, only: cpair, tmelt, gravit
@@ -339,8 +404,6 @@ subroutine macrop_driver_tend( &
use ref_pres, only: top_lev => trop_cloud_top_lev
- implicit none
-
!
! Input arguments
!
@@ -377,7 +440,6 @@ subroutine macrop_driver_tend( &
integer i,k
integer :: lchnk ! Chunk identifier
integer :: ncol ! Number of atmospheric columns
- integer :: conv_water_in_rad
! Physics buffer fields
@@ -407,10 +469,27 @@ subroutine macrop_driver_tend( &
real(r8), pointer, dimension(:,:) :: cmeliq
+ real(r8), pointer, dimension(:,:) :: tke
+ real(r8), pointer, dimension(:,:) :: qtl_flx
+ real(r8), pointer, dimension(:,:) :: qti_flx
+ real(r8), pointer, dimension(:,:) :: cmfr_det
+ real(r8), pointer, dimension(:,:) :: qlr_det
+ real(r8), pointer, dimension(:,:) :: qir_det
+
! Convective cloud to the physics buffer for purposes of ql contrib. to radn.
real(r8), pointer, dimension(:,:) :: fice_ql ! Cloud ice/water partitioning ratio.
+ real(r8), pointer, dimension(:,:) :: naai ! Number concentration of activated ice nuclei
+
+ real(r8) :: latsub
+
+ ! tendencies for ice saturation adjustment
+ real(r8) :: stend(pcols,pver)
+ real(r8) :: qvtend(pcols,pver)
+ real(r8) :: qitend(pcols,pver)
+ real(r8) :: initend(pcols,pver)
+
! Local variables for cldfrc
real(r8) cldst(pcols,pver) ! Stratus cloud fraction
@@ -479,6 +558,14 @@ subroutine macrop_driver_tend( &
real(r8) qi_inout(pcols,pver)
real(r8) concld_old(pcols,pver)
+ ! Note that below 'clr_old' is defined using 'alst_old' not 'ast_old' for full consistency with the
+ ! liquid condensation process which is using 'alst' not 'ast'.
+ ! For microconsistency use 'concld_old', since 'alst_old' was computed using 'concld_old'.
+ ! Since convective updraft fractional area is small, it does not matter whether 'concld' or 'concld_old' is used.
+ ! Note also that 'clri_old' is defined using 'ast_old' since current microphysics is operating on 'ast_old'
+ real(r8) clrw_old(pcols,pver) ! (1 - concld_old - alst_old)
+ real(r8) clri_old(pcols,pver) ! (1 - concld_old - ast_old)
+
real(r8) nl_inout(pcols,pver)
real(r8) ni_inout(pcols,pver)
@@ -497,21 +584,23 @@ subroutine macrop_driver_tend( &
real(r8) dlf_ni(pcols,pver)
! Local variables for CFMIP calculations
- real(r8) :: mr_lsliq(pcols,pver) ! mixing_ratio_large_scale_cloud_liquid (kg/kg)
- real(r8) :: mr_lsice(pcols,pver) ! mixing_ratio_large_scale_cloud_ice (kg/kg)
- real(r8) :: mr_ccliq(pcols,pver) ! mixing_ratio_convective_cloud_liquid (kg/kg)
- real(r8) :: mr_ccice(pcols,pver) ! mixing_ratio_convective_cloud_ice (kg/kg)
+ real(r8) :: mr_lsliq(pcols,pver) ! mixing_ratio_large_scale_cloud_liquid (kg/kg)
+ real(r8) :: mr_lsice(pcols,pver) ! mixing_ratio_large_scale_cloud_ice (kg/kg)
+ real(r8) :: mr_ccliq(pcols,pver) ! mixing_ratio_convective_cloud_liquid (kg/kg)
+ real(r8) :: mr_ccice(pcols,pver) ! mixing_ratio_convective_cloud_ice (kg/kg)
! CloudSat equivalent ice mass mixing ratio (kg/kg)
real(r8) :: cldsice(pcols,pver)
! ======================================================================
+ if (micro_do_icesupersat) then
+ call pbuf_get_field(pbuf, naai_idx, naai)
+ endif
+
lchnk = state%lchnk
ncol = state%ncol
- call phys_getopts( conv_water_in_rad_out = conv_water_in_rad )
-
call physics_state_copy(state, state_loc) ! Copy state to local state_loc.
! Associate pointers with physics buffer fields
@@ -636,7 +725,7 @@ subroutine macrop_driver_tend( &
! Only rliq is saved from deep convection, which is the reserved liquid. We need to keep
! track of the integrals of ice and static energy that is effected from conversion to ice
- ! so that the energy checker doesn't complain.
+ ! so that the energy checker doesn't complain.
det_s(i) = det_s(i) + ptend_loc%s(i,k)*state_loc%pdel(i,k)/gravit
det_ice(i) = det_ice(i) - ptend_loc%q(i,k,ixcldice)*state_loc%pdel(i,k)/gravit
@@ -690,6 +779,53 @@ subroutine macrop_driver_tend( &
! ptend_loc is reset to zero by this call
call physics_update(state_loc, ptend_loc, dtime)
+ if (micro_do_icesupersat) then
+
+ ! -------------------------------------- !
+ ! Ice Saturation Adjustment Computation !
+ ! -------------------------------------- !
+
+ lq(:) = .FALSE.
+
+ lq(1) = .true.
+ lq(ixcldice) = .true.
+ lq(ixnumice) = .true.
+
+ latsub = latvap + latice
+
+ call physics_ptend_init(ptend_loc, state%psetcols, 'iceadj', ls=.true., lq=lq)
+
+ stend(:ncol,:)=0._r8
+ qvtend(:ncol,:)=0._r8
+ qitend(:ncol,:)=0._r8
+ initend(:ncol,:)=0._r8
+
+ call ice_macro_tend(naai(:ncol,top_lev:pver),state%t(:ncol,top_lev:pver), &
+ state%pmid(:ncol,top_lev:pver),state%q(:ncol,top_lev:pver,1),state%q(:ncol,top_lev:pver,ixcldice),&
+ state%q(:ncol,top_lev:pver,ixnumice),latsub,dtime,&
+ stend(:ncol,top_lev:pver),qvtend(:ncol,top_lev:pver),qitend(:ncol,top_lev:pver),&
+ initend(:ncol,top_lev:pver))
+
+ ! update local copy of state with the tendencies
+ ptend_loc%q(:ncol,top_lev:pver,1)=qvtend(:ncol,top_lev:pver)
+ ptend_loc%q(:ncol,top_lev:pver,ixcldice)=qitend(:ncol,top_lev:pver)
+ ptend_loc%q(:ncol,top_lev:pver,ixnumice)=initend(:ncol,top_lev:pver)
+ ptend_loc%s(:ncol,top_lev:pver)=stend(:ncol,top_lev:pver)
+
+ ! Add the ice tendency to the output tendency
+ call physics_ptend_sum(ptend_loc, ptend, ncol)
+
+ ! ptend_loc is reset to zero by this call
+ call physics_update(state_loc, ptend_loc, dtime)
+
+ ! Write output for tendencies:
+ call outfld( 'TTENDICE', stend/cpair, pcols, lchnk )
+ call outfld( 'QVTENDICE', qvtend, pcols, lchnk )
+ call outfld( 'QITENDICE', qitend, pcols, lchnk )
+ call outfld( 'NITENDICE', initend, pcols, lchnk )
+
+ endif
+
! -------------------------------------- !
! Computation of Various Cloud Fractions !
! -------------------------------------- !
@@ -712,6 +848,23 @@ subroutine macrop_driver_tend( &
concld_old(:ncol,top_lev:pver) = concld(:ncol,top_lev:pver)
+ nullify(tke, qtl_flx, qti_flx, cmfr_det, qlr_det, qir_det)
+ if (tke_idx > 0) call pbuf_get_field(pbuf, tke_idx, tke)
+ if (qtl_flx_idx > 0) call pbuf_get_field(pbuf, qtl_flx_idx, qtl_flx)
+ if (qti_flx_idx > 0) call pbuf_get_field(pbuf, qti_flx_idx, qti_flx)
+ if (cmfr_det_idx > 0) call pbuf_get_field(pbuf, cmfr_det_idx, cmfr_det)
+ if (qlr_det_idx > 0) call pbuf_get_field(pbuf, qlr_det_idx, qlr_det)
+ if (qir_det_idx > 0) call pbuf_get_field(pbuf, qir_det_idx, qir_det)
+
+ clrw_old(:ncol,:top_lev-1) = 0._r8
+ clri_old(:ncol,:top_lev-1) = 0._r8
+ do k = top_lev, pver
+ do i = 1, ncol
+ clrw_old(i,k) = max( 0._r8, min( 1._r8, 1._r8 - concld(i,k) - alst(i,k) ) )
+ clri_old(i,k) = max( 0._r8, min( 1._r8, 1._r8 - concld(i,k) - ast(i,k) ) )
+ end do
+ end do
+
if( use_shfrc ) then
call pbuf_get_field(pbuf, shfrc_idx, shfrc )
else
@@ -836,7 +989,8 @@ subroutine macrop_driver_tend( &
ttend, qtend, lmitend, itend, nltend, nitend, &
CC_T, CC_qv, CC_ql, CC_qi, CC_nl, CC_ni, CC_qlst, &
dlf_T, dlf_qv, dlf_ql, dlf_qi, dlf_nl, dlf_ni, &
- concld_old, concld, landfrac, snowh, &
+ concld_old, concld, clrw_old, clri_old, landfrac, snowh, &
+ tke, qtl_flx, qti_flx, cmfr_det, qlr_det, qir_det, &
tlat, qvlat, qcten, qiten, ncten, niten, &
cmeliq, qvadj, qladj, qiadj, qllim, qilim, &
cld, alst, aist, qlst, qist, do_cldice )
@@ -891,6 +1045,8 @@ subroutine macrop_driver_tend( &
! state_loc is the equlibrium state after macrophysics
call physics_update(state_loc, ptend_loc, dtime)
+ call outfld('CLR_LIQ', clrw_old, pcols, lchnk)
+ call outfld('CLR_ICE', clri_old, pcols, lchnk)
call outfld( 'MACPDT ', tlat , pcols, lchnk )
call outfld( 'MACPDQ ', qvlat, pcols, lchnk )
@@ -961,4 +1117,71 @@ subroutine macrop_driver_tend( &
end subroutine macrop_driver_tend
+! Saturation adjustment for ice
+! Add ice mass if supersaturated
+elemental subroutine ice_macro_tend(naai,t,p,qv,qi,ni,xxls,deltat,stend,qvtend,qitend,nitend)
+
+ use wv_sat_methods, only: wv_sat_qsat_ice
+
+ real(r8), intent(in) :: naai !Activated number of ice nuclei
+ real(r8), intent(in) :: t !temperature (k)
+ real(r8), intent(in) :: p !pressure (pa0
+ real(r8), intent(in) :: qv !water vapor mixing ratio
+ real(r8), intent(in) :: qi !ice mixing ratio
+ real(r8), intent(in) :: ni !ice number concentration
+ real(r8), intent(in) :: xxls !latent heat of sublimation
+ real(r8), intent(in) :: deltat !timestep
+ real(r8), intent(out) :: stend ! 'temperature' tendency
+ real(r8), intent(out) :: qvtend !vapor tendency
+ real(r8), intent(out) :: qitend !ice mass tendency
+ real(r8), intent(out) :: nitend !ice number tendency
+
+ real(r8) :: ESI
+ real(r8) :: QSI
+ real(r8) :: tau
+ logical :: tau_constant
+
+ tau_constant = .true.
+
+ stend = 0._r8
+ qvtend = 0._r8
+ qitend = 0._r8
+ nitend = 0._r8
+
+ ! calculate qsati from t,p,q
+
+ call wv_sat_qsat_ice(t, p, ESI, QSI)
+
+ if (naai.gt.1.e-18_r8.and.qv.gt.QSI) then
+
+ !optional timescale on condensation
+ !tau in sections. Try 300. or tau = f(T): 300s t> 268, 1800s for t<238
+ !
+ if (.not. tau_constant) then
+ if( t.gt. 268.15_r8 ) then
+ tau = 300.0_r8
+ elseif(t.lt.238.15_r8 ) then
+ tau = 1800._r8
+ else
+ tau = 300._r8 + (1800._r8 - 300._r8) * ( 268.15_r8 - t ) / 30._r8
+ endif
+ else
+ tau = 300._r8
+ end if
+
+ qitend = (qv-QSI)/deltat !* exp(-tau/deltat)
+ qvtend = 0._r8 - qitend
+ stend = qitend * xxls ! moist static energy tend...[J/kg/s] !
+
+ ! kg(h2o)/kg(air)/s * J/kg(h2o) = J/kg(air)/s (=W/kg)
+ ! if ice exists (more than 1 L-1) and there is condensation, do not add to number (= growth), else, add 10um ice
+
+ if (ni.lt.1.e3_r8.and.(qi+qitend*deltat).gt.1e-18_r8) then
+ nitend = nitend + 3._r8 * qitend/(4._r8*3.14_r8* 10.e-6_r8**3*997._r8)
+ endif
+
+ endif
+
+end subroutine ice_macro_tend
+
end module macrop_driver
diff --git a/models/atm/cam/src/physics/cam/micro_mg1_0.F90 b/models/atm/cam/src/physics/cam/micro_mg1_0.F90
index aac79901922a..efd32b28e053 100644
--- a/models/atm/cam/src/physics/cam/micro_mg1_0.F90
+++ b/models/atm/cam/src/physics/cam/micro_mg1_0.F90
@@ -32,6 +32,7 @@ module micro_mg1_0
!---------------------------------------------------------------------------------
! modification for sub-columns, HM, (orig 8/11/10)
! This is done using the logical 'microp_uniform' set to .true. = uniform for subcolumns
+!---------------------------------------------------------------------------------
! Procedures required:
! 1) An implementation of the gamma function (if not intrinsic).
@@ -48,6 +49,8 @@ module micro_mg1_0
svp_ice => wv_sat_svp_ice, &
svp_to_qsat => wv_sat_svp_to_qsat
+ use phys_control, only: phys_getopts
+
implicit none
private
save
@@ -58,8 +61,9 @@ module micro_mg1_0
! done outside of this module.
public :: &
- micro_mg_init, &
- micro_mg_tend
+ micro_mg_init, &
+ micro_mg_get_cols, &
+ micro_mg_tend
integer, parameter :: r8 = selected_real_kind(12) ! 8 byte real
@@ -84,7 +88,7 @@ module micro_mg1_0
real(r8) :: Eii !collection efficiency aggregation of ice
real(r8) :: Ecr !collection efficiency cloud droplets/rain
real(r8) :: f1r,f2r !ventilation param for rain
-real(r8) :: dcs !autoconversion size threshold for cloud ice to snow (m)
+real(r8) :: DCS !autoconversion size threshold
real(r8) :: qsmall !min mixing ratio
real(r8) :: bimm,aimm !immersion freezing
real(r8) :: rhosu !typical 850mn air density
@@ -130,6 +134,12 @@ module micro_mg1_0
real(r8) :: rhmini ! Minimum rh for ice cloud fraction > 0.
+logical :: use_hetfrz_classnuc ! option to use heterogeneous freezing
+
+character(len=16) :: micro_mg_precip_frac_method ! type of precipitation fraction method
+real(r8) :: micro_mg_berg_eff_factor ! berg efficiency factor
+
+
!===============================================================================
contains
!===============================================================================
@@ -137,7 +147,8 @@ module micro_mg1_0
subroutine micro_mg_init( &
kind, gravit, rair, rh2o, cpair, &
rhoh2o, tmelt_in, latvap, latice, &
- rhmini_in, errstring, dcs_in)
+ rhmini_in, micro_mg_dcs, use_hetfrz_classnuc_in, &
+ micro_mg_precip_frac_method_in, micro_mg_berg_eff_factor_in, errstring)
!-----------------------------------------------------------------------
!
@@ -158,7 +169,11 @@ subroutine micro_mg_init( &
real(r8), intent(in) :: latvap
real(r8), intent(in) :: latice
real(r8), intent(in) :: rhmini_in ! Minimum rh for ice cloud fraction > 0.
-real(r8), intent(in) :: dcs_in !autoconversion size threshold for cloud ice to snow (m)
+real(r8), intent(in) :: micro_mg_dcs
+logical, intent(in) :: use_hetfrz_classnuc_in
+character(len=16),intent(in) :: micro_mg_precip_frac_method_in ! type of precipitation fraction method
+real(r8), intent(in) :: micro_mg_berg_eff_factor_in ! berg efficiency factor
+
character(128), intent(out) :: errstring ! Output status (non-blank for error return)
integer k
@@ -178,12 +193,14 @@ subroutine micro_mg_init( &
!declarations for morrison codes (transforms variable names)
g= gravit !gravity
-r= rair !Dry air Gas constant: note units(phys_constants are in J/K/kmol)
+r= rair !Dry air Gas constant: note units(phys_constants are in J/K/kmol)
rv= rh2o !water vapor gas contstant
-cpp = cpair !specific heat of dry air
+cpp = cpair !specific heat of dry air
rhow = rhoh2o !density of liquid water
tmelt = tmelt_in
rhmini = rhmini_in
+micro_mg_precip_frac_method = micro_mg_precip_frac_method_in
+micro_mg_berg_eff_factor = micro_mg_berg_eff_factor_in
! latent heats
@@ -191,6 +208,9 @@ subroutine micro_mg_init( &
xlf = latice ! latent heat freezing
xxls = xxlv + xlf ! latent heat of sublimation
+! flags
+use_hetfrz_classnuc = use_hetfrz_classnuc_in
+
! parameters for snow/rain fraction for convective clouds
tmax_fsnow = tmelt
@@ -265,7 +285,7 @@ subroutine micro_mg_init( &
! autoconversion size threshold for cloud ice to snow (m)
-dcs = dcs_in
+Dcs = micro_mg_dcs
! smallest mixing ratio considered in microphysics
@@ -313,7 +333,7 @@ subroutine micro_mg_init( &
cons14=gamma(5._r8/2._r8+bs/2._r8)
cons16=gamma(1._r8+bi)
cons17=gamma(4._r8+bi)
-cons22=(4._r8/3._r8*pi*rhow*(25.e-6_r8)**3)
+cons22=(4._r8/3._r8*pi*rhow*(25.e-6_r8)**3)
cons23=dcs**3
cons24=dcs**2
cons25=dcs**bs
@@ -340,7 +360,7 @@ subroutine micro_mg_tend ( &
icecldf, rate1ord_cw2pr_st, naai, npccnin, &
rndst, nacon, tlat, qvlat, qctend, &
qitend, nctend, nitend, effc, effc_fn, &
- effi, prect, preci, nevapr, evapsnow, &
+ effi, prect, preci, nevapr, evapsnow, am_evp_st, &
prain, prodsnow, cmeout, deffi, pgamrad, &
lamcrad, qsout, dsout, rflx, sflx, &
qrout, reff_rain, reff_snow, qcsevap, qisevap, &
@@ -353,8 +373,9 @@ subroutine micro_mg_tend ( &
frefl, csrfl, acsrfl, fcsrfl, rercld, &
ncai, ncal, qrout2, qsout2, nrout2, &
nsout2, drout2, dsout2, freqs, freqr, &
- nfice, do_cldice, tnd_qsnow, &
- tnd_nsnow, re_ice, errstring)
+ nfice, prer_evap, do_cldice, errstring, &
+ tnd_qsnow, tnd_nsnow, re_ice, &
+ frzimm, frzcnt, frzdep)
! input arguments
logical, intent(in) :: microp_uniform ! True = configure uniform for sub-columns False = use w/o sub-columns (standard)
@@ -378,7 +399,7 @@ subroutine micro_mg_tend ( &
real(r8), intent(in) :: cldn(pcols,pver) ! cloud fraction
real(r8), intent(in) :: icecldf(pcols,pver) ! ice cloud fraction
real(r8), intent(in) :: liqcldf(pcols,pver) ! liquid cloud fraction
-
+
real(r8), intent(out) :: rate1ord_cw2pr_st(pcols,pver) ! 1st order rate for direct cw to precip conversion
! used for scavenging
! Inputs for aerosol activation
@@ -390,9 +411,7 @@ subroutine micro_mg_tend ( &
! Used with CARMA cirrus microphysics
! (or similar external microphysics model)
logical, intent(in) :: do_cldice ! Prognosing cldice
-real(r8), intent(in) :: tnd_qsnow(pcols,pver) ! snow mass tendency (kg/kg/s)
-real(r8), intent(in) :: tnd_nsnow(pcols,pver) ! snow number tendency (#/kg/s)
-real(r8), intent(in) :: re_ice(pcols,pver) ! ice effective radius (m)
+
! output arguments
real(r8), intent(out) :: tlat(pcols,pver) ! latent heating rate (W/kg)
@@ -408,6 +427,7 @@ subroutine micro_mg_tend ( &
real(r8), intent(out) :: preci(pcols) ! cloud ice/snow precip rate (m/s)
real(r8), intent(out) :: nevapr(pcols,pver) ! evaporation rate of rain + snow
real(r8), intent(out) :: evapsnow(pcols,pver)! sublimation rate of snow
+real(r8), intent(out) :: am_evp_st(pcols,pver)! stratiform evaporation area
real(r8), intent(out) :: prain(pcols,pver) ! production of rain + snow
real(r8), intent(out) :: prodsnow(pcols,pver)! production of snow
real(r8), intent(out) :: cmeout(pcols,pver) ! evap/sub of cloud
@@ -455,8 +475,8 @@ subroutine micro_mg_tend ( &
real(r8), intent(out) :: arefl(pcols,pver) !average reflectivity will zero points outside valid range
real(r8), intent(out) :: areflz(pcols,pver) !average reflectivity in z.
real(r8), intent(out) :: frefl(pcols,pver)
-real(r8), intent(out) :: csrfl(pcols,pver) !cloudsat reflectivity
-real(r8), intent(out) :: acsrfl(pcols,pver) !cloudsat average
+real(r8), intent(out) :: csrfl(pcols,pver) !cloudsat reflectivity
+real(r8), intent(out) :: acsrfl(pcols,pver) !cloudsat average
real(r8), intent(out) :: fcsrfl(pcols,pver)
real(r8), intent(out) :: rercld(pcols,pver) ! effective radius calculation for rain + cloud
real(r8), intent(out) :: ncai(pcols,pver) ! output number conc of ice nuclei available (1/m3)
@@ -470,9 +490,26 @@ subroutine micro_mg_tend ( &
real(r8), intent(out) :: freqs(pcols,pver)
real(r8), intent(out) :: freqr(pcols,pver)
real(r8), intent(out) :: nfice(pcols,pver)
+real(r8), intent(out) :: prer_evap(pcols,pver)
+
+real(r8) :: nevapr2(pcols,pver)
character(128), intent(out) :: errstring ! Output status (non-blank for error return)
+! Tendencies calculated by external schemes that can replace MG's native
+! process tendencies.
+
+! Used with CARMA cirrus microphysics
+! (or similar external microphysics model)
+real(r8), intent(in), pointer :: tnd_qsnow(:,:) ! snow mass tendency (kg/kg/s)
+real(r8), intent(in), pointer :: tnd_nsnow(:,:) ! snow number tendency (#/kg/s)
+real(r8), intent(in), pointer :: re_ice(:,:) ! ice effective radius (m)
+
+! From external ice nucleation.
+real(r8), intent(in), pointer :: frzimm(:,:) ! Number tendency due to immersion freezing (1/cm3)
+real(r8), intent(in), pointer :: frzcnt(:,:) ! Number tendency due to contact freezing (1/cm3)
+real(r8), intent(in), pointer :: frzdep(:,:) ! Number tendency due to deposition nucleation (1/cm3)
+
! local workspace
! all units mks unless otherwise stated
@@ -607,7 +644,7 @@ subroutine micro_mg_tend ( &
real(r8) :: umr(pver) ! mass-weighted rain fallspeed
real(r8) :: unc ! number-weighted cloud droplet fallspeed
real(r8) :: umc ! mass-weighted cloud droplet fallspeed
-real(r8) :: pracs(pver) ! mixing rat tendency due to collection of rain by snow
+real(r8) :: pracs(pver) ! mixing rat tendency due to collection of rain by snow
real(r8) :: npracs(pver) ! number conc tendency due to collection of rain by snow
real(r8) :: mnuccr(pver) ! mixing rat tendency due to freezing of rain
real(r8) :: nnuccr(pver) ! number conc tendency due to freezing of rain
@@ -727,7 +764,7 @@ subroutine micro_mg_tend ( &
! diagnostic rain/snow for output to history
! values are in-precip (local) !!!!
-real(r8) :: drout(pcols,pver) ! rain diameter (m)
+real(r8) :: drout(pcols,pver) ! rain diameter (m)
!averageed rain/snow for history
real(r8) :: dumfice
@@ -783,11 +820,35 @@ subroutine micro_mg_tend ( &
real(r8), parameter :: cdnl = 0.e6_r8 ! cloud droplet number limiter
+! heterogeneous freezing
+real(r8) :: mnudep(pver) ! mixing ratio tendency due to deposition of water vapor
+real(r8) :: nnudep(pver) ! number conc tendency due to deposition of water vapor
+real(r8) :: con1 ! work cnstant
+real(r8) :: r3lx ! Mean volume radius (m)
+real(r8) :: mi0l
+real(r8) :: frztmp
+
+logical :: do_clubb_sgs
+
!cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
! Return error message
errstring = ' '
+if (.not. (do_cldice .or. &
+ (associated(tnd_qsnow) .and. associated(tnd_nsnow) .and. associated(re_ice)))) then
+ errstring = "MG's native cloud ice processes are disabled, but &
+ &no replacement values were passed in."
+end if
+
+if (use_hetfrz_classnuc .and. (.not. &
+ (associated(frzimm) .and. associated(frzcnt) .and. associated(frzdep)))) then
+ errstring = "Hoose heterogeneous freezing is enabled, but the &
+ &required tendencies were not all passed in."
+end if
+
+call phys_getopts(do_clubb_sgs_out = do_clubb_sgs)
+
! initialize output fields for number conc qand ice nucleation
ncai(1:ncol,1:pver)=0._r8
ncal(1:ncol,1:pver)=0._r8
@@ -838,7 +899,7 @@ subroutine micro_mg_tend ( &
effi(:,:)=0._r8
! assign variable deltat for sub-stepping...
-deltat=deltatin
+deltat=deltatin
! parameters for scheme
@@ -913,11 +974,14 @@ subroutine micro_mg_tend ( &
! initialize variables for trop_mozart
nevapr(1:ncol,1:pver) = 0._r8
+nevapr2(1:ncol,1:pver) = 0._r8
evapsnow(1:ncol,1:pver) = 0._r8
prain(1:ncol,1:pver) = 0._r8
prodsnow(1:ncol,1:pver) = 0._r8
cmeout(1:ncol,1:pver) = 0._r8
+am_evp_st(1:ncol,1:pver) = 0._r8
+
! for refl calc
rainrt1(1:ncol,1:pver) = 0._r8
@@ -1115,7 +1179,8 @@ subroutine micro_mg_tend ( &
if (qiic(i,k).ge.qsmall) then
- ! first case is for case when liquid water is present, but is completely depleted in time step, i.e., bergrsf > 0 but < 1
+ ! first case is for case when liquid water is present, but is completely depleted
+ ! in time step, i.e., bergrsf > 0 but < 1
if (qc(i,k).ge.qsmall) then
rhin = (1.0_r8 + relhum(i,k)) / 2._r8
@@ -1257,7 +1322,7 @@ subroutine micro_mg_tend ( &
rflx(i,k+1)=0._r8
sflx(i,k+1)=0._r8
end do ! i loop
-end do ! k loop
+end do ! k loop
do i=1,ncol
ltrue(i)=0
@@ -1356,15 +1421,15 @@ subroutine micro_mg_tend ( &
do k=top_lev,pver
qcvar=relvar(i,k)
- cons2=gamma(qcvar+2.47_r8)
- cons3=gamma(qcvar)
- cons9=gamma(qcvar+2._r8)
- cons10=gamma(qcvar+1._r8)
- cons12=gamma(qcvar+1.15_r8)
- cons15=gamma(qcvar+bc/3._r8)
- cons18=qcvar**2.47_r8
- cons19=qcvar**2
- cons20=qcvar**1.15_r8
+ cons2=gamma(qcvar+2.47_r8)
+ cons3=gamma(qcvar)
+ cons9=gamma(qcvar+2._r8)
+ cons10=gamma(qcvar+1._r8)
+ cons12=gamma(qcvar+1.15_r8)
+ cons15=gamma(qcvar+bc/3._r8)
+ cons18=qcvar**2.47_r8
+ cons19=qcvar**2
+ cons20=qcvar**1.15_r8
! set cwml and cwmi to current qc and qi
@@ -1389,11 +1454,21 @@ subroutine micro_mg_tend ( &
else
! if rain or snow mix ratio is smaller than
! threshold, then set cldmax to cloud fraction at current level
- if (qric(i,k-1).ge.qsmall.or.qniic(i,k-1).ge.qsmall) then
- cldmax(i,k)=max(cldmax(i,k-1),cldm(i,k))
+
+ if (do_clubb_sgs) then
+ if (qc(i,k).ge.qsmall.or.qi(i,k).ge.qsmall) then
+ cldmax(i,k)=cldm(i,k)
+ else
+ cldmax(i,k)=cldmax(i,k-1)
+ end if
else
- cldmax(i,k)=cldm(i,k)
- end if
+
+ if (qric(i,k-1).ge.qsmall.or.qniic(i,k-1).ge.qsmall) then
+ cldmax(i,k)=max(cldmax(i,k-1),cldm(i,k))
+ else
+ cldmax(i,k)=cldm(i,k)
+ end if
+ endif
end if
! decrease in number concentration due to sublimation/evap
@@ -1793,101 +1868,131 @@ subroutine micro_mg_tend ( &
! heterogeneous freezing of cloud water
- if (do_cldice .and. qcic(i,k).ge.qsmall .and. t(i,k).lt.269.15_r8) then
+ if (.not. use_hetfrz_classnuc) then
- ! immersion freezing (Bigg, 1953)
+ if (do_cldice .and. qcic(i,k).ge.qsmall .and. t(i,k).lt.269.15_r8) then
+ ! immersion freezing (Bigg, 1953)
- ! subcolumns
- if (microp_uniform) then
+ ! subcolumns
- mnuccc(k) = &
- pi*pi/36._r8*rhow* &
- cdist1(k)*gamma(7._r8+pgam(k))* &
- bimm*(exp(aimm*(273.15_r8-t(i,k)))-1._r8)/ &
- lamc(k)**3/lamc(k)**3
+ if (microp_uniform) then
- nnuccc(k) = &
- pi/6._r8*cdist1(k)*gamma(pgam(k)+4._r8) &
- *bimm* &
- (exp(aimm*(273.15_r8-t(i,k)))-1._r8)/lamc(k)**3
+ mnuccc(k) = &
+ pi*pi/36._r8*rhow* &
+ cdist1(k)*gamma(7._r8+pgam(k))* &
+ bimm*(exp(aimm*(273.15_r8-t(i,k)))-1._r8)/ &
+ lamc(k)**3/lamc(k)**3
- else
+ nnuccc(k) = &
+ pi/6._r8*cdist1(k)*gamma(pgam(k)+4._r8) &
+ *bimm* &
+ (exp(aimm*(273.15_r8-t(i,k)))-1._r8)/lamc(k)**3
- mnuccc(k) = cons9/(cons3*cons19)* &
- pi*pi/36._r8*rhow* &
- cdist1(k)*gamma(7._r8+pgam(k))* &
- bimm*(exp(aimm*(273.15_r8-t(i,k)))-1._r8)/ &
- lamc(k)**3/lamc(k)**3
+ else
- nnuccc(k) = cons10/(cons3*qcvar)* &
- pi/6._r8*cdist1(k)*gamma(pgam(k)+4._r8) &
- *bimm* &
- (exp(aimm*(273.15_r8-t(i,k)))-1._r8)/lamc(k)**3
- end if ! sub-columns
+ mnuccc(k) = cons9/(cons3*cons19)* &
+ pi*pi/36._r8*rhow* &
+ cdist1(k)*gamma(7._r8+pgam(k))* &
+ bimm*(exp(aimm*(273.15_r8-t(i,k)))-1._r8)/ &
+ lamc(k)**3/lamc(k)**3
+ nnuccc(k) = cons10/(cons3*qcvar)* &
+ pi/6._r8*cdist1(k)*gamma(pgam(k)+4._r8) &
+ *bimm* &
+ (exp(aimm*(273.15_r8-t(i,k)))-1._r8)/lamc(k)**3
+ end if ! sub-columns
- ! contact freezing (-40= qsmall) then
+ con1 = 1._r8/(1.333_r8*pi)**0.333_r8
+ r3lx = con1*(rho(i,k)*qcic(i,k)/(rhow*max(ncic(i,k)*rho(i,k), 1.0e6_r8)))**0.333_r8 ! in m
+ r3lx = max(4.e-6_r8, r3lx)
+ mi0l = 4._r8/3._r8*pi*rhow*r3lx**3_r8
+
+ nnuccc(k) = frzimm(i,k)*1.0e6_r8/rho(i,k)
+ mnuccc(k) = nnuccc(k)*mi0l
+
+ nnucct(k) = frzcnt(i,k)*1.0e6_r8/rho(i,k)
+ mnucct(k) = nnucct(k)*mi0l
+
+ nnudep(k) = frzdep(i,k)*1.0e6_r8/rho(i,k)
+ mnudep(k) = nnudep(k)*mi0
+ else
+ nnuccc(k) = 0._r8
+ mnuccc(k) = 0._r8
+
+ nnucct(k) = 0._r8
+ mnucct(k) = 0._r8
+
+ nnudep(k) = 0._r8
+ mnudep(k) = 0._r8
+ end if
+ endif
+
!.......................................................................
! snow self-aggregation from passarelli, 1978, used by reisner, 1998
@@ -1935,7 +2040,7 @@ subroutine micro_mg_tend ( &
psacws(k) = pi/4._r8*asn(i,k)*qcic(i,k)*rho(i,k)* &
n0s(k)*Eci*cons11/ &
- lams(k)**(bs+3._r8)
+ lams(k)**(bs+3._r8)
npsacws(k) = pi/4._r8*asn(i,k)*ncic(i,k)*rho(i,k)* &
n0s(k)*Eci*cons11/ &
lams(k)**(bs+3._r8)
@@ -2056,7 +2161,7 @@ subroutine micro_mg_tend ( &
prai(k) = pi/4._r8*asn(i,k)*qiic(i,k)*rho(i,k)* &
n0s(k)*Eii*cons11/ &
- lams(k)**(bs+3._r8)
+ lams(k)**(bs+3._r8)
nprai(k) = pi/4._r8*asn(i,k)*niic(i,k)* &
rho(i,k)*n0s(k)*Eii*cons11/ &
lams(k)**(bs+3._r8)
@@ -2119,6 +2224,7 @@ subroutine micro_mg_tend ( &
! and distribute across cldmax
pre(k)=min(pre(k)*(cldmax(i,k)-dum),0._r8)
pre(k)=pre(k)/cldmax(i,k)
+ am_evp_st(i,k) = max(cldmax(i,k)-dum, 0._r8)
end if
! sublimation of snow
@@ -2131,11 +2237,12 @@ subroutine micro_mg_tend ( &
f2s*(asn(i,k)*rho(i,k)/mu(i,k))**0.5_r8* &
sc(i,k)**(1._r8/3._r8)*cons14/ &
(lams(k)**(5._r8/2._r8+bs/2._r8)))
- prds(k) = epss*(qclr-qvi)/abi
+ prds(k) = epss*(qclr-qvi)/abi
! only sublimate in out-of-cloud region and distribute over cldmax
prds(k)=min(prds(k)*(cldmax(i,k)-dum),0._r8)
prds(k)=prds(k)/cldmax(i,k)
+ am_evp_st(i,k) = max(cldmax(i,k)-dum, 0._r8)
end if
! make sure RH not pushed above 100% due to rain evaporation/snow sublimation
@@ -2225,8 +2332,8 @@ subroutine micro_mg_tend ( &
mnuccc(k) = mnuccc(k)*ratio
mnucct(k) = mnucct(k)*ratio
msacwi(k) = msacwi(k)*ratio
- psacws(k) = psacws(k)*ratio
- bergs(k) = bergs(k)*ratio
+ psacws(k) = psacws(k)*ratio
+ bergs(k) = bergs(k)*ratio
end if
! conservation of nc
@@ -2242,32 +2349,38 @@ subroutine micro_mg_tend ( &
npra(k) = npra(k)*ratio
nnuccc(k) = nnuccc(k)*ratio
nnucct(k) = nnucct(k)*ratio
- npsacws(k) = npsacws(k)*ratio
+ npsacws(k) = npsacws(k)*ratio
nsubc(k)=nsubc(k)*ratio
end if
! conservation of qi
if (do_cldice) then
- dum = ((-mnuccc(k)-mnucct(k)-msacwi(k))*lcldm(i,k)+(prci(k)+ &
- prai(k))*icldm(i,k))*deltat
+
+ frztmp = -mnuccc(k) - mnucct(k) - msacwi(k)
+ if (use_hetfrz_classnuc) frztmp = -mnuccc(k)-mnucct(k)-mnudep(k)-msacwi(k)
+ dum = ( frztmp*lcldm(i,k) + (prci(k)+prai(k))*icldm(i,k) )*deltat
if (dum.gt.qie) then
- ratio = (qie/deltat+(mnuccc(k)+mnucct(k)+msacwi(k))*lcldm(i,k))/((prci(k)+prai(k))*icldm(i,k))*omsm
+ frztmp = mnuccc(k) + mnucct(k) + msacwi(k)
+ if (use_hetfrz_classnuc) frztmp = mnuccc(k) + mnucct(k) + mnudep(k) + msacwi(k)
+ ratio = (qie/deltat + frztmp*lcldm(i,k))/((prci(k)+prai(k))*icldm(i,k))*omsm
prci(k) = prci(k)*ratio
prai(k) = prai(k)*ratio
end if
! conservation of ni
-
- dum = ((-nnucct(k)-nsacwi(k))*lcldm(i,k)+(nprci(k)+ &
- nprai(k)-nsubi(k))*icldm(i,k))*deltat
+ frztmp = -nnucct(k) - nsacwi(k)
+ if (use_hetfrz_classnuc) frztmp = -nnucct(k) - nnuccc(k) - nnudep(k) - nsacwi(k)
+ dum = ( frztmp*lcldm(i,k) + (nprci(k)+nprai(k)-nsubi(k))*icldm(i,k) )*deltat
if (dum.gt.nie) then
- ratio = (nie/deltat+(nnucct(k)+nsacwi(k))*lcldm(i,k))/ &
- ((nprci(k)+nprai(k)-nsubi(k))*icldm(i,k))*omsm
+ frztmp = nnucct(k) + nsacwi(k)
+ if (use_hetfrz_classnuc) frztmp = nnucct(k) + nnuccc(k) + nnudep(k) + nsacwi(k)
+ ratio = (nie/deltat + frztmp*lcldm(i,k))/ &
+ ((nprci(k)+nprai(k)-nsubi(k))*icldm(i,k))*omsm
nprci(k) = nprci(k)*ratio
nprai(k) = nprai(k)*ratio
nsubi(k) = nsubi(k)*ratio
@@ -2362,9 +2475,12 @@ subroutine micro_mg_tend ( &
psacws(k)-bergs(k))*lcldm(i,k)-berg(i,k)
if (do_cldice) then
- qitend(i,k) = qitend(i,k)+ &
- (mnuccc(k)+mnucct(k)+msacwi(k))*lcldm(i,k)+(-prci(k)- &
- prai(k))*icldm(i,k)+cmei(i,k)+berg(i,k)
+
+ frztmp = mnuccc(k) + mnucct(k) + msacwi(k)
+ if (use_hetfrz_classnuc) frztmp = mnuccc(k) + mnucct(k) + mnudep(k) + msacwi(k)
+ qitend(i,k) = qitend(i,k) + frztmp*lcldm(i,k) + &
+ (-prci(k)-prai(k))*icldm(i,k) + cmei(i,k) + berg(i,k)
+
end if
qrtend(i,k) = qrtend(i,k)+ &
@@ -2383,6 +2499,7 @@ subroutine micro_mg_tend ( &
evapsnow(i,k) = evapsnow(i,k)-prds(k)*cldmax(i,k)
nevapr(i,k) = nevapr(i,k)-pre(k)*cldmax(i,k)
+ nevapr2(i,k) = nevapr2(i,k)-pre(k)*cldmax(i,k)
! change to make sure prain is positive: do not remove snow from
! prain used for wet deposition
@@ -2424,9 +2541,12 @@ subroutine micro_mg_tend ( &
-npra(k)-nprc1(k))*lcldm(i,k)
if (do_cldice) then
- nitend(i,k) = nitend(i,k)+ nnuccd(k)*mtime+ &
- (nnucct(k)+nsacwi(k))*lcldm(i,k)+(nsubi(k)-nprci(k)- &
- nprai(k))*icldm(i,k)
+
+ frztmp = nnucct(k) + nsacwi(k)
+ if (use_hetfrz_classnuc) frztmp = nnucct(k) + nnuccc(k) + nnudep(k) + nsacwi(k)
+ nitend(i,k) = nitend(i,k) + nnuccd(k)*mtime + &
+ frztmp*lcldm(i,k) + (nsubi(k)-nprci(k)-nprai(k))*icldm(i,k)
+
end if
nstend(i,k) = nstend(i,k)+(nsubs(k)+ &
@@ -2474,7 +2594,7 @@ subroutine micro_mg_tend ( &
if (qniic(i,k).ge.qsmall) then
if (k.eq.top_lev) then
- qniic(i,k)=qnitend(i,k)*dz(i,k)/cldmax(i,k)/ums(k)
+ qniic(i,k)=qnitend(i,k)*dz(i,k)/cldmax(i,k)/ums(k)
nsic(i,k)=nstend(i,k)*dz(i,k)/cldmax(i,k)/uns(k)
else
qniic(i,k) = (rho(i,k-1)*ums(k-1)*qniic(i,k-1)*cldmax(i,k-1)+ &
@@ -2820,6 +2940,7 @@ subroutine micro_mg_tend ( &
! divide trop_mozart variables by number of sub-steps to get average over time step
nevapr(i,k) = nevapr(i,k)/real(iter)
+ nevapr2(i,k) = nevapr2(i,k)/real(iter)
evapsnow(i,k) = evapsnow(i,k)/real(iter)
prain(i,k) = prain(i,k)/real(iter)
prodsnow(i,k) = prodsnow(i,k)/real(iter)
@@ -2849,6 +2970,7 @@ subroutine micro_mg_tend ( &
! modify to include snow. in prain & evap (diagnostic here: for wet dep)
nevapr(i,k) = nevapr(i,k) + evapsnow(i,k)
+ prer_evap(i,k) = nevapr2(i,k)
prain(i,k) = prain(i,k) + prodsnow(i,k)
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
@@ -2950,7 +3072,7 @@ subroutine micro_mg_tend ( &
if (dumi(i,k).lt.qsmall) dumni(i,k)=0._r8
end do !!! vertical loop
- do n = 1,nstep !! loop over sub-time step to ensure stability
+ do n = 1,nstep !! loop over sub-time step to ensure stability
do k = top_lev,pver
if (do_cldice) then
@@ -3059,7 +3181,7 @@ subroutine micro_mg_tend ( &
! get new update for variables that includes sedimentation tendency
! note : here dum variables are grid-average, NOT in-cloud
- do k=top_lev,pver
+ do k=top_lev,pver
dumc(i,k) = max(qc(i,k)+qctend(i,k)*deltat,0._r8)
dumi(i,k) = max(qi(i,k)+qitend(i,k)*deltat,0._r8)
@@ -3409,7 +3531,7 @@ subroutine micro_mg_tend ( &
if (refl(i,k).gt.minrefl) then
refl(i,k)=10._r8*log10(refl(i,k))
- else
+ else
refl(i,k)=-9999._r8
end if
@@ -3445,9 +3567,9 @@ subroutine micro_mg_tend ( &
qrout2(:,:)=0._r8
qsout2(:,:)=0._r8
nrout2(:,:)=0._r8
-nsout2(:,:)=0._r8
+nsout2(:,:)=0._r8
drout2(:,:)=0._r8
-dsout2(:,:)=0._r8
+dsout2(:,:)=0._r8
freqs(:,:)=0._r8
freqr(:,:)=0._r8
do i = 1,ncol
@@ -3498,4 +3620,58 @@ subroutine micro_mg_tend ( &
end subroutine micro_mg_tend
+!========================================================================
+!UTILITIES
+!========================================================================
+
+pure subroutine micro_mg_get_cols(ncol, nlev, top_lev, qcn, qin, &
+ mgncol, mgcols)
+
+ ! Determines which columns microphysics should operate over by
+ ! checking for non-zero cloud water/ice.
+
+ integer, intent(in) :: ncol ! Number of columns with meaningful data
+ integer, intent(in) :: nlev ! Number of levels to use
+ integer, intent(in) :: top_lev ! Top level for microphysics
+
+ real(r8), intent(in) :: qcn(:,:) ! cloud water mixing ratio (kg/kg)
+ real(r8), intent(in) :: qin(:,:) ! cloud ice mixing ratio (kg/kg)
+
+ integer, intent(out) :: mgncol ! Number of columns MG will use
+ integer, allocatable, intent(out) :: mgcols(:) ! column indices
+
+ integer :: lev_offset ! top_lev - 1 (defined here for consistency)
+ logical :: ltrue(ncol) ! store tests for each column
+
+ integer :: i, ii ! column indices
+
+ if (allocated(mgcols)) deallocate(mgcols)
+
+ lev_offset = top_lev - 1
+
+ ! Using "any" along dimension 2 collapses across levels, but
+ ! not columns, so we know if water is present at any level
+ ! in each column.
+
+ ltrue = any(qcn(:ncol,top_lev:(nlev+lev_offset)) >= qsmall, 2)
+ ltrue = ltrue .or. any(qin(:ncol,top_lev:(nlev+lev_offset)) >= qsmall, 2)
+
+#if ! defined(CLUBB_BFB_S2) && ! defined(CLUBB_BFB_ALL)
+ ltrue = .true. ! Effectively still to pass all columns to MG1, as in default model
+#endif
+
+ ! Scan for true values to get a usable list of indices.
+
+ mgncol = count(ltrue)
+ allocate(mgcols(mgncol))
+ i = 0
+ do ii = 1,ncol
+ if (ltrue(ii)) then
+ i = i + 1
+ mgcols(i) = ii
+ end if
+ end do
+
+end subroutine micro_mg_get_cols
+
end module micro_mg1_0
diff --git a/models/atm/cam/src/physics/cam/micro_mg1_5.F90 b/models/atm/cam/src/physics/cam/micro_mg1_5.F90
index fa16d0bd7b73..d3cb06b39453 100644
--- a/models/atm/cam/src/physics/cam/micro_mg1_5.F90
+++ b/models/atm/cam/src/physics/cam/micro_mg1_5.F90
@@ -9,7 +9,7 @@ module micro_mg1_5
! Contributions from: Peter Caldwell, Xiaohong Liu and Steve Ghan
! Version 2: Development begun: September 2011
! invoked in CAM by specifying -microphys=mg1.5
-!
+!
! for questions contact Hugh Morrison, Andrew Gettelman
! e-mail: morrison@ucar.edu, andrew@ucar.edu
!
@@ -47,6 +47,8 @@ module micro_mg1_5
! subroutine micro_mg_init --> initializes microphysics routine, should be called
! once at start of simulation
! subroutine micro_mg_tend --> main microphysics routine to be called each time step
+! this also calls several smaller subroutines to calculate
+! microphysical processes and other utilities
!
! List of external functions:
! qsat_water --> for calculating saturation vapor pressure with respect to liquid water
@@ -100,14 +102,13 @@ module micro_mg1_5
! note: number will be adjusted as needed to keep mean size within bounds,
! even when specified droplet or ice number is used
-! ***note: Even if constant cloud ice number is set, ice number is allowed
-! to evolve based on process rates. This is needed in order to calculate
-! the change in mass due to ice nucleation. All other ice microphysical
-! processes are consistent with the specified constant ice number if
-! this switch is turned on.
+! If constant cloud ice number is set (nicons = .true.),
+! then all microphysical processes except mass transfer due to ice nucleation
+! (mnuccd) are based on the fixed cloud ice number. Calculation of
+! mnuccd follows from the prognosed ice crystal number ni.
! nccons = .true. to specify constant cloud droplet number
-! cicons = .true. to specify constant cloud ice number
+! nicons = .true. to specify constant cloud ice number
logical, parameter, public :: nccons = .false.
logical, parameter, public :: nicons = .false.
@@ -167,10 +168,10 @@ module micro_mg1_5
real(r8), parameter :: eii = 0.1_r8
! autoconversion size threshold for cloud ice to snow (m)
-!real(r8), parameter :: dcs = 250.e-6_r8
+real(r8) :: dcs
! smallest mixing ratio considered in microphysics
-real(r8), parameter :: qsmall = 1.e-18_r8
+real(r8), parameter :: qsmall = 1.e-18_r8
! alternate threshold used for some in-cloud mmr
real(r8), parameter :: icsmall = 1.e-8_r8
@@ -180,7 +181,11 @@ module micro_mg1_5
real(r8), parameter :: aimm = 0.66_r8
! mass of new crystal due to aerosol freezing and growth (kg)
-real(r8), parameter :: mi0 = 4._r8/3._r8*pi*rhoi*(10.e-6_r8)*(10.e-6_r8)*(10.e-6_r8)
+real(r8), parameter :: mi0 = 4._r8/3._r8*pi*rhoi*(10.e-6_r8)**3
+
+! minimum mass of new crystal due to freezing of cloud droplets done
+! externally (kg)
+real(r8), parameter :: mi0l_min = 4._r8/3._r8*pi*rhow*(4.e-6_r8)**3
!Range of cloudsat reflectivities (dBz) for analytic simulator
real(r8), parameter :: csmin = -30._r8
@@ -192,9 +197,6 @@ module micro_mg1_5
! Constants set in initialization
!=========================================================
-! autoconversion size threshold for cloud ice to snow (m)
-real(r8) :: dcs
-
! Set using arguments to micro_mg_init
real(r8) :: g ! gravity
real(r8) :: r ! dry air gas constant
@@ -212,6 +214,7 @@ module micro_mg1_5
! flags
logical :: microp_uniform
logical :: do_cldice
+logical :: use_hetfrz_classnuc
real(r8) :: rhosu ! typical 850mn air density
@@ -238,19 +241,9 @@ module micro_mg1_5
real(r8) :: cons27
real(r8) :: cons28
-! Generic interface for packing routines
-interface pack_array
- module procedure pack_array_1Dr8
- module procedure pack_array_2Dr8
- module procedure pack_array_3Dr8
-end interface
+character(len=16) :: micro_mg_precip_frac_method ! type of precipitation fraction method
+real(r8) :: micro_mg_berg_eff_factor ! berg efficiency factor
-interface unpack_array
- module procedure unpack_array_1Dr8
- module procedure unpack_array_1Dr8_arrayfill
- module procedure unpack_array_2Dr8
- module procedure unpack_array_2Dr8_arrayfill
-end interface
!===============================================================================
contains
@@ -259,18 +252,18 @@ module micro_mg1_5
subroutine micro_mg_init( &
kind, gravit, rair, rh2o, cpair, &
tmelt_in, latvap, latice, &
- rhmini_in, microp_uniform_in, do_cldice_in, &
- errstring, dcs_in)
-
- !-----------------------------------------------------------------------
- !
- ! Purpose:
+ rhmini_in, micro_mg_dcs, microp_uniform_in, do_cldice_in, use_hetfrz_classnuc_in, &
+ micro_mg_precip_frac_method_in, micro_mg_berg_eff_factor_in, errstring)
+
+ !-----------------------------------------------------------------------
+ !
+ ! Purpose:
! initialize constants for MG microphysics
- !
+ !
! Author: Andrew Gettelman Dec 2005
- !
+ !
!-----------------------------------------------------------------------
-
+
integer, intent(in) :: kind ! Kind used for reals
real(r8), intent(in) :: gravit
real(r8), intent(in) :: rair
@@ -280,18 +273,26 @@ subroutine micro_mg_init( &
real(r8), intent(in) :: latvap
real(r8), intent(in) :: latice
real(r8), intent(in) :: rhmini_in ! Minimum rh for ice cloud fraction > 0.
+ real(r8), intent(in) :: micro_mg_dcs
- logical, intent(in) :: microp_uniform_in ! .true. = configure uniform for sub-columns
+ logical, intent(in) :: microp_uniform_in ! .true. = configure for sub-columns
! .false. = use w/o sub-columns (standard)
logical, intent(in) :: do_cldice_in ! .true. = do all processes (standard)
! .false. = skip all processes affecting
! cloud ice
- real(r8), intent(in) :: dcs_in !autoconversion size threshold for cloud ice to snow (m)
+ logical, intent(in) :: use_hetfrz_classnuc_in ! use heterogeneous freezing
+
+ character(len=16),intent(in) :: micro_mg_precip_frac_method_in ! type of precipitation fraction method
+ real(r8), intent(in) :: micro_mg_berg_eff_factor_in ! berg efficiency factor
+
character(128), intent(out) :: errstring ! Output status (non-blank for error return)
+
!-----------------------------------------------------------------------
+ dcs = micro_mg_dcs
+
errstring = ' '
if( kind .ne. r8 ) then
@@ -307,6 +308,9 @@ subroutine micro_mg_init( &
cpp = cpair ! specific heat of dry air
tmelt = tmelt_in
rhmini = rhmini_in
+ micro_mg_precip_frac_method = micro_mg_precip_frac_method_in
+ micro_mg_berg_eff_factor = micro_mg_berg_eff_factor_in
+
! latent heats
@@ -317,6 +321,7 @@ subroutine micro_mg_init( &
! flags
microp_uniform = microp_uniform_in
do_cldice = do_cldice_in
+ use_hetfrz_classnuc = use_hetfrz_classnuc_in
! typical air density at 850 mb
@@ -330,15 +335,13 @@ subroutine micro_mg_init( &
! Ice nucleation temperature
icenuct = tmelt - 5._r8
- dcs = dcs_in
-
! Define constants to help speed up code (this limits calls to gamma function)
! Unused names: cons6, cons15, cons21, cons26
cons1=gamma(1._r8+dsph)
cons4=gamma(1._r8+br)
cons5=gamma(4._r8+br)
- cons7=gamma(1._r8+bs)
- cons8=gamma(4._r8+bs)
+ cons7=gamma(1._r8+bs)
+ cons8=gamma(4._r8+bs)
cons11=gamma(3._r8+bs)
cons13=gamma(5._r8/2._r8+br/2._r8)
cons14=gamma(5._r8/2._r8+bs/2._r8)
@@ -357,52 +360,52 @@ end subroutine micro_mg_init
!microphysics routine for each timestep goes here...
subroutine micro_mg_tend ( &
- mgncol, mgcols, nlev, top_lev, deltatin, &
- tn, qn, &
+ mgncol, nlev, deltatin, &
+ t, q, &
qcn, qin, &
ncn, nin, &
- relvarn, accre_enhann, &
- pn, pdeln, pint, &
+ relvar, accre_enhan, &
+ p, pdel, pint, &
cldn, liqcldf, icecldf, &
- rate1ord_cw2pr_st, naain, npccnin, rndstn, naconin, &
- tlato, qvlato, qctendo, qitendo, nctendo, nitendo, &
- effco, effco_fn, effio, precto, precio, &
- nevapro, evapsnowo, praino, prodsnowo, cmeouto, deffio, &
- pgamrado, lamcrado, qsouto, dsouto, rflxo, sflxo, &
- qrouto, reff_raino, reff_snowo, &
- qcsevapo, qisevapo, qvreso, cmeiout, vtrmco, vtrmio, &
- qcsedteno,qisedteno,prao, prco, mnuccco, mnuccto, &
- msacwio, psacwso, bergso, bergo, melto, homoo, &
- qcreso, prcio, praio, qireso, &
- mnuccro, pracso, meltsdto, frzrdto, mnuccdo, &
- nrouto, nsouto, reflo, areflo, areflzo, freflo, &
- csrflo, acsrflo, fcsrflo, rercldo, &
- ncaio, ncalo, qrouto2, qsouto2, nrouto2, nsouto2, &
- drouto2, dsouto2, freqso, freqro, nficeo, &
- tnd_qsnown, tnd_nsnown, re_icen, &
- errstring)
+ qcsinksum_rate1ord, naai, npccn, rndst, nacon, &
+ tlat, qvlat, qctend, qitend, nctend, nitend, &
+ effc, effc_fn, effi, prect, preci, &
+ nevapr, evapsnow, prain, prodsnow, cmeout, deffi, &
+ pgamrad, lamcrad, qsout, dsout, rflx, sflx, &
+ qrout, reff_rain, reff_snow, &
+ qcsevap, qisevap, qvres, cmeitot, vtrmc, vtrmi, &
+ qcsedten,qisedten,pratot, prctot, mnuccctot, mnuccttot, &
+ msacwitot, psacwstot, bergstot, bergtot, melttot, homotot, &
+ qcrestot, prcitot, praitot, qirestot, &
+ mnuccrtot, pracstot, meltsdttot, frzrdttot, mnuccdtot, &
+ nrout, nsout, refl, arefl, areflz, frefl, &
+ csrfl, acsrfl, fcsrfl, rercld, &
+ ncai, ncal, qrout2, qsout2, nrout2, nsout2, &
+ drout2, dsout2, freqs, freqr, nfice, qcrat, &
+ errstring, &
+ tnd_qsnow, tnd_nsnow, re_ice, &
+ prer_evap, &
+ frzimm, frzcnt, frzdep)
!Authors: Hugh Morrison, Andrew Gettelman, NCAR, Peter Caldwell, LLNL
! e-mail: morrison@ucar.edu, andrew@ucar.edu
! input arguments
integer, intent(in) :: mgncol ! number of microphysics columns
- integer, intent(in) :: mgcols(:) ! list of microphysics columns
integer, intent(in) :: nlev ! number of layers
- integer, intent(in) :: top_lev ! top level to do microphysics
real(r8), intent(in) :: deltatin ! time step (s)
- real(r8), intent(in) :: tn(:,:) ! input temperature (K)
- real(r8), intent(in) :: qn(:,:) ! input h20 vapor mixing ratio (kg/kg)
- real(r8), intent(in) :: relvarn(:,:) ! relative variance of cloud water (-)
- real(r8), intent(in) :: accre_enhann(:,:) ! optional accretion enhancement factor (-)
+ real(r8), intent(in) :: t(:,:) ! input temperature (K)
+ real(r8), intent(in) :: q(:,:) ! input h20 vapor mixing ratio (kg/kg)
+ real(r8), intent(in) :: relvar(:,:) ! relative variance of cloud water (-)
+ real(r8), intent(in) :: accre_enhan(:,:) ! optional accretion enhancement factor (-)
! note: all input cloud variables are grid-averaged
real(r8), intent(in) :: qcn(:,:) ! cloud water mixing ratio (kg/kg)
real(r8), intent(in) :: qin(:,:) ! cloud ice mixing ratio (kg/kg)
real(r8), intent(in) :: ncn(:,:) ! cloud water number conc (1/kg)
real(r8), intent(in) :: nin(:,:) ! cloud ice number conc (1/kg)
- real(r8), intent(in) :: pn(:,:) ! air pressure (pa)
- real(r8), intent(in) :: pdeln(:,:) ! pressure difference across level (pa)
+ real(r8), intent(in) :: p(:,:) ! air pressure (pa)
+ real(r8), intent(in) :: pdel(:,:) ! pressure difference across level (pa)
! hm add 11-16-11, interface pressure
real(r8), intent(in) :: pint(:,:) ! level interface pressure (pa)
real(r8), intent(in) :: cldn(:,:) ! cloud fraction (no units)
@@ -410,103 +413,113 @@ subroutine micro_mg_tend ( &
real(r8), intent(in) :: icecldf(:,:) ! ice cloud fraction (no units)
! used for scavenging
! Inputs for aerosol activation
- real(r8), intent(in) :: naain(:,:) ! ice nucleation number (from microp_aero_ts) (1/kg)
- real(r8), intent(in) :: npccnin(:,:) ! ccn activated number tendency (from microp_aero_ts) (1/kg*s)
+ real(r8), intent(in) :: naai(:,:) ! ice nucleation number (from microp_aero_ts) (1/kg)
+ real(r8), intent(in) :: npccn(:,:) ! ccn activated number tendency (from microp_aero_ts) (1/kg*s)
! Note that for these variables, the dust bin is assumed to be the last index.
! (For example, in CAM, the last dimension is always size 4.)
- real(r8), intent(in) :: rndstn(:,:,:) ! radius of each dust bin, for contact freezing (from microp_aero_ts) (m)
- real(r8), intent(in) :: naconin(:,:,:) ! number in each dust bin, for contact freezing (from microp_aero_ts) (1/m^3)
-
- ! Used with CARMA cirrus microphysics
- ! (or similar external microphysics model)
- real(r8), intent(in) :: tnd_qsnown(:,:) ! snow mass tendency (kg/kg/s)
- real(r8), intent(in) :: tnd_nsnown(:,:) ! snow number tendency (#/kg/s)
- real(r8), intent(in) :: re_icen(:,:) ! ice effective radius (m)
+ real(r8), intent(in) :: rndst(:,:,:) ! radius of each dust bin, for contact freezing (from microp_aero_ts) (m)
+ real(r8), intent(in) :: nacon(:,:,:) ! number in each dust bin, for contact freezing (from microp_aero_ts) (1/m^3)
! output arguments
- real(r8), intent(out) :: rate1ord_cw2pr_st(:,:) ! 1st order rate for
+ real(r8), intent(out) :: qcsinksum_rate1ord(:,:) ! 1st order rate for
! direct cw to precip conversion
- real(r8), intent(out) :: tlato(:,:) ! latent heating rate (W/kg)
- real(r8), intent(out) :: qvlato(:,:) ! microphysical tendency qv (1/s)
- real(r8), intent(out) :: qctendo(:,:) ! microphysical tendency qc (1/s)
- real(r8), intent(out) :: qitendo(:,:) ! microphysical tendency qi (1/s)
- real(r8), intent(out) :: nctendo(:,:) ! microphysical tendency nc (1/(kg*s))
- real(r8), intent(out) :: nitendo(:,:) ! microphysical tendency ni (1/(kg*s))
- real(r8), intent(out) :: effco(:,:) ! droplet effective radius (micron)
- real(r8), intent(out) :: effco_fn(:,:) ! droplet effective radius, assuming nc = 1.e8 kg-1
- real(r8), intent(out) :: effio(:,:) ! cloud ice effective radius (micron)
- real(r8), intent(out) :: precto(:) ! surface precip rate (m/s)
- real(r8), intent(out) :: precio(:) ! cloud ice/snow precip rate (m/s)
- real(r8), intent(out) :: nevapro(:,:) ! evaporation rate of rain + snow (1/s)
- real(r8), intent(out) :: evapsnowo(:,:) ! sublimation rate of snow (1/s)
- real(r8), intent(out) :: praino(:,:) ! production of rain + snow (1/s)
- real(r8), intent(out) :: prodsnowo(:,:) ! production of snow (1/s)
- real(r8), intent(out) :: cmeouto(:,:) ! evap/sub of cloud (1/s)
- real(r8), intent(out) :: deffio(:,:) ! ice effective diameter for optics (radiation) (micron)
- real(r8), intent(out) :: pgamrado(:,:) ! ice gamma parameter for optics (radiation) (no units)
- real(r8), intent(out) :: lamcrado(:,:) ! slope of droplet distribution for optics (radiation) (1/m)
- real(r8), intent(out) :: qsouto(:,:) ! snow mixing ratio (kg/kg)
- real(r8), intent(out) :: dsouto(:,:) ! snow diameter (m)
- real(r8), intent(out) :: rflxo(:,:) ! grid-box average rain flux (kg m^-2 s^-1)
- real(r8), intent(out) :: sflxo(:,:) ! grid-box average snow flux (kg m^-2 s^-1)
- real(r8), intent(out) :: qrouto(:,:) ! grid-box average rain mixing ratio (kg/kg)
- real(r8), intent(out) :: reff_raino(:,:) ! rain effective radius (micron)
- real(r8), intent(out) :: reff_snowo(:,:) ! snow effective radius (micron)
- real(r8), intent(out) :: qcsevapo(:,:) ! cloud water evaporation due to sedimentation (1/s)
- real(r8), intent(out) :: qisevapo(:,:) ! cloud ice sublimation due to sublimation (1/s)
- real(r8), intent(out) :: qvreso(:,:) ! residual condensation term to ensure RH < 100% (1/s)
- real(r8), intent(out) :: cmeiout(:,:) ! grid-mean cloud ice sub/dep (1/s)
- real(r8), intent(out) :: vtrmco(:,:) ! mass-weighted cloud water fallspeed (m/s)
- real(r8), intent(out) :: vtrmio(:,:) ! mass-weighted cloud ice fallspeed (m/s)
- real(r8), intent(out) :: qcsedteno(:,:) ! qc sedimentation tendency (1/s)
- real(r8), intent(out) :: qisedteno(:,:) ! qi sedimentation tendency (1/s)
+ real(r8), intent(out) :: tlat(:,:) ! latent heating rate (W/kg)
+ real(r8), intent(out) :: qvlat(:,:) ! microphysical tendency qv (1/s)
+ real(r8), intent(out) :: qctend(:,:) ! microphysical tendency qc (1/s)
+ real(r8), intent(out) :: qitend(:,:) ! microphysical tendency qi (1/s)
+ real(r8), intent(out) :: nctend(:,:) ! microphysical tendency nc (1/(kg*s))
+ real(r8), intent(out) :: nitend(:,:) ! microphysical tendency ni (1/(kg*s))
+ real(r8), intent(out) :: effc(:,:) ! droplet effective radius (micron)
+ real(r8), intent(out) :: effc_fn(:,:) ! droplet effective radius, assuming nc = 1.e8 kg-1
+ real(r8), intent(out) :: effi(:,:) ! cloud ice effective radius (micron)
+ real(r8), intent(out) :: prect(:) ! surface precip rate (m/s)
+ real(r8), intent(out) :: preci(:) ! cloud ice/snow precip rate (m/s)
+ real(r8), intent(out) :: nevapr(:,:) ! evaporation rate of rain + snow (1/s)
+ real(r8), intent(out) :: evapsnow(:,:) ! sublimation rate of snow (1/s)
+ real(r8), intent(out) :: prain(:,:) ! production of rain + snow (1/s)
+ real(r8), intent(out) :: prodsnow(:,:) ! production of snow (1/s)
+ real(r8), intent(out) :: cmeout(:,:) ! evap/sub of cloud (1/s)
+ real(r8), intent(out) :: deffi(:,:) ! ice effective diameter for optics (radiation) (micron)
+ real(r8), intent(out) :: pgamrad(:,:) ! ice gamma parameter for optics (radiation) (no units)
+ real(r8), intent(out) :: lamcrad(:,:) ! slope of droplet distribution for optics (radiation) (1/m)
+ real(r8), intent(out) :: qsout(:,:) ! snow mixing ratio (kg/kg)
+ real(r8), intent(out) :: dsout(:,:) ! snow diameter (m)
+ real(r8), intent(out) :: rflx(:,:) ! grid-box average rain flux (kg m^-2 s^-1)
+ real(r8), intent(out) :: sflx(:,:) ! grid-box average snow flux (kg m^-2 s^-1)
+ real(r8), intent(out) :: qrout(:,:) ! grid-box average rain mixing ratio (kg/kg)
+ real(r8), intent(out) :: reff_rain(:,:) ! rain effective radius (micron)
+ real(r8), intent(out) :: reff_snow(:,:) ! snow effective radius (micron)
+ real(r8), intent(out) :: qcsevap(:,:) ! cloud water evaporation due to sedimentation (1/s)
+ real(r8), intent(out) :: qisevap(:,:) ! cloud ice sublimation due to sublimation (1/s)
+ real(r8), intent(out) :: qvres(:,:) ! residual condensation term to ensure RH < 100% (1/s)
+ real(r8), intent(out) :: cmeitot(:,:) ! grid-mean cloud ice sub/dep (1/s)
+ real(r8), intent(out) :: vtrmc(:,:) ! mass-weighted cloud water fallspeed (m/s)
+ real(r8), intent(out) :: vtrmi(:,:) ! mass-weighted cloud ice fallspeed (m/s)
+ real(r8), intent(out) :: qcsedten(:,:) ! qc sedimentation tendency (1/s)
+ real(r8), intent(out) :: qisedten(:,:) ! qi sedimentation tendency (1/s)
! microphysical process rates for output (mixing ratio tendencies) (all have units of 1/s)
- real(r8), intent(out) :: prao(:,:) ! accretion of cloud by rain
- real(r8), intent(out) :: prco(:,:) ! autoconversion of cloud to rain
- real(r8), intent(out) :: mnuccco(:,:) ! mixing ratio tend due to immersion freezing
- real(r8), intent(out) :: mnuccto(:,:) ! mixing ratio tend due to contact freezing
- real(r8), intent(out) :: msacwio(:,:) ! mixing ratio tend due to H-M splintering
- real(r8), intent(out) :: psacwso(:,:) ! collection of cloud water by snow
- real(r8), intent(out) :: bergso(:,:) ! bergeron process on snow
- real(r8), intent(out) :: bergo(:,:) ! bergeron process on cloud ice
- real(r8), intent(out) :: melto(:,:) ! melting of cloud ice
- real(r8), intent(out) :: homoo(:,:) ! homogeneous freezing cloud water
- real(r8), intent(out) :: qcreso(:,:) ! residual cloud condensation due to removal of excess supersat
- real(r8), intent(out) :: prcio(:,:) ! autoconversion of cloud ice to snow
- real(r8), intent(out) :: praio(:,:) ! accretion of cloud ice by snow
- real(r8), intent(out) :: qireso(:,:) ! residual ice deposition due to removal of excess supersat
- real(r8), intent(out) :: mnuccro(:,:) ! mixing ratio tendency due to heterogeneous freezing of rain to snow (1/s)
- real(r8), intent(out) :: pracso(:,:) ! mixing ratio tendency due to accretion of rain by snow (1/s)
- real(r8), intent(out) :: meltsdto(:,:) ! latent heating rate due to melting of snow (W/kg)
- real(r8), intent(out) :: frzrdto(:,:) ! latent heating rate due to homogeneous freezing of rain (W/kg)
- real(r8), intent(out) :: mnuccdo(:,:) ! mass tendency from ice nucleation
- real(r8), intent(out) :: nrouto(:,:) ! rain number concentration (1/m3)
- real(r8), intent(out) :: nsouto(:,:) ! snow number concentration (1/m3)
- real(r8), intent(out) :: reflo(:,:) ! analytic radar reflectivity
- real(r8), intent(out) :: areflo(:,:) ! average reflectivity will zero points outside valid range
- real(r8), intent(out) :: areflzo(:,:) ! average reflectivity in z.
- real(r8), intent(out) :: freflo(:,:) ! fractional occurrence of radar reflectivity
- real(r8), intent(out) :: csrflo(:,:) ! cloudsat reflectivity
- real(r8), intent(out) :: acsrflo(:,:) ! cloudsat average
- real(r8), intent(out) :: fcsrflo(:,:) ! cloudsat fractional occurrence of radar reflectivity
- real(r8), intent(out) :: rercldo(:,:) ! effective radius calculation for rain + cloud
- real(r8), intent(out) :: ncaio(:,:) ! output number conc of ice nuclei available (1/m3)
- real(r8), intent(out) :: ncalo(:,:) ! output number conc of CCN (1/m3)
- real(r8), intent(out) :: qrouto2(:,:) ! copy of qrout as used to compute drout2
- real(r8), intent(out) :: qsouto2(:,:) ! copy of qsout as used to compute dsout2
- real(r8), intent(out) :: nrouto2(:,:) ! copy of nrout as used to compute drout2
- real(r8), intent(out) :: nsouto2(:,:) ! copy of nsout as used to compute dsout2
- real(r8), intent(out) :: drouto2(:,:) ! mean rain particle diameter (m)
- real(r8), intent(out) :: dsouto2(:,:) ! mean snow particle diameter (m)
- real(r8), intent(out) :: freqso(:,:) ! fractional occurrence of snow
- real(r8), intent(out) :: freqro(:,:) ! fractional occurrence of rain
- real(r8), intent(out) :: nficeo(:,:) ! fractional occurrence of ice
-
- character(128), intent(out) :: errstring ! output status (non-blank for error return)
+ real(r8), intent(out) :: pratot(:,:) ! accretion of cloud by rain
+ real(r8), intent(out) :: prctot(:,:) ! autoconversion of cloud to rain
+ real(r8), intent(out) :: mnuccctot(:,:) ! mixing ratio tend due to immersion freezing
+ real(r8), intent(out) :: mnuccttot(:,:) ! mixing ratio tend due to contact freezing
+ real(r8), intent(out) :: msacwitot(:,:) ! mixing ratio tend due to H-M splintering
+ real(r8), intent(out) :: psacwstot(:,:) ! collection of cloud water by snow
+ real(r8), intent(out) :: bergstot(:,:) ! bergeron process on snow
+ real(r8), intent(out) :: bergtot(:,:) ! bergeron process on cloud ice
+ real(r8), intent(out) :: melttot(:,:) ! melting of cloud ice
+ real(r8), intent(out) :: homotot(:,:) ! homogeneous freezing cloud water
+ real(r8), intent(out) :: qcrestot(:,:) ! residual cloud condensation due to removal of excess supersat
+ real(r8), intent(out) :: prcitot(:,:) ! autoconversion of cloud ice to snow
+ real(r8), intent(out) :: praitot(:,:) ! accretion of cloud ice by snow
+ real(r8), intent(out) :: qirestot(:,:) ! residual ice deposition due to removal of excess supersat
+ real(r8), intent(out) :: mnuccrtot(:,:) ! mixing ratio tendency due to heterogeneous freezing of rain to snow (1/s)
+ real(r8), intent(out) :: pracstot(:,:) ! mixing ratio tendency due to accretion of rain by snow (1/s)
+ real(r8), intent(out) :: meltsdttot(:,:) ! latent heating rate due to melting of snow (W/kg)
+ real(r8), intent(out) :: frzrdttot(:,:) ! latent heating rate due to homogeneous freezing of rain (W/kg)
+ real(r8), intent(out) :: mnuccdtot(:,:) ! mass tendency from ice nucleation
+ real(r8), intent(out) :: nrout(:,:) ! rain number concentration (1/m3)
+ real(r8), intent(out) :: nsout(:,:) ! snow number concentration (1/m3)
+ real(r8), intent(out) :: refl(:,:) ! analytic radar reflectivity
+ real(r8), intent(out) :: arefl(:,:) ! average reflectivity will zero points outside valid range
+ real(r8), intent(out) :: areflz(:,:) ! average reflectivity in z.
+ real(r8), intent(out) :: frefl(:,:) ! fractional occurrence of radar reflectivity
+ real(r8), intent(out) :: csrfl(:,:) ! cloudsat reflectivity
+ real(r8), intent(out) :: acsrfl(:,:) ! cloudsat average
+ real(r8), intent(out) :: fcsrfl(:,:) ! cloudsat fractional occurrence of radar reflectivity
+ real(r8), intent(out) :: rercld(:,:) ! effective radius calculation for rain + cloud
+ real(r8), intent(out) :: ncai(:,:) ! output number conc of ice nuclei available (1/m3)
+ real(r8), intent(out) :: ncal(:,:) ! output number conc of CCN (1/m3)
+ real(r8), intent(out) :: qrout2(:,:) ! copy of qrout as used to compute drout2
+ real(r8), intent(out) :: qsout2(:,:) ! copy of qsout as used to compute dsout2
+ real(r8), intent(out) :: nrout2(:,:) ! copy of nrout as used to compute drout2
+ real(r8), intent(out) :: nsout2(:,:) ! copy of nsout as used to compute dsout2
+ real(r8), intent(out) :: drout2(:,:) ! mean rain particle diameter (m)
+ real(r8), intent(out) :: dsout2(:,:) ! mean snow particle diameter (m)
+ real(r8), intent(out) :: freqs(:,:) ! fractional occurrence of snow
+ real(r8), intent(out) :: freqr(:,:) ! fractional occurrence of rain
+ real(r8), intent(out) :: nfice(:,:) ! fractional occurrence of ice
+ real(r8), intent(out) :: qcrat(:,:) ! limiter for qc process rates (1=no limit --> 0. no qc)
+
+ real(r8), intent(out) :: prer_evap(:,:)
+
+ character(128), intent(out) :: errstring ! output status (non-blank for error return)
+
+ ! Tendencies calculated by external schemes that can replace MG's native
+ ! process tendencies.
+ ! Used with CARMA cirrus microphysics
+ ! (or similar external microphysics model)
+ real(r8), intent(in), pointer :: tnd_qsnow(:,:) ! snow mass tendency (kg/kg/s)
+ real(r8), intent(in), pointer :: tnd_nsnow(:,:) ! snow number tendency (#/kg/s)
+ real(r8), intent(in), pointer :: re_ice(:,:) ! ice effective radius (m)
+
+ ! From external ice nucleation.
+ real(r8), intent(in), pointer :: frzimm(:,:) ! Number tendency due to immersion freezing (1/cm3)
+ real(r8), intent(in), pointer :: frzcnt(:,:) ! Number tendency due to contact freezing (1/cm3)
+ real(r8), intent(in), pointer :: frzdep(:,:) ! Number tendency due to deposition nucleation (1/cm3)
! local workspace
! all units mks unless otherwise stated
@@ -514,122 +527,14 @@ subroutine micro_mg_tend ( &
! parameters
real(r8), parameter :: mincld = 0.0001_r8 ! minimum allowed cloud fraction
real(r8), parameter :: cdnl = 0.e6_r8 ! cloud droplet number limiter
- ! assign number of sub-steps to iter
- ! use 2 sub-steps, following tests described in MG2008
- integer, parameter :: iter = 2
! local copies of input variables
- real(r8) :: q(mgncol,nlev) ! water vapor mixing ratio (kg/kg)
- real(r8) :: t(mgncol,nlev) ! temperature (K)
real(r8) :: qc(mgncol,nlev) ! cloud liquid mixing ratio (kg/kg)
real(r8) :: qi(mgncol,nlev) ! cloud ice mixing ratio (kg/kg)
real(r8) :: nc(mgncol,nlev) ! cloud liquid number concentration (1/kg)
real(r8) :: ni(mgncol,nlev) ! cloud liquid number concentration (1/kg)
- real(r8) :: p(mgncol,nlev) ! pressure (Pa)
- real(r8) :: pdel(mgncol,nlev) ! pressure difference across level (Pa)
- real(r8) :: relvar(mgncol,nlev) ! relative variance of cloud water (-)
- real(r8) :: accre_enhan(mgncol,nlev) ! optional accretion enhancement factor (-)
-
- real(r8) :: naai(mgncol,nlev) ! ice nucleation number (from microp_aero_ts) (1/kg)
- real(r8) :: npccn(mgncol,nlev) ! ccn activated number tendency (from microp_aero_ts) (1/kg*s)
-
- real(r8), allocatable :: rndst(:,:,:)
- real(r8), allocatable :: nacon(:,:,:)
-
- real(r8) :: tnd_qsnow(mgncol,nlev) ! snow mass tendency (kg/kg/s)
- real(r8) :: tnd_nsnow(mgncol,nlev) ! snow number tendency (#/kg/s)
- real(r8) :: re_ice(mgncol,nlev) ! ice effective radius (m)
-
- ! Packed copies of output variables
- real(r8) :: tlat(mgncol,nlev) ! latent heating rate (W/kg)
- real(r8) :: qvlat(mgncol,nlev) ! microphysical tendency qv (1/s)
- real(r8) :: qctend(mgncol,nlev) ! microphysical tendency qc (1/s)
- real(r8) :: qitend(mgncol,nlev) ! microphysical tendency qi (1/s)
- real(r8) :: nctend(mgncol,nlev) ! microphysical tendency nc (1/(kg*s))
- real(r8) :: nitend(mgncol,nlev) ! microphysical tendency ni (1/(kg*s))
-
- real(r8) :: effc(mgncol,nlev) ! droplet effective radius (micron)
- real(r8) :: effc_fn(mgncol,nlev) ! droplet effective radius, assuming nc = 1.e8 kg-1
- real(r8) :: effi(mgncol,nlev) ! cloud ice effective radius (micron)
-
- real(r8) :: prect(mgncol) ! surface precip rate (m/s)
- real(r8) :: preci(mgncol) ! cloud ice/snow precip rate (m/s)
-
- real(r8) :: nevapr(mgncol,nlev) ! evaporation rate of rain + snow (1/s)
- real(r8) :: evapsnow(mgncol,nlev) ! sublimation rate of snow (1/s)
- real(r8) :: prain(mgncol,nlev) ! production of rain + snow (1/s)
- real(r8) :: prodsnow(mgncol,nlev) ! production of snow (1/s)
- real(r8) :: cmeout(mgncol,nlev) ! evap/sub of cloud (1/s)
- real(r8) :: deffi(mgncol,nlev) ! ice effective diameter for optics (radiation) (micron)
- real(r8) :: pgamrad(mgncol,nlev) ! ice gamma parameter for optics (radiation) (no units)
- real(r8) :: lamcrad(mgncol,nlev) ! slope of droplet distribution for optics (radiation) (1/m)
-
-
- real(r8) :: qsout(mgncol,nlev) ! snow mixing ratio (kg/kg)
- real(r8) :: qsout2(mgncol,nlev) ! copy of qsout as used to compute dsout2
- real(r8) :: nsout(mgncol,nlev) ! snow number concentration (1/m3)
- real(r8) :: nsout2(mgncol,nlev) ! copy of nsout as used to compute dsout2
- real(r8) :: dsout(mgncol,nlev) ! snow diameter (m)
- real(r8) :: dsout2(mgncol,nlev) ! mean snow particle diameter (m)
-
- real(r8) :: qrout(mgncol,nlev) ! grid-box average rain mixing ratio (kg/kg)
- real(r8) :: qrout2(mgncol,nlev) ! copy of qrout as used to compute drout2
- real(r8) :: nrout(mgncol,nlev) ! rain number concentration (1/m3)
- real(r8) :: nrout2(mgncol,nlev) ! copy of nrout as used to compute drout2
- real(r8) :: drout2(mgncol,nlev) ! mean rain particle diameter (m)
-
- real(r8) :: reff_rain(mgncol,nlev) ! rain effective radius (micron)
- real(r8) :: reff_snow(mgncol,nlev) ! snow effective radius (micron)
-
- real(r8) :: freqs(mgncol,nlev) ! fractional occurrence of snow
- real(r8) :: freqr(mgncol,nlev) ! fractional occurrence of rain
-
- real(r8) :: rflx(mgncol,nlev+1) ! grid-box average rain flux (kg m^-2 s^-1)
- real(r8) :: sflx(mgncol,nlev+1) ! grid-box average snow flux (kg m^-2 s^-1)
-
- real(r8) :: qcsevap(mgncol,nlev) ! cloud water evaporation due to sedimentation (1/s)
- real(r8) :: qisevap(mgncol,nlev) ! cloud ice sublimation due to sublimation (1/s)
- real(r8) :: qvres(mgncol,nlev) ! residual condensation term to ensure RH < 100% (1/s)
- real(r8) :: cmeitot(mgncol,nlev) ! grid-mean cloud ice sub/dep (1/s)
- real(r8) :: vtrmc(mgncol,nlev) ! mass-weighted cloud water fallspeed (m/s)
- real(r8) :: vtrmi(mgncol,nlev) ! mass-weighted cloud ice fallspeed (m/s)
- real(r8) :: qcsedten(mgncol,nlev) ! qc sedimentation tendency (1/s)
- real(r8) :: qisedten(mgncol,nlev) ! qi sedimentation tendency (1/s)
-
- real(r8) :: pratot(mgncol,nlev) ! accretion of cloud by rain
- real(r8) :: prctot(mgncol,nlev) ! autoconversion of cloud to rain
- real(r8) :: mnuccctot(mgncol,nlev) ! mixing ratio tend due to immersion freezing
- real(r8) :: mnuccttot(mgncol,nlev) ! mixing ratio tend due to contact freezing
- real(r8) :: msacwitot(mgncol,nlev) ! mixing ratio tend due to H-M splintering
- real(r8) :: psacwstot(mgncol,nlev) ! collection of cloud water by snow
- real(r8) :: bergstot(mgncol,nlev) ! bergeron process on snow
- real(r8) :: bergtot(mgncol,nlev) ! bergeron process on cloud ice
- real(r8) :: melttot(mgncol,nlev) ! melting of cloud ice
- real(r8) :: homotot(mgncol,nlev) ! homogeneous freezing cloud water
- real(r8) :: qcrestot(mgncol,nlev) ! residual cloud condensation due to removal of excess supersat
- real(r8) :: prcitot(mgncol,nlev) ! autoconversion of cloud ice to snow
- real(r8) :: praitot(mgncol,nlev) ! accretion of cloud ice by snow
- real(r8) :: qirestot(mgncol,nlev) ! residual ice deposition due to removal of excess supersat
- real(r8) :: mnuccrtot(mgncol,nlev) ! mixing ratio tendency due to heterogeneous freezing of rain to snow (1/s)
- real(r8) :: pracstot(mgncol,nlev) ! mixing ratio tendency due to accretion of rain by snow (1/s)
- real(r8) :: mnuccdtot(mgncol,nlev) ! mass tendency from ice nucleation
- real(r8) :: meltsdttot(mgncol,nlev) ! latent heating rate due to melting of snow (W/kg)
- real(r8) :: frzrdttot(mgncol,nlev) ! latent heating rate due to homogeneous freezing of rain (W/kg)
-
- real(r8) :: refl(mgncol,nlev) ! analytic radar reflectivity
- real(r8) :: arefl(mgncol,nlev) ! average reflectivity will zero points outside valid range
- real(r8) :: areflz(mgncol,nlev) ! average reflectivity in z.
- real(r8) :: frefl(mgncol,nlev) ! fractional occurrence of radar reflectivity
- real(r8) :: csrfl(mgncol,nlev) ! cloudsat reflectivity
- real(r8) :: acsrfl(mgncol,nlev) ! cloudsat average
- real(r8) :: fcsrfl(mgncol,nlev) ! cloudsat fractional occurrence of radar reflectivity
-
- real(r8) :: rercld(mgncol,nlev) ! effective radius calculation for rain + cloud
-
- real(r8) :: nfice(mgncol,nlev) ! fractional occurrence of ice
-
- real(r8) :: ncai(mgncol,nlev) ! output number conc of ice nuclei available (1/m3)
- real(r8) :: ncal(mgncol,nlev) ! output number conc of CCN (1/m3)
+
+ real(r8) :: nevapr2(mgncol,nlev)
! general purpose variables
real(r8) :: deltat ! sub-time step (s)
@@ -639,16 +544,6 @@ subroutine micro_mg_tend ( &
real(r8) :: int_to_mid(mgncol, nlev) ! Coefficients for linear interpolation from
! interface to mid-level
- ! temporary variables for sub-stepping
- real(r8) :: tlat1(mgncol,nlev)
- real(r8) :: qvlat1(mgncol,nlev)
- real(r8) :: qctend1(mgncol,nlev)
- real(r8) :: qitend1(mgncol,nlev)
- real(r8) :: nctend1(mgncol,nlev)
- real(r8) :: nitend1(mgncol,nlev)
- real(r8) :: prect1(mgncol)
- real(r8) :: preci1(mgncol)
-
! physical properties of the air at a given point
real(r8) :: rho(mgncol,nlev) ! density (kg m-3)
real(r8) :: dv(mgncol,nlev) ! diffusivity of water vapor
@@ -691,12 +586,11 @@ subroutine micro_mg_tend ( &
real(r8) :: lamr(mgncol,nlev) ! slope
real(r8) :: n0r(mgncol,nlev) ! intercept
- ! combined size of precip & cloud drops
- integer :: arcld(mgncol, nlev) ! averaging control flag
-
! Rates/tendencies due to:
- ! deposition/sublimation of cloud ice
- real(r8) :: cmei(mgncol,nlev)
+ ! deposition of cloud ice
+ real(r8) :: vap_dep(mgncol,nlev) ! deposition from vapor to ice PMC 12/3/12
+ ! sublimation of cloud ice
+ real(r8) :: ice_sublim(mgncol,nlev) ! sublimation from ice to vapor PMC 12/3/12
! ice nucleation
real(r8) :: nnuccd(mgncol,nlev) ! number rate from deposition/cond.-freezing
real(r8) :: mnuccd(mgncol,nlev) ! mass mixing ratio
@@ -706,9 +600,12 @@ subroutine micro_mg_tend ( &
! contact freezing of cloud water
real(r8) :: mnucct(mgncol,nlev) ! mass mixing ratio
real(r8) :: nnucct(mgncol,nlev) ! number concentration
+ ! deposition nucleation in mixed-phase clouds (from external scheme)
+ real(r8) :: mnudep(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nnudep(mgncol,nlev) ! number concentration
! HM ice multiplication
real(r8) :: msacwi(mgncol,nlev) ! mass mixing ratio
- real(r8) :: nsacwi(mgncol,nlev) ! number conc
+ real(r8) :: nsacwi(mgncol,nlev) ! number concentration
! autoconversion of cloud droplets
real(r8) :: prc(mgncol,nlev) ! mass mixing ratio
real(r8) :: nprc(mgncol,nlev) ! number concentration (rain)
@@ -761,6 +658,9 @@ subroutine micro_mg_tend ( &
real(r8) :: acn(mgncol,nlev) ! cloud droplet
real(r8) :: ain(mgncol,nlev) ! cloud ice
+ ! Mass of liquid droplets used with external heterogeneous freezing.
+ real(r8) :: mi0l(mgncol)
+
! saturation vapor pressures
real(r8) :: esl(mgncol,nlev) ! liquid
real(r8) :: esi(mgncol,nlev) ! ice
@@ -769,7 +669,7 @@ subroutine micro_mg_tend ( &
! saturation vapor mixing ratios
real(r8) :: qvl(mgncol,nlev) ! liquid
real(r8) :: qvi(mgncol,nlev) ! ice
- real(r8) :: qsn ! checking for RH after rain evap
+ real(r8) :: qvn ! checking for RH after rain evap
! relative humidity
real(r8) :: relhum(mgncol,nlev)
@@ -803,8 +703,7 @@ subroutine micro_mg_tend ( &
real(r8) :: qstot(mgncol) ! snow mixing ratio
real(r8) :: nstot(mgncol) ! snow number concentration
- ! for calculation of rate1ord_cw2pr_st
- real(r8) :: qcsinksum_rate1ord(mgncol,nlev) ! sum over iterations of cw to precip sink
+ ! for calculation of rate1ord
real(r8) :: qcsum_rate1ord(mgncol,nlev) ! sum over iterations of cloud water
real(r8) :: rainrt(mgncol,nlev) ! rain rate for reflectivity calculation
@@ -812,15 +711,15 @@ subroutine micro_mg_tend ( &
! dummy variables
real(r8) :: dum
real(r8) :: dum1
+ real(r8) :: dum2
! dummies for checking RH
real(r8) :: qtmp
real(r8) :: ttmp
+ real(r8) :: qtmp1
+ real(r8) :: ttmp1
! dummies for conservation check
- real(r8) :: qce ! qc
- real(r8) :: qie ! qi
- real(r8) :: nce ! nc
- real(r8) :: nie ! ni
real(r8) :: ratio
+ real(r8) :: tmpfrz
! dummies for in-cloud variables
real(r8) :: dumc(mgncol,nlev) ! qc
real(r8) :: dumnc(mgncol,nlev) ! nc
@@ -833,66 +732,48 @@ subroutine micro_mg_tend ( &
! loop array variables
! "i" and "k" are column/level iterators for internal (MG) variables
- ! "ii" and "kk" are used for indices into input/output buffers
- ! "it" is substepping variable
- ! "n" is used for other iterations (currently just sedimentation)
- integer i, ii, k, kk, it, n
+ ! "n" is used for other looping (currently just sedimentation)
+ integer i, k, n
- ! number of iterations for loops over "n"
+ ! number of sub-steps for loops over "n" (for sedimentation)
integer nstep
+ ! Whether or not to limit evaporation/sublimation of precip at each grid
+ ! point.
+ logical :: limit_precip_evap_sublim
+
!cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
! default return error message
errstring = ' '
+ if (.not. (do_cldice .or. &
+ (associated(tnd_qsnow) .and. associated(tnd_nsnow) .and. associated(re_ice)))) then
+ errstring = "MG's native cloud ice processes are disabled, but &
+ &no replacement values were passed in."
+ end if
+
+ if (use_hetfrz_classnuc .and. (.not. &
+ (associated(frzimm) .and. associated(frzcnt) .and. associated(frzdep)))) then
+ errstring = "External heterogeneous freezing is enabled, but the &
+ &required tendencies were not all passed in."
+ end if
+
! Process inputs
- ! assign variable deltat for sub-stepping...
+ ! assign variable deltat to deltatin
deltat = deltatin
- call pack_array( qn, mgcols, top_lev, q)
- call pack_array( tn, mgcols, top_lev, t)
- call pack_array( qcn, mgcols, top_lev, qc)
- call pack_array( qin, mgcols, top_lev, qi)
- call pack_array( ncn, mgcols, top_lev, nc)
- call pack_array( nin, mgcols, top_lev, ni)
- call pack_array( pn, mgcols, top_lev, p)
- call pack_array( pdeln, mgcols, top_lev, pdel)
- call pack_array( relvarn, mgcols, top_lev, relvar)
- call pack_array(accre_enhann, mgcols, top_lev, accre_enhan)
-
- call pack_array( naain, mgcols, top_lev, naai)
- call pack_array(npccnin, mgcols, top_lev, npccn)
-
- ! These are allocated instead of used as automatic arrays
- ! purely to work around a PGI bug.
- allocate(rndst(mgncol,nlev,size(rndstn,3)))
- allocate(nacon(mgncol,nlev,size(rndstn,3)))
- call pack_array( rndstn, mgcols, top_lev, rndst)
- call pack_array(naconin, mgcols, top_lev, nacon)
-
- if (.not. do_cldice) then
- call pack_array(tnd_qsnown, mgcols, top_lev, tnd_qsnow)
- call pack_array(tnd_nsnown, mgcols, top_lev, tnd_nsnow)
- call pack_array( re_icen, mgcols, top_lev, re_ice)
- end if
-
- ! Some inputs are only used once, to create a reference array that is
- ! used repeatedly later. Rather than bothering to pack these, just
- ! set the local reference directly from the inputs.
+ ! Copies of input concentrations that may be changed internally.
+ qc = qcn
+ nc = ncn
+ qi = qin
+ ni = nin
! pint: used to set int_to_mid
! interface to mid-level linear interpolation
do k = 1,nlev
- do i = 1, mgncol
- ! Set ii and kk to values that correspond to i and k.
- ii = mgcols(i)
- kk = k + top_lev - 1
-
- int_to_mid(i,k) = (p(i,k) - pint(ii,kk))/ &
- (pint(ii,kk+1) - pint(ii,kk))
- end do
+ int_to_mid(:,k) = (p(:,k) - pint(:,k)) / (pint(:,k+1) - pint(:,k))
end do
! cldn: used to set cldm, unused for subcolumns
@@ -921,17 +802,9 @@ subroutine micro_mg_tend ( &
else
! get cloud fraction, check for minimum
-
- do k = 1,nlev
- do i = 1, mgncol
- ii = mgcols(i)
- kk = k + top_lev - 1
-
- cldm(i,k) = max(cldn(ii,kk),mincld)
- lcldm(i,k) = max(liqcldf(ii,kk),mincld)
- icldm(i,k) = max(icecldf(ii,kk),mincld)
- end do
- end do
+ cldm = max(cldn,mincld)
+ lcldm = max(liqcldf,mincld)
+ icldm = max(icecldf,mincld)
end if
! Initialize local variables
@@ -976,74 +849,13 @@ subroutine micro_mg_tend ( &
end do
end do
- where (qvl <= 0.0_r8)
- relhum = q
- elsewhere
- relhum = q / min(1.0_r8,qvl)
- end where
+ relhum = q / max(qvl, qsmall)
!===============================================
- ! Processes done before substepping
- !===============================================
-
- ! Initial deposition/sublimation of ice
- !===========================================
-
- if (do_cldice) then
-
- call ice_deposition_sublimation_init(deltat, t, q, qc, qi, ni, &
- lcldm, icldm, naai, rho, dv, &
- esl, esi, qvl, qvi, relhum, &
- berg, cmei)
-
- else
- berg = 0._r8
- cmei = 0._r8
- end if ! end do_cldice
-
- !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
- ! droplet activation
- ! hm, modify 5/12/11
- ! get provisional droplet number after activation. This is used for
- ! all microphysical process calculations, for consistency with update of
- ! droplet mass before microphysics
-
- ! calculate potential for droplet activation if cloud water is present
- ! tendency from activation (npccn) is read in from companion routine
-
- ! output activated liquid and ice (convert from #/kg -> #/m3)
- !--------------------------------------------------
- where (qc >= qsmall)
- nc = nc + npccn*deltat
- ncal = max(nc/lcldm,cdnl/rho)*rho ! sghan minimum in #/cm3
- elsewhere
- ncal = 0._r8
- end where
-
- where (t < icenuct)
- ncai = naai*rho
- elsewhere
- ncai = 0._r8
- end where
-
- !INITIALIZE STUFF FOR SUBSTEPPING
- !===============================================
-
- ! get sub-step time step
- deltat=deltat/real(iter)
! hm, set mtime here to avoid answer-changing
mtime=deltat
- ! initialize tendencies to zero
- tlat1 = 0._r8
- qvlat1 = 0._r8
- qctend1 = 0._r8
- qitend1 = 0._r8
- nctend1 = 0._r8
- nitend1 = 0._r8
-
-
! initialize microphysics output
qcsevap=0._r8
qisevap=0._r8
@@ -1078,7 +890,7 @@ subroutine micro_mg_tend ( &
sflx=0._r8
! initialize precip output
-
+
qrout=0._r8
qsout=0._r8
nrout=0._r8
@@ -1089,139 +901,122 @@ subroutine micro_mg_tend ( &
! initialize rain size
rercld=0._r8
- arcld = 0
- qcsinksum_rate1ord = 0._r8
- qcsum_rate1ord = 0._r8
+ qcsinksum_rate1ord = 0._r8
+ qcsum_rate1ord = 0._r8
! initialize variables for trop_mozart
nevapr = 0._r8
+ nevapr2 = 0._r8
evapsnow = 0._r8
prain = 0._r8
prodsnow = 0._r8
cmeout = 0._r8
- prect1 = 0._r8
- preci1 = 0._r8
-
cldmax = mincld
lamc=0._r8
+ ! initialize microphysical tendencies
- !*********DO SUBSTEPPING!***************
- !============================================
- substepping: do it=1,iter
+ tlat=0._r8
+ qvlat=0._r8
+ qctend=0._r8
+ qitend=0._r8
+ qstend = 0._r8
+ qrtend = 0._r8
+ nctend=0._r8
+ nitend=0._r8
+ nrtend = 0._r8
+ nstend = 0._r8
- ! initialize sub-step microphysical tendencies
+ ! initialize diagnostic precipitation to zero
+ qcic = 0._r8
+ qiic = 0._r8
+ qsic = 0._r8
+ qric = 0._r8
- tlat=0._r8
- qvlat=0._r8
- qctend=0._r8
- qitend=0._r8
- qstend = 0._r8
- qrtend = 0._r8
- nctend=0._r8
- nitend=0._r8
- nrtend = 0._r8
- nstend = 0._r8
+ ncic = 0._r8
+ niic = 0._r8
+ nsic = 0._r8
+ nric = 0._r8
- ! initialize diagnostic precipitation to zero
- qcic = 0._r8
- qiic = 0._r8
- qsic = 0._r8
- qric = 0._r8
+ ! initialize precip at surface
- ncic = 0._r8
- niic = 0._r8
- nsic = 0._r8
- nric = 0._r8
+ prect = 0._r8
+ preci = 0._r8
- ! initialize precip at surface
+ ! initialize vertically-integrated rain and snow tendencies
- prect = 0._r8
- preci = 0._r8
+ qrtot = 0._r8
+ nrtot = 0._r8
+ qstot = 0._r8
+ nstot = 0._r8
- ! initialize vertically-integrated rain and snow tendencies
+ ! initialize precip fallspeeds to zero
+ ums = 0._r8
+ uns = 0._r8
+ umr = 0._r8
+ unr = 0._r8
- qrtot = 0._r8
- nrtot = 0._r8
- qstot = 0._r8
- nstot = 0._r8
-
- ! recalculate saturation vapor pressure for liquid and ice
- do k = 1, nlev
- do i = 1, mgncol
-
- call qsat_water(t(i,k), p(i,k), esl(i,k), qvl(i,k))
-
- ! hm fix, make sure when above freezing that esi=esl, not active yet
- if (t(i,k) >= tmelt) then
- esi(i,k)=esl(i,k)
- qvi(i,k)=qvl(i,k)
- else
- call qsat_ice(t(i,k), p(i,k), esi(i,k), qvi(i,k))
- end if
-
- end do
- end do
-
- where (qvl <= 0.0_r8)
- relhum = q
- elsewhere
- relhum = q / min(1.0_r8,qvl)
- end where
+ ! initialize limiter for output
+ qcrat = 1._r8
- ! decrease in number concentration due to sublimation/evap
- !-------------------------------------------------------
- ! divide by cloud fraction to get in-cloud decrease
- ! don't reduce Nc due to bergeron process
+ !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+ ! droplet activation
+ ! hm, modify 5/12/11
+ ! get provisional droplet number after activation. This is used for
+ ! all microphysical process calculations, for consistency with update of
+ ! droplet mass before microphysics
- where (cmei < 0._r8 .and. qi > qsmall .and. icldm > mincld)
- nsubi = cmei / qi * ni / icldm
- elsewhere
- nsubi = 0._r8
- end where
+ ! calculate potential for droplet activation if cloud water is present
+ ! tendency from activation (npccn) is read in from companion routine
- nsubc = 0._r8
+ ! output activated liquid and ice (convert from #/kg -> #/m3)
+ !--------------------------------------------------
+ where (qc >= qsmall)
+ nc = max(nc + npccn*deltat, cdnl*lcldm/rho)
+ ncal = nc*rho/lcldm ! sghan minimum in #/cm3
+ elsewhere
+ ncal = 0._r8
+ end where
- ! ice nucleation if activated nuclei exist at t<-5C AND rhmini + 5%
- !-------------------------------------------------------
+ where (t < icenuct)
+ ncai = naai*rho
+ elsewhere
+ ncai = 0._r8
+ end where
- if (do_cldice) then
- where (naai > 0._r8 .and. t < icenuct .and. &
- relhum*esl/esi > rhmini+0.05_r8)
+ !===============================================
- !if NAAI > 0. then set numice = naai (as before)
- !note: this is gridbox averaged
- ! hm, modify to use mtime
- nnuccd = (naai-ni/icldm)/mtime*icldm
- nnuccd = max(nnuccd,0._r8)
- nimax = naai*icldm
+ ! ice nucleation if activated nuclei exist at t<-5C AND rhmini + 5%
+ !-------------------------------------------------------
- !Calc mass of new particles using new crystal mass...
- !also this will be multiplied by mtime as nnuccd is...
+ if (do_cldice) then
+ where (naai > 0._r8 .and. t < icenuct .and. &
+ relhum*esl/esi > rhmini+0.05_r8)
- mnuccd = nnuccd * mi0
+ !if NAAI > 0. then set numice = naai (as before)
+ !note: this is gridbox averaged
+ ! hm, modify to use mtime
+ nnuccd = (naai-ni/icldm)/mtime*icldm
+ nnuccd = max(nnuccd,0._r8)
+ nimax = naai*icldm
- ! add mnuccd to cmei....
- cmei = cmei + mnuccd
-
- ! limit cmei
- !-------------------------------------------------------
- cmei = min(cmei,(q-qvi)/calc_ab(t, qvi, xxls)/deltat)
+ !Calc mass of new particles using new crystal mass...
+ !also this will be multiplied by mtime as nnuccd is...
- ! limit for roundoff error
- cmei = cmei * omsm
+ mnuccd = nnuccd * mi0
- elsewhere
- nnuccd = 0._r8
- nimax = 0._r8
- mnuccd = 0._r8
- end where
+ elsewhere
+ nnuccd = 0._r8
+ nimax = 0._r8
+ mnuccd = 0._r8
+ end where
- end if
+ end if
+ !=============================================================================
pre_vert_loop: do k=1,nlev
pre_col_loop: do i=1,mgncol
@@ -1231,7 +1026,7 @@ subroutine micro_mg_tend ( &
! for microphysical process calculations
! units are kg/kg for mixing ratio, 1/kg for number conc
- if (qc(i,k) - berg(i,k)*deltat.ge.qsmall) then
+ if (qc(i,k).ge.qsmall) then
! limit in-cloud values to 0.005 kg/kg
qcic(i,k)=min(qc(i,k)/lcldm(i,k),5.e-3_r8)
ncic(i,k)=max(nc(i,k)/lcldm(i,k),0._r8)
@@ -1243,11 +1038,9 @@ subroutine micro_mg_tend ( &
else
qcic(i,k)=0._r8
ncic(i,k)=0._r8
-
- berg(i,k)=qc(i,k)/deltat*omsm
end if
- if (qi(i,k)+(cmei(i,k)+berg(i,k))*deltat.ge.qsmall) then
+ if (qi(i,k).ge.qsmall) then
! limit in-cloud values to 0.005 kg/kg
qiic(i,k)=min(qi(i,k)/icldm(i,k),5.e-3_r8)
niic(i,k)=max(ni(i,k)/icldm(i,k),0._r8)
@@ -1259,27 +1052,12 @@ subroutine micro_mg_tend ( &
else
qiic(i,k)=0._r8
niic(i,k)=0._r8
-
- if (do_cldice) then
- cmei(i,k)=(-qi(i,k)/deltat-berg(i,k))*omsm
- end if
end if
end do pre_col_loop
end do pre_vert_loop
- ! add to cme output
- cmeout = cmeout + cmei
-
- !=========================================================
- ! Main microphysical loop
- !=========================================================
-
- ! initialize precip fallspeeds to zero
- ums = 0._r8
- uns = 0._r8
- umr = 0._r8
- unr = 0._r8
+ !========================================================================
! for sub-columns cldm has already been set to 1 if cloud
! water or ice is present, so cldmax will be correctly set below
@@ -1289,16 +1067,37 @@ subroutine micro_mg_tend ( &
micro_vert_loop: do k=1,nlev
- ! calculate precip fraction based on maximum overlap assumption
+ if (trim(micro_mg_precip_frac_method) == 'in_cloud') then
+
+ do i=1, mgncol
+
+ if (k .eq. 1) then
+ cldmax(i,k)=cldm(i,k)
+ else
+
+ if (qc(i,k).ge.qsmall.or.qi(i,k).ge.qsmall) then
+ cldmax(i,k)=cldm(i,k)
+ else
+ cldmax(i,k)=cldmax(i,k-1)
+ end if
+
+ endif
+
+ enddo
+ else if(trim(micro_mg_precip_frac_method) == 'max_overlap') then
+
+ ! calculate precip fraction based on maximum overlap assumption
+
+ ! if rain or snow mix ratios are smaller than threshold,
+ ! then leave cldmax as cloud fraction at current level
+ if (k /= 1) then
+ where (qric(:,k-1).ge.qsmall .or. qsic(:,k-1).ge.qsmall)
+ cldmax(:,k)=max(cldmax(:,k-1),cldmax(:,k))
+ end where
+ end if
+
+ endif
- ! if rain or snow mix ratios are smaller than threshold,
- ! then leave cldmax as cloud fraction at current level
- if (k /= 1) then
- where (qric(:,k-1).ge.qsmall .or. qsic(:,k-1).ge.qsmall)
- cldmax(:,k)=max(cldmax(:,k-1),cldmax(:,k))
- end where
- end if
-
do i = 1, mgncol
!ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
@@ -1387,7 +1186,7 @@ subroutine micro_mg_tend ( &
nric(:,k)=0._r8
end where
- ! make sure number concentration is a positive number to avoid
+ ! make sure number concentration is a positive number to avoid
! taking root of negative later
nric(:,k)=max(nric(:,k),0._r8)
@@ -1415,7 +1214,7 @@ subroutine micro_mg_tend ( &
! add autoconversion to flux from level above to get provisional snow mixing ratio
! and number concentration (qsic and nsic)
- ! hm 11-16-11 modify for mid-point method, see comments above
+ ! hm 11-16-11 modify for mid-point-type method, see comments above
if (k == 1) then
dum=(asn(i,k)*cons25)
@@ -1451,7 +1250,7 @@ subroutine micro_mg_tend ( &
nsic(:,k)=0._r8
end where
- ! make sure number concentration is a positive number to avoid
+ ! make sure number concentration is a positive number to avoid
! taking root of negative later
nsic(:,k)=max(nsic(:,k),0._r8)
@@ -1493,34 +1292,66 @@ subroutine micro_mg_tend ( &
end where
if (do_cldice) then
+ if (.not. use_hetfrz_classnuc) then
- ! heterogeneous freezing of cloud water
- !----------------------------------------------
+ ! heterogeneous freezing of cloud water
+ !----------------------------------------------
- call immersion_freezing(t(:,k), pgam(:,k), lamc(:,k), cdist1(:,k), qcic(:,k), &
- relvar(:,k), mnuccc(:,k), nnuccc(:,k))
+ call immersion_freezing(t(:,k), pgam(:,k), lamc(:,k), cdist1(:,k), qcic(:,k), &
+ relvar(:,k), mnuccc(:,k), nnuccc(:,k))
- ! make sure number of droplets frozen does not exceed available ice nuclei concentration
- ! this prevents 'runaway' droplet freezing
+ ! make sure number of droplets frozen does not exceed available ice nuclei concentration
+ ! this prevents 'runaway' droplet freezing
- where (qcic(:,k).ge.qsmall .and. t(:,k).lt.269.15_r8)
- where (nnuccc(:,k)*lcldm(:,k).gt.nnuccd(:,k))
- ! scale mixing ratio of droplet freezing with limit
- mnuccc(:,k)=mnuccc(:,k)*(nnuccd(:,k)/(nnuccc(:,k)*lcldm(:,k)))
- nnuccc(:,k)=nnuccd(:,k)/lcldm(:,k)
+ where (qcic(:,k).ge.qsmall .and. t(:,k).lt.269.15_r8)
+ where (nnuccc(:,k)*lcldm(:,k).gt.nnuccd(:,k))
+ ! scale mixing ratio of droplet freezing with limit
+ mnuccc(:,k)=mnuccc(:,k)*(nnuccd(:,k)/(nnuccc(:,k)*lcldm(:,k)))
+ nnuccc(:,k)=nnuccd(:,k)/lcldm(:,k)
+ end where
end where
- end where
- call contact_freezing(t(:,k), p(:,k), rndst(:,k,:), nacon(:,k,:), &
- pgam(:,k), lamc(:,k), cdist1(:,k), qcic(:,k), &
- relvar(:,k), mnucct(:,k), nnucct(:,k))
+ call contact_freezing(t(:,k), p(:,k), rndst(:,k,:), nacon(:,k,:), &
+ pgam(:,k), lamc(:,k), cdist1(:,k), qcic(:,k), &
+ relvar(:,k), mnucct(:,k), nnucct(:,k))
+
+ mnudep(:,k)=0._r8
+ nnudep(:,k)=0._r8
+
+ else
+
+ mi0l = qcic(:,k)/max(ncic(:,k), 1.0e6_r8/rho(:,k))
+ mi0l = max(mi0l_min, mi0l)
+
+ where (qcic(:,k) >= qsmall)
+ nnuccc(:,k) = frzimm(:,k)*1.0e6_r8/rho(:,k)
+ mnuccc(:,k) = nnuccc(:,k)*mi0l
+
+ nnucct(:,k) = frzcnt(:,k)*1.0e6_r8/rho(:,k)
+ mnucct(:,k) = nnucct(:,k)*mi0l
+ nnudep(:,k) = frzdep(:,k)*1.0e6_r8/rho(:,k)
+ mnudep(:,k) = nnudep(:,k)*mi0
+ elsewhere
+ nnuccc(:,k) = 0._r8
+ mnuccc(:,k) = 0._r8
+
+ nnucct(:,k) = 0._r8
+ mnucct(:,k) = 0._r8
+
+ nnudep(:,k) = 0._r8
+ mnudep(:,k) = 0._r8
+ end where
+
+ end if
else
- mnuccc(:,k)=0._r8
- nnuccc(:,k)=0._r8
- mnucct(:,k)=0._r8
- nnucct(:,k)=0._r8
+ mnuccc(:,k)=0._r8
+ nnuccc(:,k)=0._r8
+ mnucct(:,k)=0._r8
+ nnucct(:,k)=0._r8
+ mnudep(:,k)=0._r8
+ nnudep(:,k)=0._r8
end if
call snow_self_aggregation(t(:,k), rho(:,k), asn(:,k), qsic(:,k), nsic(:,k), &
@@ -1556,17 +1387,38 @@ subroutine micro_mg_tend ( &
prai(:,k) = 0._r8
nprai(:,k) = 0._r8
end if
-
+
call evaporate_sublimate_precip(deltat, t(:,k), p(:,k), rho(:,k), &
dv(:,k), mu(:,k), sc(:,k), q(:,k), qvl(:,k), qvi(:,k), &
lcldm(:,k), cldmax(:,k), arn(:,k), asn(:,k), qcic(:,k), qiic(:,k), &
- qric(:,k), qsic(:,k), lamr(:,k), n0r(:,k), lams(:,k), n0s(:,k), cmei(:,k), &
+ qric(:,k), qsic(:,k), lamr(:,k), n0r(:,k), lams(:,k), n0s(:,k), &
pre(:,k), prds(:,k))
- call bergeron_process(t(:,k), rho(:,k), dv(:,k), mu(:,k), sc(:,k), &
+ call bergeron_process_snow(t(:,k), rho(:,k), dv(:,k), mu(:,k), sc(:,k), &
qvl(:,k), qvi(:,k), asn(:,k), qcic(:,k), qsic(:,k), lams(:,k), n0s(:,k), &
bergs(:,k))
+ !+++PMC 12/3/12 - NEW VAPOR DEP/SUBLIMATION GOES HERE!!!
+ if (do_cldice) then
+
+ call ice_deposition_sublimation(deltat, t(:,k), q(:,k), qc(:,k), qi(:,k), ni(:,k), &
+ lcldm(:,k),icldm(:,k), naai(:,k), rho(:,k), dv(:,k), qvl(:,k), qvi(:,k), &
+ berg(:,k), vap_dep(:,k), ice_sublim(:,k))
+
+ where (vap_dep(:,k) < 0._r8 .and. qi(:,k) > qsmall .and. icldm(:,k) > mincld)
+ nsubi(:,k) = vap_dep(:,k) / qi(:,k) * ni(:,k) / icldm(:,k)
+ elsewhere
+ nsubi(:,k) = 0._r8
+ end where
+
+ ! bergeron process should not reduce nc unless
+ ! all ql is removed (which is handled elsewhere)
+ !in fact, nothing in this entire file makes nsubc nonzero.
+ nsubc(:,k) = 0._r8
+
+ end if !do_cldice
+ !---PMC 12/3/12
+
! Big "administration" loop enforces conservation, updates variables
! that accumulate over substeps, and sets output variables.
@@ -1576,42 +1428,128 @@ subroutine micro_mg_tend ( &
! in case microphysical process rates are large
!===================================================================
- ! make sure to use end-of-time step values for cloud water, ice, due
- ! condensation/deposition
-
! note: for check on conservation, processes are multiplied by omsm
! to prevent problems due to round off error
- qce=(qc(i,k) - berg(i,k)*deltat)
- nce=nc(i,k)
- qie=(qi(i,k)+(cmei(i,k)+berg(i,k))*deltat)
- nie=(ni(i,k)+nnuccd(i,k)*deltat)
-
! conservation of qc
!-------------------------------------------------------------------
- dum = (prc(i,k)+pra(i,k)+mnuccc(i,k)+mnucct(i,k)+msacwi(i,k)+ &
- psacws(i,k)+bergs(i,k))*lcldm(i,k)*deltat
-
- if (dum.gt.qce) then
- ratio = qce/deltat/lcldm(i,k)/(prc(i,k)+pra(i,k)+mnuccc(i,k)+mnucct(i,k)+msacwi(i,k)+psacws(i,k)+bergs(i,k))*omsm
+ dum = ((prc(i,k)+pra(i,k)+mnuccc(i,k)+mnucct(i,k)+msacwi(i,k)+ &
+ psacws(i,k)+bergs(i,k))*lcldm(i,k)+berg(i,k))*deltat
+ if (dum.gt.qc(i,k)) then
+ ratio = qc(i,k)/deltat/((prc(i,k)+pra(i,k)+mnuccc(i,k)+mnucct(i,k)+ &
+ msacwi(i,k)+psacws(i,k)+bergs(i,k))*lcldm(i,k)+berg(i,k))*omsm
prc(i,k) = prc(i,k)*ratio
pra(i,k) = pra(i,k)*ratio
mnuccc(i,k) = mnuccc(i,k)*ratio
- mnucct(i,k) = mnucct(i,k)*ratio
- msacwi(i,k) = msacwi(i,k)*ratio
+ mnucct(i,k) = mnucct(i,k)*ratio
+ msacwi(i,k) = msacwi(i,k)*ratio
psacws(i,k) = psacws(i,k)*ratio
bergs(i,k) = bergs(i,k)*ratio
+ berg(i,k) = berg(i,k)*ratio
+ qcrat(i,k) = ratio
+ else
+ qcrat(i,k) = 1._r8
end if
+ !PMC 12/3/12: ratio is also frac of step w/ liquid.
+ !thus we apply berg for "ratio" of timestep and vapor
+ !deposition for the remaining frac of the timestep.
+ if (qc(i,k) >= qsmall) then
+ vap_dep(i,k) = vap_dep(i,k)*(1._r8-qcrat(i,k))
+ end if
+
+ !=================================================================
+ ! apply limiter to ensure that ice/snow sublimation and rain evap
+ ! don't push conditions into supersaturation, and ice deposition/nucleation don't
+ ! push conditions into sub-saturation
+ ! note this is done after qc conservation since we don't know how large
+ ! vap_dep is before then
+ ! estimates are only approximate since other process terms haven't been limited
+ ! for conservation yet
+
+ ! first limit ice deposition/nucleation vap_dep + mnuccd
+ dum1 = vap_dep(i,k) + mnuccd(i,k)
+ if (dum1 > 1.e-20_r8) then
+ dum = (q(i,k)-qvi(i,k))/(1._r8 + cons28*qvi(i,k)/(cpp*rv*t(i,k)**2))/deltat
+ dum = max(dum,0._r8)
+ if (dum1 > dum) then
+ dum1=mnuccd(i,k)/(vap_dep(i,k)+mnuccd(i,k))
+ ! don't divide by cloud fraction since grid-mean rate
+ mnuccd(i,k)=dum*dum1/deltat
+
+ ! don't divide by cloud fraction since grid-mean rate
+ vap_dep(i,k)=dum*(1._r8-dum1)/deltat
+ end if
+ end if
+
+ ! next limit ice and snow sublimation and rain evaporation
+ ! get estimate of q and t at end of time step
+ ! don't include other microphysical processes since they haven't
+ ! been limited via conservation checks yet
+
+ if ((pre(i,k)+prds(i,k))*cldmax(i,k)+ice_sublim(i,k) < -1.e-20_r8) then
+
+ qtmp=q(i,k)-(ice_sublim(i,k)+vap_dep(i,k)+mnuccd(i,k)+ &
+ (pre(i,k)+prds(i,k))*cldmax(i,k))*deltat
+ ttmp=t(i,k)+((pre(i,k)*cldmax(i,k))*xxlv+ &
+ (prds(i,k)*cldmax(i,k)+vap_dep(i,k)+ice_sublim(i,k)+mnuccd(i,k))*xxls)*deltat/cpp
+
+ ! If the unlimited tendencies are so large that ttmp is
+ ! extremely low, qsat_water may hit a floating point
+ ! exception, so just automatically limit temperatures below
+ ! 50 K to prevent this.
+ if (ttmp <= 50._r8) then
+ limit_precip_evap_sublim = .true.
+ else
+ ! Else, check to see if we are pushing temperature down
+ ! and q up enough to become super-saturated.
+ call qsat_water(ttmp, p(i,k), esn, qvn)
+ limit_precip_evap_sublim = (qtmp > qvn)
+ end if
+
+ ! modify ice/precip evaporation rate if q > qsat
+ if (limit_precip_evap_sublim) then
+
+ dum1=pre(i,k)*cldmax(i,k)/((pre(i,k)+prds(i,k))*cldmax(i,k)+ice_sublim(i,k))
+ dum2=prds(i,k)*cldmax(i,k)/((pre(i,k)+prds(i,k))*cldmax(i,k)+ice_sublim(i,k))
+ ! recalculate q and t after vap_dep and mnuccd but without evap or sublim
+ qtmp=q(i,k)-(vap_dep(i,k)+mnuccd(i,k))*deltat
+ ttmp=t(i,k)+((vap_dep(i,k)+mnuccd(i,k))*xxls)*deltat/cpp
+
+ ! use rhw to allow ice supersaturation
+ call qsat_water(ttmp, p(i,k), esn, qvn)
+
+ dum=(qtmp-qvn)/(1._r8 + cons27*qvn/(cpp*rv*ttmp**2))
+ dum=min(dum,0._r8)
+
+ ! modify rates if needed, divide by cldmax to get local (in-precip) value
+ pre(i,k)=dum*dum1/deltat/cldmax(i,k)
+
+ ! do separately using RHI for prds and ice_sublim
+ call qsat_ice(ttmp, p(i,k), esn, qvn)
+
+ dum=(qtmp-qvn)/(1._r8 + cons28*qvn/(cpp*rv*ttmp**2))
+ dum=min(dum,0._r8)
+
+ ! modify rates if needed, divide by cldmax to get local (in-precip) value
+ prds(i,k) = dum*dum2/deltat/cldmax(i,k)
+
+ ! don't divide ice_sublim by cloud fraction since it is grid-averaged
+ dum1 = (1._r8-dum1-dum2)
+ ice_sublim(i,k) = dum*dum1/deltat
+ end if
+ end if
+
+ !===================================================================
! conservation of nc
!-------------------------------------------------------------------
dum = (nprc1(i,k)+npra(i,k)+nnuccc(i,k)+nnucct(i,k)+ &
npsacws(i,k)-nsubc(i,k))*lcldm(i,k)*deltat
- if (dum.gt.nce) then
- ratio = nce/deltat/((nprc1(i,k)+npra(i,k)+nnuccc(i,k)+nnucct(i,k)+&
+ if (dum.gt.nc(i,k)) then
+ ratio = nc(i,k)/deltat/((nprc1(i,k)+npra(i,k)+nnuccc(i,k)+nnucct(i,k)+&
npsacws(i,k)-nsubc(i,k))*lcldm(i,k))*omsm
nprc1(i,k) = nprc1(i,k)*ratio
@@ -1626,33 +1564,40 @@ subroutine micro_mg_tend ( &
! conservation of qi
!-------------------------------------------------------------------
- dum = ((-mnuccc(i,k)-mnucct(i,k)-msacwi(i,k))*lcldm(i,k)+(prci(i,k)+ &
- prai(i,k))*icldm(i,k))*deltat
-
- if (dum.gt.qie) then
+ dum = ((-mnuccc(i,k)-mnucct(i,k)-mnudep(i,k)-msacwi(i,k))*lcldm(i,k)+(prci(i,k)+ &
+ prai(i,k))*icldm(i,k)-ice_sublim(i,k)-vap_dep(i,k)-berg(i,k)-mnuccd(i,k))*deltat
- ratio = (qie/deltat+(mnuccc(i,k)+mnucct(i,k)+msacwi(i,k))*lcldm(i,k))/ &
- ((prci(i,k)+prai(i,k))*icldm(i,k))*omsm
+ if (dum.gt.qi(i,k)) then
+ ratio = (qi(i,k)/deltat+vap_dep(i,k)+berg(i,k)+mnuccd(i,k)+ &
+ (mnuccc(i,k)+mnucct(i,k)+mnudep(i,k)+msacwi(i,k))*lcldm(i,k))/ &
+ ((prci(i,k)+prai(i,k))*icldm(i,k)-ice_sublim(i,k))*omsm
prci(i,k) = prci(i,k)*ratio
prai(i,k) = prai(i,k)*ratio
+ ice_sublim(i,k) = ice_sublim(i,k)*ratio
end if
! conservation of ni
!-------------------------------------------------------------------
- dum = ((-nnucct(i,k)-nsacwi(i,k))*lcldm(i,k)+(nprci(i,k)+ &
- nprai(i,k)-nsubi(i,k))*icldm(i,k))*deltat
-
- if (dum.gt.nie) then
+ if (use_hetfrz_classnuc) then
+ tmpfrz = nnuccc(i,k)
+ else
+ tmpfrz = 0._r8
+ end if
+ dum = ((-nnucct(i,k)-tmpfrz-nnudep(i,k)-nsacwi(i,k))*lcldm(i,k)+(nprci(i,k)+ &
+ nprai(i,k)-nsubi(i,k))*icldm(i,k)-nnuccd(i,k))*deltat
- ratio = (nie/deltat+(nnucct(i,k)+nsacwi(i,k))*lcldm(i,k))/ &
+ if (dum.gt.ni(i,k)) then
+ ratio = (ni(i,k)/deltat+nnuccd(i,k)+ &
+ (nnucct(i,k)+tmpfrz+nnudep(i,k)+nsacwi(i,k))*lcldm(i,k))/ &
((nprci(i,k)+nprai(i,k)-nsubi(i,k))*icldm(i,k))*omsm
nprci(i,k) = nprci(i,k)*ratio
nprai(i,k) = nprai(i,k)*ratio
nsubi(i,k) = nsubi(i,k)*ratio
end if
+
end if
- ! for precipitation conservation, use logic that vertical integral
+ ! for precipitation conservation, use logic that vertical integral
! of tendency from current level to top of model (i.e., qrtot) cannot be negative
! conservation of rain mixing rat
@@ -1663,7 +1608,7 @@ subroutine micro_mg_tend ( &
if (-pre(i,k)+pracs(i,k)+mnuccr(i,k).ge.qsmall) then
ratio = (qrtot(i)/(dz(i,k)*rho(i,k))+(prc(i,k)+pra(i,k))*lcldm(i,k))/&
- ((-pre(i,k)+pracs(i,k)+mnuccr(i,k))*cldmax(i,k))*omsm
+ ((-pre(i,k)+pracs(i,k)+mnuccr(i,k))*cldmax(i,k))*omsm
pre(i,k) = pre(i,k)*ratio
pracs(i,k) = pracs(i,k)*ratio
@@ -1728,25 +1673,26 @@ subroutine micro_mg_tend ( &
! get tendencies due to microphysical conversion processes
!==========================================================
- ! note: tendencies are multiplied by appropriate cloud/precip
+ ! note: tendencies are multiplied by appropriate cloud/precip
! fraction to get grid-scale values
- ! note: cmei is already grid-average values
+ ! note: vap_dep is already grid-average values
- qvlat(i,k) = qvlat(i,k)-(pre(i,k)+prds(i,k))*cldmax(i,k)-cmei(i,k)
+ qvlat(i,k) = qvlat(i,k)-(pre(i,k)+prds(i,k))*cldmax(i,k)-&
+ vap_dep(i,k)-ice_sublim(i,k)-mnuccd(i,k)-mnudep(i,k)*lcldm(i,k)
tlat(i,k) = tlat(i,k)+((pre(i,k)*cldmax(i,k)) &
- *xxlv+(prds(i,k)*cldmax(i,k)+cmei(i,k))*xxls+ &
+ *xxlv+(prds(i,k)*cldmax(i,k)+vap_dep(i,k)+ice_sublim(i,k)+mnuccd(i,k)+mnudep(i,k)*lcldm(i,k))*xxls+ &
((bergs(i,k)+psacws(i,k)+mnuccc(i,k)+mnucct(i,k)+msacwi(i,k))*lcldm(i,k)+(mnuccr(i,k)+ &
pracs(i,k))*cldmax(i,k)+berg(i,k))*xlf)
qctend(i,k) = qctend(i,k)+ &
- (-pra(i,k)-prc(i,k)-mnuccc(i,k)-mnucct(i,k)-msacwi(i,k)- &
+ (-pra(i,k)-prc(i,k)-mnuccc(i,k)-mnucct(i,k)-msacwi(i,k)- &
psacws(i,k)-bergs(i,k))*lcldm(i,k)-berg(i,k)
if (do_cldice) then
qitend(i,k) = qitend(i,k)+ &
- (mnuccc(i,k)+mnucct(i,k)+msacwi(i,k))*lcldm(i,k)+(-prci(i,k)- &
- prai(i,k))*icldm(i,k)+cmei(i,k)+berg(i,k)
+ (mnuccc(i,k)+mnucct(i,k)+mnudep(i,k)+msacwi(i,k))*lcldm(i,k)+(-prci(i,k)- &
+ prai(i,k))*icldm(i,k)+vap_dep(i,k)+berg(i,k)+ice_sublim(i,k)+mnuccd(i,k)
end if
qrtend(i,k) = qrtend(i,k)+ &
@@ -1757,8 +1703,10 @@ subroutine micro_mg_tend ( &
(prai(i,k)+prci(i,k))*icldm(i,k)+(psacws(i,k)+bergs(i,k))*lcldm(i,k)+(prds(i,k)+ &
pracs(i,k)+mnuccr(i,k))*cldmax(i,k)
+ cmeout(i,k) = cmeout(i,k) + vap_dep(i,k) + ice_sublim(i,k) + mnuccd(i,k)
+
! add output for cmei (accumulate)
- cmeitot(i,k) = cmeitot(i,k) + cmei(i,k)
+ cmeitot(i,k) = cmeitot(i,k) + vap_dep(i,k) + ice_sublim(i,k) + mnuccd(i,k)
! assign variables for trop_mozart, these are grid-average
!-------------------------------------------------------------------
@@ -1766,6 +1714,7 @@ subroutine micro_mg_tend ( &
evapsnow(i,k) = evapsnow(i,k)-prds(i,k)*cldmax(i,k)
nevapr(i,k) = nevapr(i,k)-pre(i,k)*cldmax(i,k)
+ nevapr2(i,k) = nevapr2(i,k)-pre(i,k)*cldmax(i,k)
! change to make sure prain is positive: do not remove snow from
! prain used for wet deposition
@@ -1778,35 +1727,43 @@ subroutine micro_mg_tend ( &
! to rain and snow (1/s), for later use in aerosol wet removal routine
! previously, wetdepa used (prain/qc) for this, and the qc in wetdepa may be smaller than the qc
! used to calculate pra, prc, ... in this routine
- ! qcsinksum_rate1ord = sum over iterations{ rate of direct transfer of cloud water to rain & snow }
+ ! qcsinksum_rate1ord = { rate of direct transfer of cloud water to rain & snow }
! (no cloud ice or bergeron terms)
- ! qcsum_rate1ord = sum over iterations{ qc used in calculation of the transfer terms }
+ ! qcsum_rate1ord = { qc used in calculation of the transfer terms }
- qcsinksum_rate1ord(i,k) = qcsinksum_rate1ord(i,k) + (pra(i,k)+prc(i,k)+psacws(i,k))*lcldm(i,k)
- qcsum_rate1ord(i,k) = qcsum_rate1ord(i,k) + qc(i,k)
+ qcsinksum_rate1ord(i,k) = qcsinksum_rate1ord(i,k) + (pra(i,k)+prc(i,k)+psacws(i,k))*lcldm(i,k)
+ qcsum_rate1ord(i,k) = qcsum_rate1ord(i,k) + qc(i,k)
! microphysics output, note this is grid-averaged
pratot(i,k)=pratot(i,k)+pra(i,k)*lcldm(i,k)
prctot(i,k)=prctot(i,k)+prc(i,k)*lcldm(i,k)
mnuccctot(i,k)=mnuccctot(i,k)+mnuccc(i,k)*lcldm(i,k)
mnuccttot(i,k)=mnuccttot(i,k)+mnucct(i,k)*lcldm(i,k)
- mnuccdtot(i,k)=mnuccdtot(i,k)+mnuccd(i,k)*lcldm(i,k)
msacwitot(i,k)=msacwitot(i,k)+msacwi(i,k)*lcldm(i,k)
psacwstot(i,k)=psacwstot(i,k)+psacws(i,k)*lcldm(i,k)
bergstot(i,k)=bergstot(i,k)+bergs(i,k)*lcldm(i,k)
+
bergtot(i,k)=bergtot(i,k)+berg(i,k)
+
prcitot(i,k)=prcitot(i,k)+prci(i,k)*icldm(i,k)
praitot(i,k)=praitot(i,k)+prai(i,k)*icldm(i,k)
- mnuccrtot(i,k)=mnuccrtot(i,k)+mnuccr(i,k)*cldmax(i,k)
+ mnuccdtot(i,k)=mnuccdtot(i,k)+mnuccd(i,k)*icldm(i,k)
+
pracstot(i,k)=pracstot(i,k)+pracs(i,k)*cldmax(i,k)
+ mnuccrtot(i,k)=mnuccrtot(i,k)+mnuccr(i,k)*cldmax(i,k)
nctend(i,k) = nctend(i,k)+&
- (-nnuccc(i,k)-nnucct(i,k)-npsacws(i,k)+nsubc(i,k) &
+ (-nnuccc(i,k)-nnucct(i,k)-npsacws(i,k)+nsubc(i,k) &
-npra(i,k)-nprc1(i,k))*lcldm(i,k)
if (do_cldice) then
+ if (use_hetfrz_classnuc) then
+ tmpfrz = nnuccc(i,k)
+ else
+ tmpfrz = 0._r8
+ end if
nitend(i,k) = nitend(i,k)+ nnuccd(i,k)+ &
- (nnucct(i,k)+nsacwi(i,k))*lcldm(i,k)+(nsubi(i,k)-nprci(i,k)- &
+ (nnucct(i,k)+tmpfrz+nnudep(i,k)+nsacwi(i,k))*lcldm(i,k)+(nsubi(i,k)-nprci(i,k)- &
nprai(i,k))*icldm(i,k)
end if
@@ -1827,7 +1784,7 @@ subroutine micro_mg_tend ( &
end if
end do
-
+
! End of "administration" loop
! get final values for precipitation q and N, based on
@@ -1976,7 +1933,7 @@ subroutine micro_mg_tend ( &
! if rain/snow mix ratio is zero so should number concentration
!=========================================================
-
+
if (qsic(i,k) < qsmall) then
qsic(i,k)=0._r8
nsic(i,k)=0._r8
@@ -1987,7 +1944,7 @@ subroutine micro_mg_tend ( &
nric(i,k)=0._r8
end if
- ! make sure number concentration is a positive number to avoid
+ ! make sure number concentration is a positive number to avoid
! taking root of negative
nric(i,k)=max(nric(i,k),0._r8)
@@ -2035,12 +1992,11 @@ subroutine micro_mg_tend ( &
end do micro_vert_loop ! end k loop
- ! sum over sub-step for average process rates
!-----------------------------------------------------
- ! convert rain/snow q and N for output to history, note,
+ ! convert rain/snow q and N for output to history, note,
! output is for gridbox average
- ! calculate precip fluxes and adding them to summing sub-stepping variables
+ ! calculate precip fluxes
! calculate the precip flux (kg/m2/s) as mixingratio(kg/kg)*airdensity(kg/m3)*massweightedfallspeed(m/s)
! ---------------------------------------------------------------------
@@ -2061,13 +2017,13 @@ subroutine micro_mg_tend ( &
! Calculate rercld
! calculate mean size of combined rain and cloud water
-
+
! hm 11-22-11 modify to interpolate rain from interface to mid-point
! logic is to interpolate rain mass and number, then recalculate PSD
! parameters to get relevant parameters for mean size
! interpolate rain mass and number, store in dummy variables
-
+
! calculate n0r and lamr from interpolated mid-point rain mass and number
! divide by precip fraction to get in-precip (local) values of
! rain mass and number, divide by rhow to get rain number in kg^-1
@@ -2075,7 +2031,7 @@ subroutine micro_mg_tend ( &
call size_dist_param_rain(dumr, dumnr, lamr, n0r)
call calc_rercld(lamr, n0r, lamc, cdist1, pgam, dumr, qcic, &
- arcld, rercld)
+ rercld)
nsout(:,1) = nsout(:,1) + &
(int_to_mid(:,1)*nsic(:,1)*cldmax(:,1)*rho(:,1))
@@ -2086,116 +2042,25 @@ subroutine micro_mg_tend ( &
sflx(:,2:) = sflx(:,2:) + (qsic*rho*ums*cldmax)
- ! Sum into other variables that accumulate over substeps.
- tlat1 = tlat1 + tlat
- t = t + tlat*deltat/cpp
-
- qvlat1 = qvlat1 + qvlat
- q = q + qvlat*deltat
-
- qctend1 = qctend1 + qctend
- qc = qc + qctend*deltat
-
- qitend1 = qitend1 + qitend
- qi = qi + qitend*deltat
-
- nctend1 = nctend1 + nctend
- nc = nc + nctend*deltat
-
- nitend1 = nitend1 + nitend
- ni = ni + nitend*deltat
-
- prect1 = prect1 + prect
- preci1 = preci1 + preci
-
- end do substepping ! it loop, sub-step
-
- ! divide rain radius over substeps for average
- where (arcld > 0) rercld = rercld/arcld
-
- ! convert dt from sub-step back to full time step
- !-------------------------------------------------------------------
- deltat = deltatin
-
- ! assign variables back to start-of-timestep values before updating after sub-steps
+ ! assign variables back to start-of-timestep values
+ !hm note: only nc is modified above (droplet activation tendency is added on)
+ !hm thus only nc needs to be assigned to start-of-timestep values
!================================================================================
-
- call pack_array(qn, mgcols, top_lev, q)
- call pack_array(tn, mgcols, top_lev, t)
- call pack_array(qcn, mgcols, top_lev, qc)
- call pack_array(ncn, mgcols, top_lev, nc)
- call pack_array(qin, mgcols, top_lev, qi)
- call pack_array(nin, mgcols, top_lev, ni)
- !.............................................................................
+ nc = ncn
- ! divide precip rate by number of sub-steps to get average over time step
-
- prect = prect1/real(iter)
- preci = preci1/real(iter)
+ !.............................................................................
- ! divide microphysical tendencies by number of sub-steps to get average over time step
!================================================================================
- tlat = tlat1/real(iter)
- qvlat = qvlat1/real(iter)
- qctend = qctend1/real(iter)
- qitend = qitend1/real(iter)
- nctend = nctend1/real(iter)
- nitend = nitend1/real(iter)
-
! Re-apply droplet activation tendency
nctend = nctend + npccn
- rainrt = rainrt/real(iter)
-
- ! divide by number of sub-steps to find final values
- rflx = rflx/real(iter)
- sflx = sflx/real(iter)
-
- ! divide output precip q and N by number of sub-steps to get average over time step
- !================================================================================
-
- qrout = qrout/real(iter)
- qsout = qsout/real(iter)
- nrout = nrout/real(iter)
- nsout = nsout/real(iter)
-
- ! divide trop_mozart variables by number of sub-steps to get average over time step
- !================================================================================
-
- nevapr = nevapr/real(iter)
- evapsnow = evapsnow/real(iter)
- prain = prain/real(iter)
- prodsnow = prodsnow/real(iter)
-
! modify to include snow. in prain & evap (diagnostic here: for wet dep)
nevapr = nevapr + evapsnow
+ prer_evap = nevapr2
prain = prain + prodsnow
- cmeout = cmeout/real(iter)
-
- cmeitot = cmeitot/real(iter)
- meltsdttot = meltsdttot/real(iter)
- frzrdttot = frzrdttot /real(iter)
-
- ! microphysics output
- pratot=pratot/real(iter)
- prctot=prctot/real(iter)
- mnuccctot=mnuccctot/real(iter)
- mnuccttot=mnuccttot/real(iter)
- msacwitot=msacwitot/real(iter)
- psacwstot=psacwstot/real(iter)
- bergstot=bergstot/real(iter)
- bergtot=bergtot/real(iter)
- prcitot=prcitot/real(iter)
- praitot=praitot/real(iter)
-
- mnuccrtot=mnuccrtot/real(iter)
- pracstot =pracstot /real(iter)
-
- mnuccdtot=mnuccdtot/real(iter)
-
sed_col_loop: do i=1,mgncol
do k=1,nlev
@@ -2203,7 +2068,7 @@ subroutine micro_mg_tend ( &
! calculate sedimentation for cloud water and ice
!================================================================================
- ! update in-cloud cloud mixing ratio and number concentration
+ ! update in-cloud cloud mixing ratio and number concentration
! with microphysical tendencies to calculate sedimentation, assign to dummy vars
! note: these are in-cloud values***, hence we divide by cloud fraction
@@ -2376,7 +2241,7 @@ subroutine micro_mg_tend ( &
end do !! k loop
! units below are m/s
- ! cloud water/ice sedimentation flux at surface
+ ! cloud water/ice sedimentation flux at surface
! is added to precip flux at surface to get total precip (cloud + precip water)
! rate
@@ -2478,7 +2343,7 @@ subroutine micro_mg_tend ( &
end if
end if
- ! remove any excess over-saturation, which is possible due to non-linearity when adding
+ ! remove any excess over-saturation, which is possible due to non-linearity when adding
! together all microphysical processes
!-----------------------------------------------------------------
! follow code similar to old CAM scheme
@@ -2487,12 +2352,12 @@ subroutine micro_mg_tend ( &
ttmp=t(i,k)+tlat(i,k)/cpp*deltat
! use rhw to allow ice supersaturation
- call qsat_water(ttmp, p(i,k), esn, qsn)
- qsn = min(qsn,1._r8)
+ call qsat_water(ttmp, p(i,k), esn, qvn)
+ qvn = min(qvn,1._r8)
- if (qtmp > qsn .and. qsn > 0) then
+ if (qtmp > qvn .and. qvn > 0) then
! expression below is approximate since there may be ice deposition
- dum = (qtmp-qsn)/(1._r8+cons27*qsn/(cpp*rv*ttmp**2))/deltat
+ dum = (qtmp-qvn)/(1._r8+cons27*qvn/(cpp*rv*ttmp**2))/deltat
! add to output cme
cmeout(i,k) = cmeout(i,k)+dum
! now add to tendencies, partition between liquid and ice based on temperature
@@ -2506,8 +2371,8 @@ subroutine micro_mg_tend ( &
dum1=(268.15_r8-ttmp)/30._r8
end if
- dum = (qtmp-qsn)/(1._r8+(xxls*dum1+xxlv*(1._r8-dum1))**2 &
- *qsn/(cpp*rv*ttmp**2))/deltat
+ dum = (qtmp-qvn)/(1._r8+(xxls*dum1+xxlv*(1._r8-dum1))**2 &
+ *qvn/(cpp*rv*ttmp**2))/deltat
qctend(i,k)=qctend(i,k)+dum*(1._r8-dum1)
! for output
qcrestot(i,k)=dum*(1._r8-dum1)
@@ -2591,7 +2456,7 @@ subroutine micro_mg_tend ( &
nctend(i,k)=(ncnst/rho(i,k)*lcldm(i,k)-nc(i,k))/deltat
- end if
+ end if
dum = dumnc(i,k)
@@ -2639,6 +2504,7 @@ subroutine micro_mg_tend ( &
!=================================================================================
if (qc(i,k)+qctend(i,k)*deltat.lt.qsmall) nctend(i,k)=-nc(i,k)/deltat
if (do_cldice .and. qi(i,k)+qitend(i,k)*deltat.lt.qsmall) nitend(i,k)=-ni(i,k)/deltat
+
end do
end do sed_col_loop! i loop
@@ -2667,10 +2533,10 @@ subroutine micro_mg_tend ( &
nrout2 = nrout * cldmax
! The avg_diameter call does the actual calculation; other diameter
! outputs are just drout2 times constants.
- drout2 = avg_diameter(qrout, nrout, rho, rhow) * cldmax
+ drout2 = avg_diameter(qrout, nrout, rho, rhow)
freqr = cldmax
- reff_rain=1.5_r8*drout2*1.e6_r8
+ reff_rain=1.5_r8*drout2*1.e6_r8
elsewhere
qrout2 = 0._r8
nrout2 = 0._r8
@@ -2690,8 +2556,6 @@ subroutine micro_mg_tend ( &
dsout=3._r8*rhosn/917._r8*dsout2
- dsout2 = dsout2 * cldmax
-
reff_snow=1.5_r8*dsout2*1.e6_r8
elsewhere
dsout = 0._r8
@@ -2718,7 +2582,7 @@ subroutine micro_mg_tend ( &
end if
if (qi(i,k).ge.qsmall) then
dum1=(qi(i,k)*rho(i,k)/icldm(i,k)*1000._r8/0.1_r8)**(1._r8/0.63_r8)*icldm(i,k)/cldmax(i,k)
- else
+ else
dum1=0._r8
end if
@@ -2751,16 +2615,16 @@ subroutine micro_mg_tend ( &
!output reflectivity in Z.
areflz(i,k)=refl(i,k) * cldmax(i,k)
- ! convert back to DBz
+ ! convert back to DBz
- if (refl(i,k).gt.minrefl) then
+ if (refl(i,k).gt.minrefl) then
refl(i,k)=10._r8*log10(refl(i,k))
else
refl(i,k)=-9999._r8
end if
!set averaging flag
- if (refl(i,k).gt.mindbz) then
+ if (refl(i,k).gt.mindbz) then
arefl(i,k)=refl(i,k) * cldmax(i,k)
frefl(i,k)=cldmax(i,k)
else
@@ -2774,7 +2638,7 @@ subroutine micro_mg_tend ( &
csrfl(i,k)=min(csmax,refl(i,k))
!set averaging flag
- if (csrfl(i,k).gt.csmin) then
+ if (csrfl(i,k).gt.csmin) then
acsrfl(i,k)=refl(i,k) * cldmax(i,k)
fcsrfl(i,k)=cldmax(i,k)
else
@@ -2794,111 +2658,9 @@ subroutine micro_mg_tend ( &
nfice=0._r8
end where
- ! Unpack all outputs
-
! Avoid zero/near-zero division.
qcsinksum_rate1ord = qcsinksum_rate1ord/max(qcsum_rate1ord,1.0e-30_r8)
- call unpack_array(qcsinksum_rate1ord, mgcols, top_lev, 0._r8, rate1ord_cw2pr_st)
-
- call unpack_array(tlat, mgcols, top_lev, 0._r8, tlato)
- call unpack_array(qvlat, mgcols, top_lev, 0._r8, qvlato)
-
- call unpack_array(qctend, mgcols, top_lev, 0._r8, qctendo)
- call unpack_array(qitend, mgcols, top_lev, 0._r8, qitendo)
-
- ! Note that where there is no water, we set nctend and nitend to remove number
- ! concentration as well.
- call unpack_array(nctend, mgcols, top_lev, -ncn/deltat, nctendo)
- if (do_cldice) then
- call unpack_array(nitend, mgcols, top_lev, -nin/deltat, nitendo)
- else
- call unpack_array(nitend, mgcols, top_lev, 0._r8, nitendo)
- end if
-
- call unpack_array(effc, mgcols, top_lev, 10._r8, effco)
- call unpack_array(effc_fn, mgcols, top_lev, 10._r8, effco_fn)
- call unpack_array(effi, mgcols, top_lev, 25._r8, effio)
-
- call unpack_array(prect, mgcols, 0._r8, precto)
- call unpack_array(preci, mgcols, 0._r8, precio)
-
- call unpack_array(nevapr, mgcols, top_lev, 0._r8, nevapro)
- call unpack_array(evapsnow, mgcols, top_lev, 0._r8, evapsnowo)
- call unpack_array(prain, mgcols, top_lev, 0._r8, praino)
- call unpack_array(prodsnow, mgcols, top_lev, 0._r8, prodsnowo)
- call unpack_array(cmeout, mgcols, top_lev, 0._r8, cmeouto)
-
- call unpack_array(lamcrad, mgcols, top_lev, 0._r8, lamcrado)
- call unpack_array(pgamrad, mgcols, top_lev, 0._r8, pgamrado)
- call unpack_array(deffi, mgcols, top_lev, 0._r8, deffio)
-
- call unpack_array(qsout, mgcols, top_lev, 0._r8, qsouto)
- call unpack_array(qsout2, mgcols, top_lev, 0._r8, qsouto2)
- call unpack_array(nsout, mgcols, top_lev, 0._r8, nsouto)
- call unpack_array(nsout2, mgcols, top_lev, 0._r8, nsouto2)
- call unpack_array(dsout, mgcols, top_lev, 0._r8, dsouto)
- call unpack_array(dsout2, mgcols, top_lev, 0._r8, dsouto2)
-
- call unpack_array(qrout, mgcols, top_lev, 0._r8, qrouto)
- call unpack_array(qrout2, mgcols, top_lev, 0._r8, qrouto2)
- call unpack_array(nrout, mgcols, top_lev, 0._r8, nrouto)
- call unpack_array(nrout2, mgcols, top_lev, 0._r8, nrouto2)
- call unpack_array(drout2, mgcols, top_lev, 0._r8, drouto2)
-
- call unpack_array(reff_rain, mgcols, top_lev, 0._r8, reff_raino)
- call unpack_array(reff_snow, mgcols, top_lev, 0._r8, reff_snowo)
-
- call unpack_array(freqs, mgcols, top_lev, 0._r8, freqso)
- call unpack_array(freqr, mgcols, top_lev, 0._r8, freqro)
-
- call unpack_array(rflx, mgcols, top_lev, 0._r8, rflxo)
- call unpack_array(sflx, mgcols, top_lev, 0._r8, sflxo)
-
- call unpack_array(qcsevap, mgcols, top_lev, 0._r8, qcsevapo)
- call unpack_array(qisevap, mgcols, top_lev, 0._r8, qisevapo)
- call unpack_array(qvres, mgcols, top_lev, 0._r8, qvreso)
- call unpack_array(cmeitot, mgcols, top_lev, 0._r8, cmeiout)
- call unpack_array(vtrmc, mgcols, top_lev, 0._r8, vtrmco)
- call unpack_array(vtrmi, mgcols, top_lev, 0._r8, vtrmio)
- call unpack_array(qcsedten, mgcols, top_lev, 0._r8, qcsedteno)
- call unpack_array(qisedten, mgcols, top_lev, 0._r8, qisedteno)
-
- call unpack_array(pratot, mgcols,top_lev, 0._r8, prao)
- call unpack_array(prctot, mgcols,top_lev, 0._r8, prco)
- call unpack_array(mnuccctot, mgcols,top_lev, 0._r8, mnuccco)
- call unpack_array(mnuccttot, mgcols,top_lev, 0._r8, mnuccto)
- call unpack_array(msacwitot, mgcols,top_lev, 0._r8, msacwio)
- call unpack_array(psacwstot, mgcols,top_lev, 0._r8, psacwso)
- call unpack_array(bergstot, mgcols,top_lev, 0._r8, bergso)
- call unpack_array(bergtot, mgcols,top_lev, 0._r8, bergo)
- call unpack_array(melttot, mgcols,top_lev, 0._r8, melto)
- call unpack_array(homotot, mgcols,top_lev, 0._r8, homoo)
- call unpack_array(qcrestot, mgcols,top_lev, 0._r8, qcreso)
- call unpack_array(prcitot, mgcols,top_lev, 0._r8, prcio)
- call unpack_array(praitot, mgcols,top_lev, 0._r8, praio)
- call unpack_array(qirestot, mgcols,top_lev, 0._r8, qireso)
- call unpack_array(mnuccrtot, mgcols,top_lev, 0._r8, mnuccro)
- call unpack_array(pracstot, mgcols,top_lev, 0._r8, pracso)
- call unpack_array(mnuccdtot, mgcols,top_lev, 0._r8, mnuccdo)
- call unpack_array(meltsdttot, mgcols,top_lev, 0._r8, meltsdto)
- call unpack_array(frzrdttot, mgcols,top_lev, 0._r8, frzrdto)
-
- call unpack_array(refl, mgcols, top_lev, -9999._r8, reflo)
- call unpack_array(arefl, mgcols, top_lev, 0._r8, areflo)
- call unpack_array(areflz, mgcols, top_lev, 0._r8, areflzo)
- call unpack_array(frefl, mgcols, top_lev, 0._r8, freflo)
- call unpack_array(csrfl, mgcols, top_lev, -9999._r8, csrflo)
- call unpack_array(acsrfl, mgcols, top_lev, 0._r8, acsrflo)
- call unpack_array(fcsrfl, mgcols, top_lev, 0._r8, fcsrflo)
-
- call unpack_array(rercld, mgcols, top_lev, 0._r8, rercldo)
-
- call unpack_array(nfice, mgcols, top_lev, 0._r8, nficeo)
-
- call unpack_array(ncai, mgcols, top_lev, 0._r8, ncaio)
- call unpack_array(ncal, mgcols, top_lev, 0._r8, ncalo)
-
end subroutine micro_mg_tend
!========================================================================
@@ -3009,7 +2771,6 @@ elemental subroutine size_dist_param_ice(qiic, niic, lami, n0i)
! local parameters
real(r8), parameter :: lammaxi = 1._r8/10.e-6_r8
-
real(r8) :: lammini
lammini = 1._r8/(2._r8*dcs)
@@ -3021,7 +2782,7 @@ elemental subroutine size_dist_param_ice(qiic, niic, lami, n0i)
lami = (cons1*ci*niic/qiic)**(1._r8/dsph)
n0i = niic * lami
-
+
! check for slope
! adjust vars
if (lami < lammini) then
@@ -3066,7 +2827,7 @@ elemental subroutine size_dist_param_rain(qric, nric, lamr, n0r)
lamr = (cr*nric/qric)**(1._r8/3._r8)
n0r = nric * lamr
-
+
! check for slope
! adjust vars
@@ -3109,7 +2870,7 @@ elemental subroutine size_dist_param_snow(qsic, nsic, lams, n0s)
lams = (cons1*cs*nsic/qsic)**(1._r8/dsph)
n0s = nsic * lams
-
+
! check for slope
! adjust vars
if (lams < lammins) then
@@ -3121,7 +2882,7 @@ elemental subroutine size_dist_param_snow(qsic, nsic, lams, n0s)
n0s = lams**(dsph+1._r8) * qsic/(cs*cons1)
nsic = n0s/lams
end if
-
+
else
lams = 0._r8
n0s = 0._r8
@@ -3132,8 +2893,9 @@ end subroutine size_dist_param_snow
real(r8) elemental function avg_diameter(q, n, rho_air, rho_sub)
! Finds the average diameter of particles given their density, and
! mass/number concentrations in the air.
+ ! Assumes that diameter follows an exponential distribution.
real(r8), intent(in) :: q ! mass mixing ratio
- real(r8), intent(in) :: n ! number concentration
+ real(r8), intent(in) :: n ! number concentration (per volume)
real(r8), intent(in) :: rho_air ! local density of the air
real(r8), intent(in) :: rho_sub ! density of the particle substance
@@ -3158,193 +2920,89 @@ end function var_coef
!========================================================================
! Initial ice deposition and sublimation loop.
! Run before the main loop
+! This subroutine written by Peter Caldwell
-elemental subroutine ice_deposition_sublimation_init(deltat, t, q, qc, qi, ni, &
- lcldm, icldm, naai, rho, dv, &
- esl, esi, qvl, qvi, relhum, &
- berg, cmei)
+elemental subroutine ice_deposition_sublimation(deltat, t, qv, qc, qi, ni, lcldm, &
+ icldm, naai, rho, dv,qvl, qvi, &
+ berg, vap_dep, ice_sublim)
- ! Inputs
+ !INPUT VARS:
+ !===============================================
real(r8), intent(in) :: deltat
-
real(r8), intent(in) :: t
- real(r8), intent(in) :: q
-
+ real(r8), intent(in) :: qv
real(r8), intent(in) :: qc
real(r8), intent(in) :: qi
real(r8), intent(in) :: ni
-
real(r8), intent(in) :: lcldm
real(r8), intent(in) :: icldm
-
real(r8), intent(in) :: naai
real(r8), intent(in) :: rho
real(r8), intent(in) :: dv
-
- real(r8), intent(in) :: esl
- real(r8), intent(in) :: esi
real(r8), intent(in) :: qvl
real(r8), intent(in) :: qvi
- real(r8), intent(in) :: relhum
-
- ! Outputs
- real(r8), intent(out) :: berg
- real(r8), intent(out) :: cmei
-
- ! Internal variables
+ !OUTPUT VARS:
+ !===============================================
+ real(r8), intent(out) :: vap_dep !ice deposition (cell-ave value)
+ real(r8), intent(out) :: ice_sublim !ice sublimation (cell-ave value)
+ real(r8), intent(out) :: berg !bergeron enhancement (cell-ave value)
+ !INTERNAL VARS:
+ !===============================================
+ real(r8) :: ab
+ real(r8) :: epsi
real(r8) :: qiic
real(r8) :: niic
-
- real(r8) :: prd ! provisional deposition rate of cloud ice at water sat
- real(r8) :: bergtsf ! bergeron timescale to remove all liquid
- real(r8) :: rhin ! modified RH for vapor deposition
-
- real(r8) :: epsi ! 1/sat relaxation timescale for ice
-
- real(r8) :: ab
+ real(r8) :: dum
real(r8) :: lami
real(r8) :: n0i
- real(r8) :: dum
-
- ! initialize bergeron process to zero
- berg = 0._r8
-
- ! Initialize CME components
- cmei = 0._r8
-
- if (t < icenuct) then
- ! provisional nucleation rate
- dum = max((naai - ni/icldm)/deltat*icldm,0._r8)
- else
- dum = 0._r8
- end if
- ! get in-cloud qi and ni after nucleation
- qiic = (qi + dum*deltat*mi0)/icldm
- niic = (ni + dum*deltat)/icldm
-
- ! hm add 6/2/11 switch for specification of cloud ice number
- if (nicons) niic = ninst/rho
- !ICE DEPOSITION:
- !=============================================
- !if ice exists
- if (t < tmelt .and. qi >= qsmall) then
+ if (qi>=qsmall) then
- ab = calc_ab(t, qvi, xxls)
+ !GET IN-CLOUD qi, ni
+ !===============================================
+ qiic = qi/icldm
+ niic = ni/icldm
- ! get ice size distribution parameters
+ !Compute linearized condensational heating correction
+ ab=calc_ab(t, qvi, xxls)
+ !Get slope and intercept of gamma distn for ice.
call size_dist_param_ice(qiic, niic, lami, n0i)
-
+ !Get depletion timescale=1/eps
epsi = 2._r8*pi*n0i*rho*Dv/(lami*lami)
-
- !if liquid exists
- if (qc >= qsmall) then
-
- ! calculate Bergeron process
- berg = epsi*(qvl-qvi)/ab
-
- ! multiply by cloud fraction
- berg = berg*min(icldm,lcldm)
-
- ! Must be positive
- if (berg <= 0._r8) then
- berg = 0._r8
- else
- !BERGERON LIMITING WHEN ALL LIQUID DEPLETED IN 1 TIMESTEP
- !-------------------------------------------------------------
-
- bergtsf = (qc/berg) / deltat ! bergeron time scale (fraction of timestep)
-
- if (bergtsf < 1._r8) then
- berg = qc/deltat
-
- rhin = (1.0_r8 + relhum) / 2._r8
- !assume RH for frac of step w/ no liq is 1/2 way btwn cldy & cell-ave RH.
-
- if ((rhin*esl/esi) > 1._r8) then !if ice saturated (but all liquid evap'd)
- prd = epsi*(rhin*qvl-qvi)/ab
-
- ! multiply by cloud fraction assuming liquid/ice maximum overlap
- prd = prd*min(icldm,lcldm)
-
- ! add to cmei
- cmei = cmei + (prd * (1._r8- bergtsf))
- end if ! rhin
-
- end if
-
- end if
- end if
+ !Compute deposition/sublimation
+ vap_dep = epsi/ab*(qv - qvi)
+
+ !Make this a grid-averaged quantity
+ vap_dep=vap_dep*icldm
- !Ice deposition in frac of cell with no liquid
- !-------------------------------------------------------------
- ! store liquid cloud fraction in 'dum'
- if (qc >= qsmall) then
- dum = lcldm
+ !Split into deposition or sublimation.
+ if (t<273.15_r8 .and. vap_dep>0._r8) then
+ ice_sublim=0._r8
else
- ! for case of no liquid, need to set liquid cloud fraction to zero
- dum = 0._r8
+ !hm, make ice_sublim negative for consistency with other evap/sub processes
+ ice_sublim=min(vap_dep,0._r8)
+ vap_dep=0._r8
end if
- if (icldm > dum) then
-
- ! set RH to grid-mean value for pure ice cloud
- rhin = relhum
-
- if ((rhin*esl/esi) > 1._r8) then !if rh over ice>ice saturation.
-
- prd = epsi*(rhin*qvl-qvi)/ab
-
- ! multiply by relevant cloud fraction for pure ice cloud
- ! assuming maximum overlap of liquid/ice
- prd = prd*(icldm-dum) !apply to ice-only part of cld.
- cmei = cmei + prd
-
- end if ! rhin
- end if ! qc or icldm > lcldm
-
- !if grid-mean is ice saturated & qi formed in non-liq cld part,
- !limit ice formation to avoid mean becoming undersaturated.
- !-------------------------------------------------------------
- if(cmei > 0.0_r8 .and. (relhum*esl/esi) > 1._r8 ) &
- ! max berg is val which removes all ice supersaturation from vapor phase.
- cmei=min(cmei,(q-qvl*esi/esl)/ab/deltat)
-
- end if ! end ice exists and t < tmelt
-
- !ICE SUBLIMATION:
- !=========================================
- !If ice-subsaturated and ice exists:
-
- if ((relhum*esl/esi) < 1._r8 .and. qiic >= qsmall ) then
+ !sublimation occurs @ any T. Not so for berg.
+ if (T<273.15_r8) then
- ab = calc_ab(t, qvi, xxls)
+ !Compute bergeron rate assuming cloud for whole step.
+ berg = max(epsi/ab*(qvl - qvi), 0._r8)
+ else !T>frz
+ berg=0._r8
+ end if !Tqsmall
- epsi = 2._r8*pi*n0i*rho*Dv/(lami*lami)
-
- ! modify for ice fraction below
- prd = epsi*(relhum*qvl-qvi)/ab * icldm
- cmei=min(prd,0._r8)
-
- endif !subsaturated and ice exists
-
- ! sublimation should not exceed available ice
- cmei = max(cmei, -qi/deltat)
-
- ! sublimation should not increase grid mean rhi above 1.0
- if(cmei < 0.0_r8 .and. (relhum*esl/esi) < 1._r8 ) &
- cmei=min(0._r8,max(cmei,(q-qvl*esi/esl)/ab/deltat))
-
- ! limit cmei due for roundoff error
- cmei = cmei*omsm
-
-end subroutine ice_deposition_sublimation_init
+end subroutine ice_deposition_sublimation
!========================================================================
! autoconversion of cloud liquid water to rain
@@ -3353,7 +3011,7 @@ end subroutine ice_deposition_sublimation_init
elemental subroutine kk2000_liq_autoconversion(qcic, ncic, rho, relvar, &
prc, nprc, nprc1)
-
+
real(r8), intent(in) :: qcic
real(r8), intent(in) :: ncic
real(r8), intent(in) :: rho
@@ -3379,11 +3037,11 @@ elemental subroutine kk2000_liq_autoconversion(qcic, ncic, rho, relvar, &
! nprc is increase in rain number conc due to autoconversion
! nprc1 is decrease in cloud droplet conc due to autoconversion
-
+
! assume exponential sub-grid distribution of qc, resulting in additional
! factor related to qcvar below
! hm switch for sub-columns, don't include sub-grid qc
-
+
prc = prc_coef * &
1350._r8 * qcic**2.47_r8 * (ncic/1.e6_r8*rho)**(-1.79_r8)
nprc = prc/nprc_denom
@@ -3407,7 +3065,7 @@ elemental subroutine ice_autoconversion(t, qiic, lami, n0i, prci, nprci)
real(r8), intent(in) :: qiic
real(r8), intent(in) :: lami
real(r8), intent(in) :: n0i
-
+
real(r8), intent(out) :: prci
real(r8), intent(out) :: nprci
@@ -3419,7 +3077,7 @@ elemental subroutine ice_autoconversion(t, qiic, lami, n0i, prci, nprci)
prci = pi*rhoi*n0i/(6._r8*180._r8)* &
(cons23/lami+3._r8*cons24/lami**2+ &
- 6._r8*dcs/lami**3+6._r8/lami**4)*exp(-lami*dcs)
+ 6._r8*dcs/lami**3+6._r8/lami**4)*exp(-lami*dcs)
else
prci=0._r8
@@ -3444,14 +3102,14 @@ elemental subroutine immersion_freezing(t, pgam, lamc, cdist1, qcic, &
! MMR of in-cloud liquid water
real(r8), intent(in) :: qcic
-
+
! Relative variance of cloud water
real(r8), intent(in) :: relvar
! Output tendencies
real(r8), intent(out) :: mnuccc ! MMR
real(r8), intent(out) :: nnuccc ! Number
-
+
! Coefficients that will be omitted for sub-columns
real(r8) :: dum, dum1
@@ -3488,7 +3146,7 @@ end subroutine immersion_freezing
pure subroutine contact_freezing (t, p, rndst, nacon, pgam, lamc, cdist1, qcic, &
relvar, mnucct, nnucct)
-
+
real(r8), intent(in) :: t(:) ! Temperature
real(r8), intent(in) :: p(:) ! Pressure
real(r8), intent(in) :: rndst(:,:) ! Radius (for multiple dust bins)
@@ -3501,7 +3159,7 @@ pure subroutine contact_freezing (t, p, rndst, nacon, pgam, lamc, cdist1, qcic,
! MMR of in-cloud liquid water
real(r8), intent(in) :: qcic(:)
-
+
! Relative cloud water variance
real(r8), intent(in) :: relvar(:)
@@ -3659,7 +3317,7 @@ elemental subroutine accrete_cloud_water_snow(t, rho, asn, uns, mu, qcic, ncic,
end subroutine accrete_cloud_water_snow
-! add secondary ice production due to accretion of droplets by snow
+! add secondary ice production due to accretion of droplets by snow
!===================================================================
! (Hallet-Mossop process) (from Cotton et al., 1986)
@@ -3795,7 +3453,7 @@ elemental subroutine accrete_cloud_water_rain(qric, qcic, ncic, &
! Cloud droplets
real(r8), intent(in) :: qcic ! MMR
real(r8), intent(in) :: ncic ! Number
-
+
! SGS variability
real(r8), intent(in) :: relvar
real(r8), intent(in) :: accre_enhan
@@ -3870,7 +3528,7 @@ elemental subroutine accrete_cloud_ice_snow(t, rho, asn, qiic, niic, qsic, &
! Snow size parameters
real(r8), intent(in) :: lams
- real(r8), intent(in) :: n0s
+ real(r8), intent(in) :: n0s
! Output tendencies
real(r8), intent(out) :: prai ! MMR
@@ -3897,7 +3555,8 @@ end subroutine accrete_cloud_ice_snow
! except for transfer of cloud water to snow through bergeron process
elemental subroutine evaporate_sublimate_precip(deltat, t, p, rho, dv, mu, sc, q, qvl, qvi, &
- lcldm, cldmax, arn, asn, qcic, qiic, qric, qsic, lamr, n0r, lams, n0s, cmei, pre, prds)
+ lcldm, cldmax, arn, asn, qcic, qiic, qric, qsic, lamr, n0r, lams, n0s, &
+ pre, prds)
real(r8), intent(in) :: deltat ! timestep
@@ -3931,16 +3590,13 @@ elemental subroutine evaporate_sublimate_precip(deltat, t, p, rho, dv, mu, sc, q
real(r8), intent(in) :: lams
real(r8), intent(in) :: n0s
- ! cloud ice sublimation/deposition tendency
- real(r8), intent(in) :: cmei
-
! Output tendencies
real(r8), intent(out) :: pre
real(r8), intent(out) :: prds
! checking for RH after rain evap
real(r8) :: esn ! saturation pressure
- real(r8) :: qsn ! saturation humidity
+ real(r8) :: qvn ! saturation humidity
real(r8) :: qclr ! water vapor mixing ratio in clear air
real(r8) :: ab ! correction to account for latent heat
@@ -3966,8 +3622,8 @@ elemental subroutine evaporate_sublimate_precip(deltat, t, p, rho, dv, mu, sc, q
if (cldmax > dum) then
! calculate q for out-of-cloud region
- qsn = min(qvl,1._r8)
- qclr=(q-dum*qsn)/(1._r8-dum)
+ qvn = min(qvl,1._r8)
+ qclr=(q-dum*qvn)/(1._r8-dum)
! evaporation of rain
if (qric.ge.qsmall) then
@@ -4006,50 +3662,6 @@ elemental subroutine evaporate_sublimate_precip(deltat, t, p, rho, dv, mu, sc, q
prds = 0._r8
end if
- ! make sure RH not pushed above 100% due to rain evaporation/snow sublimation
- ! get updated RH at end of time step based on cloud water/ice condensation/evap
-
- qtmp=q-(cmei+(pre+prds)*cldmax)*deltat
- ttmp=t+((pre*cldmax)*xxlv+ &
- (cmei+prds*cldmax)*xxls)*deltat/cpp
-
- !limit range of temperatures!
- ttmp=max(180._r8,min(ttmp,323._r8))
-
- ! use rhw to allow ice supersaturation
- call qsat_water(ttmp, p, esn, qsn)
- qsn=min(qsn,1._r8)
-
- ! modify precip evaporation rate if q > qsat
- if (qtmp.gt.qsn) then
- if (pre+prds.lt.-1.e-20_r8) then
- dum1=pre/(pre+prds)
- ! recalculate q and t after cloud water cond but without precip evap
- qtmp=q-(cmei)*deltat
- ttmp=t+(cmei*xxls)*deltat/cpp
- ! use rhw to allow ice supersaturation
- call qsat_water(ttmp, p, esn, qsn)
- qsn=min(qsn,1._r8)
-
- dum=(qtmp-qsn)/(1._r8 + cons27*qsn/(cpp*rv*ttmp**2))
- dum=min(dum,0._r8)
-
- ! modify rates if needed, divide by cldmax to get local (in-precip) value
- pre=dum*dum1/deltat/cldmax
-
- ! do separately using RHI for prds....
- ! use rhi to allow ice supersaturation
- call qsat_ice(ttmp, p, esn, qsn)
- qsn=min(qsn,1._r8)
-
- dum=(qtmp-qsn)/(1._r8 + cons28*qsn/(cpp*rv*ttmp**2))
- dum=min(dum,0._r8)
-
- ! modify rates if needed, divide by cldmax to get local (in-precip) value
- prds=dum*(1._r8-dum1)/deltat/cldmax
- end if
- end if
-
else
prds = 0._r8
pre = 0._r8
@@ -4060,7 +3672,7 @@ end subroutine evaporate_sublimate_precip
! bergeron process - evaporation of droplets and deposition onto snow
!===================================================================
-elemental subroutine bergeron_process(t, rho, dv, mu, sc, qvl, qvi, asn, &
+elemental subroutine bergeron_process_snow(t, rho, dv, mu, sc, qvl, qvi, asn, &
qcic, qsic, lams, n0s, bergs)
real(r8), intent(in) :: t ! temperature
@@ -4100,14 +3712,14 @@ elemental subroutine bergeron_process(t, rho, dv, mu, sc, qvl, qvi, asn, &
bergs = 0._r8
end if
-end subroutine bergeron_process
+end subroutine bergeron_process_snow
!========================================================================
!OUTPUT CALCULATIONS
!========================================================================
elemental subroutine calc_rercld(lamr, n0r, lamc, cdist1, pgam, dumr, qcic, &
- arcld, rercld)
+ rercld)
real(r8), intent(in) :: lamr ! rain size parameter (slope)
real(r8), intent(in) :: n0r ! rain size parameter (intercept)
real(r8), intent(in) :: lamc ! size distribution parameter (slope)
@@ -4116,7 +3728,6 @@ elemental subroutine calc_rercld(lamr, n0r, lamc, cdist1, pgam, dumr, qcic, &
real(r8), intent(in) :: dumr ! in-cloud rain mass mixing ratio
real(r8), intent(in) :: qcic ! in-cloud cloud liquid
- integer, intent(inout) :: arcld ! number of substeps rercld has been through
real(r8), intent(inout) :: rercld ! effective radius calculation for rain + cloud
! combined size of precip & cloud drops
@@ -4136,7 +3747,6 @@ elemental subroutine calc_rercld(lamr, n0r, lamc, cdist1, pgam, dumr, qcic, &
if (Atmp > 0._r8) then
rercld = rercld + 3._r8 *(dumr + qcic) / (4._r8 * rhow * Atmp)
- arcld = arcld+1
end if
end subroutine calc_rercld
@@ -4178,7 +3788,7 @@ pure subroutine micro_mg_get_cols(ncol, nlev, top_lev, qcn, qin, &
ltrue = ltrue .or. any(qin(:ncol,top_lev:(nlev+lev_offset)) >= qsmall, 2)
! Scan for true values to get a usable list of indices.
-
+
mgncol = count(ltrue)
allocate(mgcols(mgncol))
i = 0
@@ -4204,154 +3814,4 @@ pure function interp_to_mid(orig_val, weights) result(new_val)
end function interp_to_mid
-! Subroutines to pack arrays into smaller, contiguous pieces
-!========================================================================
-! Rank 1 array of reals, columns only
-pure subroutine pack_array_1Dr8(old_array, cols, new_array)
- ! Inputs
- real(r8), intent(in) :: old_array(:) ! Array to be packed
- integer, intent(in) :: cols(:) ! List of columns to include
-
- ! Output
- real(r8), intent(out) :: new_array(:)
-
- ! Attempt to speed up packing if it is unnecessary.
- if (size(new_array) == size(old_array)) then
- new_array = old_array
- else
- new_array = old_array(cols)
- end if
-
-end subroutine pack_array_1Dr8
-
-! Rank 2 array of reals, columns and levels
-pure subroutine pack_array_2Dr8(old_array, cols, top_lev, new_array)
- ! Inputs
- real(r8), intent(in) :: old_array(:,:) ! Array to be packed
- integer, intent(in) :: cols(:) ! List of columns to include
- integer, intent(in) :: top_lev ! First level to use
-
- ! Output
- real(r8), intent(out) :: new_array(:,:)
-
- ! Attempt to speed up packing if it is unnecessary.
- if (size(new_array) == size(old_array)) then
- new_array = old_array
- else
- new_array = old_array(cols, top_lev:)
- end if
-
-end subroutine pack_array_2Dr8
-
-! Rank 3 array of reals, assume last index is extra
-pure subroutine pack_array_3Dr8(old_array, cols, top_lev, new_array)
- ! Inputs
- real(r8), intent(in) :: old_array(:,:,:) ! Array to be packed
- integer, intent(in) :: cols(:) ! List of columns to include
- integer, intent(in) :: top_lev ! First level to use
-
- ! Output
- real(r8), intent(out) :: new_array(:,:,:)
-
- ! Attempt to speed up packing if it is unnecessary.
- if (size(new_array) == size(old_array)) then
- new_array = old_array
- else
- new_array = old_array(cols, top_lev:,:)
- end if
-
-end subroutine pack_array_3Dr8
-
-! Subroutines to unpack arrays for output
-!========================================================================
-! Rank 1 array of reals, columns only
-pure subroutine unpack_array_1Dr8(old_array, cols, fill, new_array)
- ! Inputs
- real(r8), intent(in) :: old_array(:) ! Array to be packed
- integer, intent(in) :: cols(:) ! List of columns to include
- real(r8), intent(in) :: fill ! Value with which to fill unused
- ! sections of new_array.
-
- ! Output
- real(r8), intent(out) :: new_array(:)
-
- ! Attempt to speed up packing if it is unnecessary.
- if (size(new_array) == size(old_array)) then
- new_array = old_array
- else
- new_array = fill
-
- new_array(cols) = old_array
- end if
-
-end subroutine unpack_array_1Dr8
-
-! Rank 1 array of reals, columns only, "fill" value is an array
-pure subroutine unpack_array_1Dr8_arrayfill(old_array, cols, fill, new_array)
- ! Inputs
- real(r8), intent(in) :: old_array(:) ! Array to be packed
- integer, intent(in) :: cols(:) ! List of columns to include
- real(r8), intent(in) :: fill(:) ! Value with which to fill unused
- ! sections of new_array.
-
- ! Output
- real(r8), intent(out) :: new_array(:)
-
- ! Attempt to speed up packing if it is unnecessary.
- if (size(new_array) == size(old_array)) then
- new_array = old_array
- else
- new_array = fill
-
- new_array(cols) = old_array
- end if
-
-end subroutine unpack_array_1Dr8_arrayfill
-
-! Rank 2 array of reals, columns and levels
-pure subroutine unpack_array_2Dr8(old_array, cols, top_lev, fill, new_array)
- ! Inputs
- real(r8), intent(in) :: old_array(:,:) ! Array to be packed
- integer, intent(in) :: cols(:) ! List of columns to include
- integer, intent(in) :: top_lev ! First level to use
- real(r8), intent(in) :: fill ! Value with which to fill unused
- ! sections of new_array.
-
- ! Output
- real(r8), intent(out) :: new_array(:,:)
-
- ! Attempt to speed up packing if it is unnecessary.
- if (size(new_array) == size(old_array)) then
- new_array = old_array
- else
- new_array = fill
-
- new_array(cols, top_lev:) = old_array
- end if
-
-end subroutine unpack_array_2Dr8
-
-! Rank 2 array of reals, columns and levels, "fill" value is an array
-pure subroutine unpack_array_2Dr8_arrayfill(old_array, cols, top_lev, fill, new_array)
- ! Inputs
- real(r8), intent(in) :: old_array(:,:) ! Array to be packed
- integer, intent(in) :: cols(:) ! List of columns to include
- integer, intent(in) :: top_lev ! First level to use
- real(r8), intent(in) :: fill(:,:) ! Value with which to fill unused
- ! sections of new_array.
-
- ! Output
- real(r8), intent(out) :: new_array(:,:)
-
- ! Attempt to speed up packing if it is unnecessary.
- if (size(new_array) == size(old_array)) then
- new_array = old_array
- else
- new_array = fill
-
- new_array(cols, top_lev:) = old_array
- end if
-
-end subroutine unpack_array_2Dr8_arrayfill
-
end module micro_mg1_5
diff --git a/models/atm/cam/src/physics/cam/micro_mg2_0.F90 b/models/atm/cam/src/physics/cam/micro_mg2_0.F90
new file mode 100644
index 000000000000..3c458c767cb8
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/micro_mg2_0.F90
@@ -0,0 +1,2962 @@
+module micro_mg2_0
+
+!---------------------------------------------------------------------------------
+! Purpose:
+! MG microphysics version 2.0 - Update of MG microphysics with
+! prognostic precipitation.
+!
+! Author: Andrew Gettelman, Hugh Morrison.
+! Contributions from: Peter Caldwell, Xiaohong Liu and Steve Ghan
+! Version 2 history: Sep 2011: Development begun.
+! Feb 2013: Added of prognostic precipitation.
+! invoked in CAM by specifying -microphys=mg2.0
+!
+! for questions contact Hugh Morrison, Andrew Gettelman
+! e-mail: morrison@ucar.edu, andrew@ucar.edu
+!---------------------------------------------------------------------------------
+!
+! NOTE: Modified to allow other microphysics packages (e.g. CARMA) to do ice
+! microphysics in cooperation with the MG liquid microphysics. This is
+! controlled by the do_cldice variable.
+!
+! If do_cldice is false, then MG microphysics should not update CLDICE or
+! NUMICE; it is assumed that the other microphysics scheme will have updated
+! CLDICE and NUMICE. The other microphysics should handle the following
+! processes that would have been done by MG:
+! - Detrainment (liquid and ice)
+! - Homogeneous ice nucleation
+! - Heterogeneous ice nucleation
+! - Bergeron process
+! - Melting of ice
+! - Freezing of cloud drops
+! - Autoconversion (ice -> snow)
+! - Growth/Sublimation of ice
+! - Sedimentation of ice
+!
+! This option has not been updated since the introduction of prognostic
+! precipitation, and probably should be adjusted to cover snow as well.
+!
+!---------------------------------------------------------------------------------
+! Based on micro_mg (restructuring of former cldwat2m_micro)
+! Author: Andrew Gettelman, Hugh Morrison.
+! Contributions from: Xiaohong Liu and Steve Ghan
+! December 2005-May 2010
+! Description in: Morrison and Gettelman, 2008. J. Climate (MG2008)
+! Gettelman et al., 2010 J. Geophys. Res. - Atmospheres (G2010)
+! for questions contact Hugh Morrison, Andrew Gettelman
+! e-mail: morrison@ucar.edu, andrew@ucar.edu
+!---------------------------------------------------------------------------------
+! Code comments added by HM, 093011
+! General code structure:
+!
+! Code is divided into two main subroutines:
+! subroutine micro_mg_init --> initializes microphysics routine, should be called
+! once at start of simulation
+! subroutine micro_mg_tend --> main microphysics routine to be called each time step
+! this also calls several smaller subroutines to calculate
+! microphysical processes and other utilities
+!
+! List of external functions:
+! qsat_water --> for calculating saturation vapor pressure with respect to liquid water
+! qsat_ice --> for calculating saturation vapor pressure with respect to ice
+! gamma --> standard mathematical gamma function
+! .........................................................................
+! List of inputs through use statement in fortran90:
+! Variable Name Description Units
+! .........................................................................
+! gravit acceleration due to gravity m s-2
+! rair dry air gas constant for air J kg-1 K-1
+! tmelt temperature of melting point for water K
+! cpair specific heat at constant pressure for dry air J kg-1 K-1
+! rh2o gas constant for water vapor J kg-1 K-1
+! latvap latent heat of vaporization J kg-1
+! latice latent heat of fusion J kg-1
+! qsat_water external function for calculating liquid water
+! saturation vapor pressure/humidity -
+! qsat_ice external function for calculating ice
+! saturation vapor pressure/humidity pa
+! rhmini relative humidity threshold parameter for
+! nucleating ice -
+! .........................................................................
+! NOTE: List of all inputs/outputs passed through the call/subroutine statement
+! for micro_mg_tend is given below at the start of subroutine micro_mg_tend.
+!---------------------------------------------------------------------------------
+
+! Procedures required:
+! 1) An implementation of the gamma function (if not intrinsic).
+! 2) saturation vapor pressure and specific humidity over water
+! 3) svp over ice
+
+#ifndef HAVE_GAMMA_INTRINSICS
+use shr_spfn_mod, only: gamma => shr_spfn_gamma
+#endif
+
+use wv_sat_methods, only: &
+ qsat_water => wv_sat_qsat_water, &
+ qsat_ice => wv_sat_qsat_ice
+
+! Parameters from the utilities module.
+use micro_mg_utils, only: &
+ r8, &
+ pi, &
+ omsm, &
+ qsmall, &
+ mincld, &
+ rhosn, &
+ rhoi, &
+ rhow, &
+ rhows, &
+ ac, bc, &
+ ai, bi, &
+ ar, br, &
+ as, bs, &
+ mi0, &
+ rising_factorial
+
+implicit none
+private
+save
+
+public :: &
+ micro_mg_init, &
+ micro_mg_get_cols, &
+ micro_mg_tend
+
+! switch for specification rather than prediction of droplet and crystal number
+! note: number will be adjusted as needed to keep mean size within bounds,
+! even when specified droplet or ice number is used
+
+! If constant cloud ice number is set (nicons = .true.),
+! then all microphysical processes except mass transfer due to ice nucleation
+! (mnuccd) are based on the fixed cloud ice number. Calculation of
+! mnuccd follows from the prognosed ice crystal number ni.
+
+! nccons = .true. to specify constant cloud droplet number
+! nicons = .true. to specify constant cloud ice number
+
+logical, parameter, public :: nccons = .false.
+logical, parameter, public :: nicons = .false.
+
+!=========================================================
+! Private module parameters
+!=========================================================
+
+! parameters for specified ice and droplet number concentration
+! note: these are local in-cloud values, not grid-mean
+real(r8), parameter :: ncnst = 100.e6_r8 ! droplet num concentration when nccons=.true. (m-3)
+real(r8), parameter :: ninst = 0.1e6_r8 ! ice num concentration when nicons=.true. (m-3)
+
+!Range of cloudsat reflectivities (dBz) for analytic simulator
+real(r8), parameter :: csmin = -30._r8
+real(r8), parameter :: csmax = 26._r8
+real(r8), parameter :: mindbz = -99._r8
+real(r8), parameter :: minrefl = 1.26e-10_r8 ! minrefl = 10._r8**(mindbz/10._r8)
+
+! autoconversion size threshold for cloud ice to snow (m)
+real(r8) :: dcs
+
+! minimum mass of new crystal due to freezing of cloud droplets done
+! externally (kg)
+real(r8), parameter :: mi0l_min = 4._r8/3._r8*pi*rhow*(4.e-6_r8)**3
+
+!=========================================================
+! Constants set in initialization
+!=========================================================
+
+! Set using arguments to micro_mg_init
+real(r8) :: g ! gravity
+real(r8) :: r ! dry air gas constant
+real(r8) :: rv ! water vapor gas constant
+real(r8) :: cpp ! specific heat of dry air
+real(r8) :: tmelt ! freezing point of water (K)
+
+! latent heats of:
+real(r8) :: xxlv ! vaporization
+real(r8) :: xlf ! freezing
+real(r8) :: xxls ! sublimation
+
+real(r8) :: rhmini ! Minimum rh for ice cloud fraction > 0.
+
+! flags
+logical :: microp_uniform
+logical :: do_cldice
+logical :: use_hetfrz_classnuc
+
+real(r8) :: rhosu ! typical 850mn air density
+
+real(r8) :: icenuct ! ice nucleation temperature: currently -5 degrees C
+
+real(r8) :: snowmelt ! what temp to melt all snow: currently 2 degrees C
+real(r8) :: rainfrze ! what temp to freeze all rain: currently -5 degrees C
+
+! additional constants to help speed up code
+real(r8) :: gamma_br_plus1
+real(r8) :: gamma_br_plus4
+real(r8) :: gamma_bs_plus1
+real(r8) :: gamma_bs_plus4
+real(r8) :: gamma_bi_plus1
+real(r8) :: gamma_bi_plus4
+real(r8) :: xxlv_squared
+real(r8) :: xxls_squared
+
+character(len=16) :: micro_mg_precip_frac_method ! type of precipitation fraction method
+real(r8) :: micro_mg_berg_eff_factor ! berg efficiency factor
+
+logical :: allow_sed_supersat ! Allow supersaturated conditions after sedimentation loop
+
+!===============================================================================
+contains
+!===============================================================================
+
+subroutine micro_mg_init( &
+ kind, gravit, rair, rh2o, cpair, &
+ tmelt_in, latvap, latice, &
+ rhmini_in, micro_mg_dcs, &
+ microp_uniform_in, do_cldice_in, use_hetfrz_classnuc_in, &
+ micro_mg_precip_frac_method_in, micro_mg_berg_eff_factor_in, &
+ allow_sed_supersat_in, errstring)
+
+ use micro_mg_utils, only: micro_mg_utils_init
+
+ !-----------------------------------------------------------------------
+ !
+ ! Purpose:
+ ! initialize constants for MG microphysics
+ !
+ ! Author: Andrew Gettelman Dec 2005
+ !
+ !-----------------------------------------------------------------------
+
+ integer, intent(in) :: kind ! Kind used for reals
+ real(r8), intent(in) :: gravit
+ real(r8), intent(in) :: rair
+ real(r8), intent(in) :: rh2o
+ real(r8), intent(in) :: cpair
+ real(r8), intent(in) :: tmelt_in ! Freezing point of water (K)
+ real(r8), intent(in) :: latvap
+ real(r8), intent(in) :: latice
+ real(r8), intent(in) :: rhmini_in ! Minimum rh for ice cloud fraction > 0.
+ real(r8), intent(in) :: micro_mg_dcs
+
+ logical, intent(in) :: microp_uniform_in ! .true. = configure uniform for sub-columns
+ ! .false. = use w/o sub-columns (standard)
+ logical, intent(in) :: do_cldice_in ! .true. = do all processes (standard)
+ ! .false. = skip all processes affecting
+ ! cloud ice
+ logical, intent(in) :: use_hetfrz_classnuc_in ! use heterogeneous freezing
+
+ character(len=16),intent(in) :: micro_mg_precip_frac_method_in ! type of precipitation fraction method
+ real(r8), intent(in) :: micro_mg_berg_eff_factor_in ! berg efficiency factor
+ logical, intent(in) :: allow_sed_supersat_in ! allow supersaturated conditions after sedimentation loop
+
+
+ character(128), intent(out) :: errstring ! Output status (non-blank for error return)
+
+ !-----------------------------------------------------------------------
+
+ dcs = micro_mg_dcs
+
+ ! Initialize subordinate utilities module.
+ call micro_mg_utils_init(kind, rh2o, cpair, tmelt_in, latvap, latice, &
+ dcs, errstring)
+
+ if (trim(errstring) /= "") return
+
+ ! declarations for MG code (transforms variable names)
+
+ g= gravit ! gravity
+ r= rair ! dry air gas constant: note units(phys_constants are in J/K/kmol)
+ rv= rh2o ! water vapor gas constant
+ cpp = cpair ! specific heat of dry air
+ tmelt = tmelt_in
+ rhmini = rhmini_in
+ micro_mg_precip_frac_method = micro_mg_precip_frac_method_in
+ micro_mg_berg_eff_factor = micro_mg_berg_eff_factor_in
+ allow_sed_supersat = allow_sed_supersat_in
+
+ ! latent heats
+
+ xxlv = latvap ! latent heat vaporization
+ xlf = latice ! latent heat freezing
+ xxls = xxlv + xlf ! latent heat of sublimation
+
+ ! flags
+ microp_uniform = microp_uniform_in
+ do_cldice = do_cldice_in
+ use_hetfrz_classnuc = use_hetfrz_classnuc_in
+
+ ! typical air density at 850 mb
+
+ rhosu = 85000._r8/(rair * tmelt)
+
+ ! Maximum temperature at which snow is allowed to exist
+ snowmelt = tmelt + 2._r8
+ ! Minimum temperature at which rain is allowed to exist
+ rainfrze = tmelt - 40._r8
+
+ ! Ice nucleation temperature
+ icenuct = tmelt - 5._r8
+
+ ! Define constants to help speed up code (this limits calls to gamma function)
+ gamma_br_plus1=gamma(1._r8+br)
+ gamma_br_plus4=gamma(4._r8+br)
+ gamma_bs_plus1=gamma(1._r8+bs)
+ gamma_bs_plus4=gamma(4._r8+bs)
+ gamma_bi_plus1=gamma(1._r8+bi)
+ gamma_bi_plus4=gamma(4._r8+bi)
+ xxlv_squared=xxlv**2
+ xxls_squared=xxls**2
+
+end subroutine micro_mg_init
+
+!===============================================================================
+!microphysics routine for each timestep goes here...
+
+subroutine micro_mg_tend ( &
+ mgncol, nlev, deltatin, &
+ t, q, &
+ qcn, qin, &
+ ncn, nin, &
+ qrn, qsn, &
+ nrn, nsn, &
+ relvar, accre_enhan, &
+ p, pdel, &
+ cldn, liqcldf, icecldf, &
+ qcsinksum_rate1ord, &
+ naai, npccn, &
+ rndst, nacon, &
+ tlat, qvlat, &
+ qctend, qitend, &
+ nctend, nitend, &
+ qrtend, qstend, &
+ nrtend, nstend, &
+ effc, effc_fn, effi, &
+ prect, preci, &
+ nevapr, evapsnow, &
+ prain, prodsnow, &
+ cmeout, deffi, &
+ pgamrad, lamcrad, &
+ qsout, dsout, &
+ rflx, sflx, qrout, &
+ reff_rain, reff_snow, &
+ qcsevap, qisevap, qvres, &
+ cmeitot, vtrmc, vtrmi, &
+ umr, ums, &
+ qcsedten, qisedten, &
+ qrsedten, qssedten, &
+ pratot, prctot, &
+ mnuccctot, mnuccttot, msacwitot, &
+ psacwstot, bergstot, bergtot, &
+ melttot, homotot, &
+ qcrestot, prcitot, praitot, &
+ qirestot, mnuccrtot, pracstot, &
+ meltsdttot, frzrdttot, mnuccdtot, &
+ nrout, nsout, &
+ refl, arefl, areflz, &
+ frefl, csrfl, acsrfl, &
+ fcsrfl, rercld, &
+ ncai, ncal, &
+ qrout2, qsout2, &
+ nrout2, nsout2, &
+ drout2, dsout2, &
+ freqs, freqr, &
+ nfice, qcrat, &
+ errstring, & ! Below arguments are "optional" (pass null pointers to omit).
+ tnd_qsnow, tnd_nsnow, re_ice, &
+ prer_evap, &
+ frzimm, frzcnt, frzdep)
+
+ ! Constituent properties.
+ use micro_mg_utils, only: &
+ mg_liq_props, &
+ mg_ice_props, &
+ mg_rain_props, &
+ mg_snow_props
+
+ ! Size calculation functions.
+ use micro_mg_utils, only: &
+ size_dist_param_liq, &
+ size_dist_param_basic, &
+ avg_diameter
+
+ ! Microphysical processes.
+ use micro_mg_utils, only: &
+ ice_deposition_sublimation, &
+ kk2000_liq_autoconversion, &
+ ice_autoconversion, &
+ immersion_freezing, &
+ contact_freezing, &
+ snow_self_aggregation, &
+ accrete_cloud_water_snow, &
+ secondary_ice_production, &
+ accrete_rain_snow, &
+ heterogeneous_rain_freezing, &
+ accrete_cloud_water_rain, &
+ self_collection_rain, &
+ accrete_cloud_ice_snow, &
+ evaporate_sublimate_precip, &
+ bergeron_process_snow
+
+ !Authors: Hugh Morrison, Andrew Gettelman, NCAR, Peter Caldwell, LLNL
+ ! e-mail: morrison@ucar.edu, andrew@ucar.edu
+
+ ! input arguments
+ integer, intent(in) :: mgncol ! number of microphysics columns
+ integer, intent(in) :: nlev ! number of layers
+ real(r8), intent(in) :: deltatin ! time step (s)
+ real(r8), intent(in) :: t(:,:) ! input temperature (K)
+ real(r8), intent(in) :: q(:,:) ! input h20 vapor mixing ratio (kg/kg)
+
+ ! note: all input cloud variables are grid-averaged
+ real(r8), intent(in) :: qcn(:,:) ! cloud water mixing ratio (kg/kg)
+ real(r8), intent(in) :: qin(:,:) ! cloud ice mixing ratio (kg/kg)
+ real(r8), intent(in) :: ncn(:,:) ! cloud water number conc (1/kg)
+ real(r8), intent(in) :: nin(:,:) ! cloud ice number conc (1/kg)
+
+ real(r8), intent(in) :: qrn(:,:) ! rain mixing ratio (kg/kg)
+ real(r8), intent(in) :: qsn(:,:) ! snow mixing ratio (kg/kg)
+ real(r8), intent(in) :: nrn(:,:) ! rain number conc (1/kg)
+ real(r8), intent(in) :: nsn(:,:) ! snow number conc (1/kg)
+
+ real(r8), intent(in) :: relvar(:,:) ! cloud water relative variance (-)
+ real(r8), intent(in) :: accre_enhan(:,:) ! optional accretion
+ ! enhancement factor (-)
+
+ real(r8), intent(in) :: p(:,:) ! air pressure (pa)
+ real(r8), intent(in) :: pdel(:,:) ! pressure difference across level (pa)
+
+ real(r8), intent(in) :: cldn(:,:) ! cloud fraction (no units)
+ real(r8), intent(in) :: liqcldf(:,:) ! liquid cloud fraction (no units)
+ real(r8), intent(in) :: icecldf(:,:) ! ice cloud fraction (no units)
+ ! used for scavenging
+ ! Inputs for aerosol activation
+ real(r8), intent(in) :: naai(:,:) ! ice nucleation number (from microp_aero_ts) (1/kg)
+ real(r8), intent(in) :: npccn(:,:) ! ccn activated number tendency (from microp_aero_ts) (1/kg*s)
+
+ ! Note that for these variables, the dust bin is assumed to be the last index.
+ ! (For example, in CAM, the last dimension is always size 4.)
+ real(r8), intent(in) :: rndst(:,:,:) ! radius of each dust bin, for contact freezing (from microp_aero_ts) (m)
+ real(r8), intent(in) :: nacon(:,:,:) ! number in each dust bin, for contact freezing (from microp_aero_ts) (1/m^3)
+
+ ! output arguments
+
+ real(r8), intent(out) :: qcsinksum_rate1ord(:,:) ! 1st order rate for
+ ! direct cw to precip conversion
+ real(r8), intent(out) :: tlat(:,:) ! latent heating rate (W/kg)
+ real(r8), intent(out) :: qvlat(:,:) ! microphysical tendency qv (1/s)
+ real(r8), intent(out) :: qctend(:,:) ! microphysical tendency qc (1/s)
+ real(r8), intent(out) :: qitend(:,:) ! microphysical tendency qi (1/s)
+ real(r8), intent(out) :: nctend(:,:) ! microphysical tendency nc (1/(kg*s))
+ real(r8), intent(out) :: nitend(:,:) ! microphysical tendency ni (1/(kg*s))
+
+ real(r8), intent(out) :: qrtend(:,:) ! microphysical tendency qr (1/s)
+ real(r8), intent(out) :: qstend(:,:) ! microphysical tendency qs (1/s)
+ real(r8), intent(out) :: nrtend(:,:) ! microphysical tendency nr (1/(kg*s))
+ real(r8), intent(out) :: nstend(:,:) ! microphysical tendency ns (1/(kg*s))
+
+ real(r8), intent(out) :: effc(:,:) ! droplet effective radius (micron)
+ real(r8), intent(out) :: effc_fn(:,:) ! droplet effective radius, assuming nc = 1.e8 kg-1
+ real(r8), intent(out) :: effi(:,:) ! cloud ice effective radius (micron)
+ real(r8), intent(out) :: prect(:) ! surface precip rate (m/s)
+ real(r8), intent(out) :: preci(:) ! cloud ice/snow precip rate (m/s)
+ real(r8), intent(out) :: nevapr(:,:) ! evaporation rate of rain + snow (1/s)
+ real(r8), intent(out) :: evapsnow(:,:) ! sublimation rate of snow (1/s)
+ real(r8), intent(out) :: prain(:,:) ! production of rain + snow (1/s)
+ real(r8), intent(out) :: prodsnow(:,:) ! production of snow (1/s)
+ real(r8), intent(out) :: cmeout(:,:) ! evap/sub of cloud (1/s)
+ real(r8), intent(out) :: deffi(:,:) ! ice effective diameter for optics (radiation) (micron)
+ real(r8), intent(out) :: pgamrad(:,:) ! ice gamma parameter for optics (radiation) (no units)
+ real(r8), intent(out) :: lamcrad(:,:) ! slope of droplet distribution for optics (radiation) (1/m)
+ real(r8), intent(out) :: qsout(:,:) ! snow mixing ratio (kg/kg)
+ real(r8), intent(out) :: dsout(:,:) ! snow diameter (m)
+ real(r8), intent(out) :: rflx(:,:) ! grid-box average rain flux (kg m^-2 s^-1)
+ real(r8), intent(out) :: sflx(:,:) ! grid-box average snow flux (kg m^-2 s^-1)
+ real(r8), intent(out) :: qrout(:,:) ! grid-box average rain mixing ratio (kg/kg)
+ real(r8), intent(out) :: reff_rain(:,:) ! rain effective radius (micron)
+ real(r8), intent(out) :: reff_snow(:,:) ! snow effective radius (micron)
+ real(r8), intent(out) :: qcsevap(:,:) ! cloud water evaporation due to sedimentation (1/s)
+ real(r8), intent(out) :: qisevap(:,:) ! cloud ice sublimation due to sublimation (1/s)
+ real(r8), intent(out) :: qvres(:,:) ! residual condensation term to ensure RH < 100% (1/s)
+ real(r8), intent(out) :: cmeitot(:,:) ! grid-mean cloud ice sub/dep (1/s)
+ real(r8), intent(out) :: vtrmc(:,:) ! mass-weighted cloud water fallspeed (m/s)
+ real(r8), intent(out) :: vtrmi(:,:) ! mass-weighted cloud ice fallspeed (m/s)
+ real(r8), intent(out) :: umr(:,:) ! mass weighted rain fallspeed (m/s)
+ real(r8), intent(out) :: ums(:,:) ! mass weighted snow fallspeed (m/s)
+ real(r8), intent(out) :: qcsedten(:,:) ! qc sedimentation tendency (1/s)
+ real(r8), intent(out) :: qisedten(:,:) ! qi sedimentation tendency (1/s)
+ real(r8), intent(out) :: qrsedten(:,:) ! qr sedimentation tendency (1/s)
+ real(r8), intent(out) :: qssedten(:,:) ! qs sedimentation tendency (1/s)
+
+ ! microphysical process rates for output (mixing ratio tendencies) (all have units of 1/s)
+ real(r8), intent(out) :: pratot(:,:) ! accretion of cloud by rain
+ real(r8), intent(out) :: prctot(:,:) ! autoconversion of cloud to rain
+ real(r8), intent(out) :: mnuccctot(:,:) ! mixing ratio tend due to immersion freezing
+ real(r8), intent(out) :: mnuccttot(:,:) ! mixing ratio tend due to contact freezing
+ real(r8), intent(out) :: msacwitot(:,:) ! mixing ratio tend due to H-M splintering
+ real(r8), intent(out) :: psacwstot(:,:) ! collection of cloud water by snow
+ real(r8), intent(out) :: bergstot(:,:) ! bergeron process on snow
+ real(r8), intent(out) :: bergtot(:,:) ! bergeron process on cloud ice
+ real(r8), intent(out) :: melttot(:,:) ! melting of cloud ice
+ real(r8), intent(out) :: homotot(:,:) ! homogeneous freezing cloud water
+ real(r8), intent(out) :: qcrestot(:,:) ! residual cloud condensation due to removal of excess supersat
+ real(r8), intent(out) :: prcitot(:,:) ! autoconversion of cloud ice to snow
+ real(r8), intent(out) :: praitot(:,:) ! accretion of cloud ice by snow
+ real(r8), intent(out) :: qirestot(:,:) ! residual ice deposition due to removal of excess supersat
+ real(r8), intent(out) :: mnuccrtot(:,:) ! mixing ratio tendency due to heterogeneous freezing of rain to snow (1/s)
+ real(r8), intent(out) :: pracstot(:,:) ! mixing ratio tendency due to accretion of rain by snow (1/s)
+ real(r8), intent(out) :: meltsdttot(:,:) ! latent heating rate due to melting of snow (W/kg)
+ real(r8), intent(out) :: frzrdttot(:,:) ! latent heating rate due to homogeneous freezing of rain (W/kg)
+ real(r8), intent(out) :: mnuccdtot(:,:) ! mass tendency from ice nucleation
+ real(r8), intent(out) :: nrout(:,:) ! rain number concentration (1/m3)
+ real(r8), intent(out) :: nsout(:,:) ! snow number concentration (1/m3)
+ real(r8), intent(out) :: refl(:,:) ! analytic radar reflectivity
+ real(r8), intent(out) :: arefl(:,:) ! average reflectivity will zero points outside valid range
+ real(r8), intent(out) :: areflz(:,:) ! average reflectivity in z.
+ real(r8), intent(out) :: frefl(:,:) ! fractional occurrence of radar reflectivity
+ real(r8), intent(out) :: csrfl(:,:) ! cloudsat reflectivity
+ real(r8), intent(out) :: acsrfl(:,:) ! cloudsat average
+ real(r8), intent(out) :: fcsrfl(:,:) ! cloudsat fractional occurrence of radar reflectivity
+ real(r8), intent(out) :: rercld(:,:) ! effective radius calculation for rain + cloud
+ real(r8), intent(out) :: ncai(:,:) ! output number conc of ice nuclei available (1/m3)
+ real(r8), intent(out) :: ncal(:,:) ! output number conc of CCN (1/m3)
+ real(r8), intent(out) :: qrout2(:,:) ! copy of qrout as used to compute drout2
+ real(r8), intent(out) :: qsout2(:,:) ! copy of qsout as used to compute dsout2
+ real(r8), intent(out) :: nrout2(:,:) ! copy of nrout as used to compute drout2
+ real(r8), intent(out) :: nsout2(:,:) ! copy of nsout as used to compute dsout2
+ real(r8), intent(out) :: drout2(:,:) ! mean rain particle diameter (m)
+ real(r8), intent(out) :: dsout2(:,:) ! mean snow particle diameter (m)
+ real(r8), intent(out) :: freqs(:,:) ! fractional occurrence of snow
+ real(r8), intent(out) :: freqr(:,:) ! fractional occurrence of rain
+ real(r8), intent(out) :: nfice(:,:) ! fractional occurrence of ice
+ real(r8), intent(out) :: qcrat(:,:) ! limiter for qc process rates (1=no limit --> 0. no qc)
+
+ real(r8), intent(out) :: prer_evap(:,:)
+
+ character(128), intent(out) :: errstring ! output status (non-blank for error return)
+
+ ! Tendencies calculated by external schemes that can replace MG's native
+ ! process tendencies.
+
+ ! Used with CARMA cirrus microphysics
+ ! (or similar external microphysics model)
+ real(r8), intent(in), pointer :: tnd_qsnow(:,:) ! snow mass tendency (kg/kg/s)
+ real(r8), intent(in), pointer :: tnd_nsnow(:,:) ! snow number tendency (#/kg/s)
+ real(r8), intent(in), pointer :: re_ice(:,:) ! ice effective radius (m)
+
+ ! From external ice nucleation.
+ real(r8), intent(in), pointer :: frzimm(:,:) ! Number tendency due to immersion freezing (1/cm3)
+ real(r8), intent(in), pointer :: frzcnt(:,:) ! Number tendency due to contact freezing (1/cm3)
+ real(r8), intent(in), pointer :: frzdep(:,:) ! Number tendency due to deposition nucleation (1/cm3)
+
+ ! local workspace
+ ! all units mks unless otherwise stated
+
+ ! local copies of input variables
+ real(r8) :: qc(mgncol,nlev) ! cloud liquid mixing ratio (kg/kg)
+ real(r8) :: qi(mgncol,nlev) ! cloud ice mixing ratio (kg/kg)
+ real(r8) :: nc(mgncol,nlev) ! cloud liquid number concentration (1/kg)
+ real(r8) :: ni(mgncol,nlev) ! cloud liquid number concentration (1/kg)
+ real(r8) :: qr(mgncol,nlev) ! rain mixing ratio (kg/kg)
+ real(r8) :: qs(mgncol,nlev) ! snow mixing ratio (kg/kg)
+ real(r8) :: nr(mgncol,nlev) ! rain number concentration (1/kg)
+ real(r8) :: ns(mgncol,nlev) ! snow number concentration (1/kg)
+
+ ! general purpose variables
+ real(r8) :: deltat ! sub-time step (s)
+ real(r8) :: mtime ! the assumed ice nucleation timescale
+
+ ! physical properties of the air at a given point
+ real(r8) :: rho(mgncol,nlev) ! density (kg m-3)
+ real(r8) :: dv(mgncol,nlev) ! diffusivity of water vapor
+ real(r8) :: mu(mgncol,nlev) ! viscosity
+ real(r8) :: sc(mgncol,nlev) ! schmidt number
+ real(r8) :: rhof(mgncol,nlev) ! density correction factor for fallspeed
+
+ ! cloud fractions
+ real(r8) :: precip_frac(mgncol,nlev) ! precip fraction assuming maximum overlap
+ real(r8) :: cldm(mgncol,nlev) ! cloud fraction
+ real(r8) :: icldm(mgncol,nlev) ! ice cloud fraction
+ real(r8) :: lcldm(mgncol,nlev) ! liq cloud fraction
+
+ ! mass mixing ratios
+ real(r8) :: qcic(mgncol,nlev) ! in-cloud cloud liquid
+ real(r8) :: qiic(mgncol,nlev) ! in-cloud cloud ice
+ real(r8) :: qsic(mgncol,nlev) ! in-precip snow
+ real(r8) :: qric(mgncol,nlev) ! in-precip rain
+
+ ! number concentrations
+ real(r8) :: ncic(mgncol,nlev) ! in-cloud droplet
+ real(r8) :: niic(mgncol,nlev) ! in-cloud cloud ice
+ real(r8) :: nsic(mgncol,nlev) ! in-precip snow
+ real(r8) :: nric(mgncol,nlev) ! in-precip rain
+ ! maximum allowed ni value
+ real(r8) :: nimax(mgncol,nlev)
+
+ ! Size distribution parameters for:
+ ! cloud ice
+ real(r8) :: lami(mgncol,nlev) ! slope
+ real(r8) :: n0i(mgncol,nlev) ! intercept
+ ! cloud liquid
+ real(r8) :: lamc(mgncol,nlev) ! slope
+ real(r8) :: pgam(mgncol,nlev) ! spectral width parameter
+ ! snow
+ real(r8) :: lams(mgncol,nlev) ! slope
+ real(r8) :: n0s(mgncol,nlev) ! intercept
+ ! rain
+ real(r8) :: lamr(mgncol,nlev) ! slope
+ real(r8) :: n0r(mgncol,nlev) ! intercept
+
+ ! Rates/tendencies due to:
+
+ ! Instantaneous snow melting
+ real(r8) :: minstsm(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: ninstsm(mgncol,nlev) ! number concentration
+ ! Instantaneous rain freezing
+ real(r8) :: minstrf(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: ninstrf(mgncol,nlev) ! number concentration
+
+ ! deposition of cloud ice
+ real(r8) :: vap_dep(mgncol,nlev) ! deposition from vapor to ice PMC 12/3/12
+ ! sublimation of cloud ice
+ real(r8) :: ice_sublim(mgncol,nlev) ! sublimation from ice to vapor PMC 12/3/12
+ ! ice nucleation
+ real(r8) :: nnuccd(mgncol,nlev) ! number rate from deposition/cond.-freezing
+ real(r8) :: mnuccd(mgncol,nlev) ! mass mixing ratio
+ ! freezing of cloud water
+ real(r8) :: mnuccc(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nnuccc(mgncol,nlev) ! number concentration
+ ! contact freezing of cloud water
+ real(r8) :: mnucct(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nnucct(mgncol,nlev) ! number concentration
+ ! deposition nucleation in mixed-phase clouds (from external scheme)
+ real(r8) :: mnudep(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nnudep(mgncol,nlev) ! number concentration
+ ! ice multiplication
+ real(r8) :: msacwi(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nsacwi(mgncol,nlev) ! number concentration
+ ! autoconversion of cloud droplets
+ real(r8) :: prc(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nprc(mgncol,nlev) ! number concentration (rain)
+ real(r8) :: nprc1(mgncol,nlev) ! number concentration (cloud droplets)
+ ! self-aggregation of snow
+ real(r8) :: nsagg(mgncol,nlev) ! number concentration
+ ! self-collection of rain
+ real(r8) :: nragg(mgncol,nlev) ! number concentration
+ ! collection of droplets by snow
+ real(r8) :: psacws(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: npsacws(mgncol,nlev) ! number concentration
+ ! collection of rain by snow
+ real(r8) :: pracs(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: npracs(mgncol,nlev) ! number concentration
+ ! freezing of rain
+ real(r8) :: mnuccr(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nnuccr(mgncol,nlev) ! number concentration
+ ! freezing of rain to form ice (mg add 4/26/13)
+ real(r8) :: mnuccri(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nnuccri(mgncol,nlev) ! number concentration
+ ! accretion of droplets by rain
+ real(r8) :: pra(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: npra(mgncol,nlev) ! number concentration
+ ! autoconversion of cloud ice to snow
+ real(r8) :: prci(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nprci(mgncol,nlev) ! number concentration
+ ! accretion of cloud ice by snow
+ real(r8) :: prai(mgncol,nlev) ! mass mixing ratio
+ real(r8) :: nprai(mgncol,nlev) ! number concentration
+ ! evaporation of rain
+ real(r8) :: pre(mgncol,nlev) ! mass mixing ratio
+ ! sublimation of snow
+ real(r8) :: prds(mgncol,nlev) ! mass mixing ratio
+ ! number evaporation
+ real(r8) :: nsubi(mgncol,nlev) ! cloud ice
+ real(r8) :: nsubc(mgncol,nlev) ! droplet
+ real(r8) :: nsubs(mgncol,nlev) ! snow
+ real(r8) :: nsubr(mgncol,nlev) ! rain
+ ! bergeron process
+ real(r8) :: berg(mgncol,nlev) ! mass mixing ratio (cloud ice)
+ real(r8) :: bergs(mgncol,nlev) ! mass mixing ratio (snow)
+
+
+ ! fallspeeds
+ ! number-weighted
+ real(r8) :: uns(mgncol,nlev) ! snow
+ real(r8) :: unr(mgncol,nlev) ! rain
+ ! air density corrected fallspeed parameters
+ real(r8) :: arn(mgncol,nlev) ! rain
+ real(r8) :: asn(mgncol,nlev) ! snow
+ real(r8) :: acn(mgncol,nlev) ! cloud droplet
+ real(r8) :: ain(mgncol,nlev) ! cloud ice
+
+ ! Mass of liquid droplets used with external heterogeneous freezing.
+ real(r8) :: mi0l(mgncol)
+
+ ! saturation vapor pressures
+ real(r8) :: esl(mgncol,nlev) ! liquid
+ real(r8) :: esi(mgncol,nlev) ! ice
+ real(r8) :: esn ! checking for RH after rain evap
+
+ ! saturation vapor mixing ratios
+ real(r8) :: qvl(mgncol,nlev) ! liquid
+ real(r8) :: qvi(mgncol,nlev) ! ice
+ real(r8) :: qvn ! checking for RH after rain evap
+
+ ! relative humidity
+ real(r8) :: relhum(mgncol,nlev)
+
+ ! parameters for cloud water and cloud ice sedimentation calculations
+ real(r8) :: fc(nlev)
+ real(r8) :: fnc(nlev)
+ real(r8) :: fi(nlev)
+ real(r8) :: fni(nlev)
+
+ real(r8) :: fr(nlev)
+ real(r8) :: fnr(nlev)
+ real(r8) :: fs(nlev)
+ real(r8) :: fns(nlev)
+
+ real(r8) :: faloutc(nlev)
+ real(r8) :: faloutnc(nlev)
+ real(r8) :: falouti(nlev)
+ real(r8) :: faloutni(nlev)
+
+ real(r8) :: faloutr(nlev)
+ real(r8) :: faloutnr(nlev)
+ real(r8) :: falouts(nlev)
+ real(r8) :: faloutns(nlev)
+
+ real(r8) :: faltndc
+ real(r8) :: faltndnc
+ real(r8) :: faltndi
+ real(r8) :: faltndni
+ real(r8) :: faltndqie
+ real(r8) :: faltndqce
+
+ real(r8) :: faltndr
+ real(r8) :: faltndnr
+ real(r8) :: faltnds
+ real(r8) :: faltndns
+
+ real(r8) :: rainrt(mgncol,nlev) ! rain rate for reflectivity calculation
+
+ ! dummy variables
+ real(r8) :: dum
+ real(r8) :: dum1
+ real(r8) :: dum2
+ ! dummies for checking RH
+ real(r8) :: qtmp
+ real(r8) :: ttmp
+ ! dummies for conservation check
+ real(r8) :: ratio
+ real(r8) :: tmpfrz
+ ! dummies for in-cloud variables
+ real(r8) :: dumc(mgncol,nlev) ! qc
+ real(r8) :: dumnc(mgncol,nlev) ! nc
+ real(r8) :: dumi(mgncol,nlev) ! qi
+ real(r8) :: dumni(mgncol,nlev) ! ni
+ real(r8) :: dumr(mgncol,nlev) ! rain mixing ratio
+ real(r8) :: dumnr(mgncol,nlev) ! rain number concentration
+ real(r8) :: dums(mgncol,nlev) ! snow mixing ratio
+ real(r8) :: dumns(mgncol,nlev) ! snow number concentration
+ ! Array dummy variable
+ real(r8) :: dum_2D(mgncol,nlev)
+
+ ! loop array variables
+ ! "i" and "k" are column/level iterators for internal (MG) variables
+ ! "n" is used for other looping (currently just sedimentation)
+ integer i, k, n
+
+ ! number of sub-steps for loops over "n" (for sedimentation)
+ integer nstep
+
+ !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+
+ ! default return error message
+ errstring = ' '
+
+ if (.not. (do_cldice .or. &
+ (associated(tnd_qsnow) .and. associated(tnd_nsnow) .and. associated(re_ice)))) then
+ errstring = "MG's native cloud ice processes are disabled, but &
+ &no replacement values were passed in."
+ end if
+
+ if (use_hetfrz_classnuc .and. (.not. &
+ (associated(frzimm) .and. associated(frzcnt) .and. associated(frzdep)))) then
+ errstring = "External heterogeneous freezing is enabled, but the &
+ &required tendencies were not all passed in."
+ end if
+
+ ! Process inputs
+
+ ! assign variable deltat to deltatin
+ deltat = deltatin
+
+ ! Copies of input concentrations that may be changed internally.
+ qc = qcn
+ nc = ncn
+ qi = qin
+ ni = nin
+ qr = qrn
+ nr = nrn
+ qs = qsn
+ ns = nsn
+
+ ! cldn: used to set cldm, unused for subcolumns
+ ! liqcldf: used to set lcldm, unused for subcolumns
+ ! icecldf: used to set icldm, unused for subcolumns
+
+ if (microp_uniform) then
+ ! subcolumns, set cloud fraction variables to one
+ ! if cloud water or ice is present, if not present
+ ! set to mincld (mincld used instead of zero, to prevent
+ ! possible division by zero errors).
+
+ where (qc >= qsmall)
+ lcldm = 1._r8
+ elsewhere
+ lcldm = mincld
+ end where
+
+ where (qi >= qsmall)
+ icldm = 1._r8
+ elsewhere
+ icldm = mincld
+ end where
+
+ cldm = max(icldm, lcldm)
+
+ else
+ ! get cloud fraction, check for minimum
+ cldm = max(cldn,mincld)
+ lcldm = max(liqcldf,mincld)
+ icldm = max(icecldf,mincld)
+ end if
+
+ ! Initialize local variables
+
+ ! local physical properties
+ rho = p/(r*t)
+ dv = 8.794E-5_r8 * t**1.81_r8 / p
+ mu = 1.496E-6_r8 * t**1.5_r8 / (t + 120._r8)
+ sc = mu/(rho*dv)
+
+ ! air density adjustment for fallspeed parameters
+ ! includes air density correction factor to the
+ ! power of 0.54 following Heymsfield and Bansemer 2007
+
+ rhof=(rhosu/rho)**0.54_r8
+
+ arn=ar*rhof
+ asn=as*rhof
+ acn=g*rhow/(18._r8*mu)
+ ain=ai*(rhosu/rho)**0.35_r8
+
+ !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+ ! Get humidity and saturation vapor pressures
+
+ do k=1,nlev
+ do i=1,mgncol
+
+ call qsat_water(t(i,k), p(i,k), esl(i,k), qvl(i,k))
+
+ ! make sure when above freezing that esi=esl, not active yet
+ if (t(i,k) >= tmelt) then
+ esi(i,k)=esl(i,k)
+ qvi(i,k)=qvl(i,k)
+ else
+ call qsat_ice(t(i,k), p(i,k), esi(i,k), qvi(i,k))
+ end if
+
+ end do
+ end do
+
+ relhum = q / max(qvl, qsmall)
+
+ !===============================================
+
+ ! set mtime here to avoid answer-changing
+ mtime=deltat
+
+ ! initialize microphysics output
+ qcsevap=0._r8
+ qisevap=0._r8
+ qvres =0._r8
+ cmeitot =0._r8
+ vtrmc =0._r8
+ vtrmi =0._r8
+ qcsedten =0._r8
+ qisedten =0._r8
+ qrsedten =0._r8
+ qssedten =0._r8
+
+ pratot=0._r8
+ prctot=0._r8
+ mnuccctot=0._r8
+ mnuccttot=0._r8
+ msacwitot=0._r8
+ psacwstot=0._r8
+ bergstot=0._r8
+ bergtot=0._r8
+ melttot=0._r8
+ homotot=0._r8
+ qcrestot=0._r8
+ prcitot=0._r8
+ praitot=0._r8
+ qirestot=0._r8
+ mnuccrtot=0._r8
+ pracstot=0._r8
+ meltsdttot=0._r8
+ frzrdttot=0._r8
+ mnuccdtot=0._r8
+
+ rflx=0._r8
+ sflx=0._r8
+
+ ! initialize precip output
+
+ qrout=0._r8
+ qsout=0._r8
+ nrout=0._r8
+ nsout=0._r8
+
+ ! for refl calc
+ rainrt = 0._r8
+
+ ! initialize rain size
+ rercld=0._r8
+
+ qcsinksum_rate1ord = 0._r8
+
+ ! initialize variables for trop_mozart
+ nevapr = 0._r8
+ prer_evap = 0._r8
+ evapsnow = 0._r8
+ prain = 0._r8
+ prodsnow = 0._r8
+ cmeout = 0._r8
+
+ precip_frac = mincld
+
+ lamc=0._r8
+
+ ! initialize microphysical tendencies
+
+ tlat=0._r8
+ qvlat=0._r8
+ qctend=0._r8
+ qitend=0._r8
+ qstend = 0._r8
+ qrtend = 0._r8
+ nctend=0._r8
+ nitend=0._r8
+ nrtend = 0._r8
+ nstend = 0._r8
+
+ ! initialize in-cloud and in-precip quantities to zero
+ qcic = 0._r8
+ qiic = 0._r8
+ qsic = 0._r8
+ qric = 0._r8
+
+ ncic = 0._r8
+ niic = 0._r8
+ nsic = 0._r8
+ nric = 0._r8
+
+ ! initialize precip at surface
+
+ prect = 0._r8
+ preci = 0._r8
+
+ ! initialize precip fallspeeds to zero
+ ums = 0._r8
+ uns = 0._r8
+ umr = 0._r8
+ unr = 0._r8
+
+ ! initialize limiter for output
+ qcrat = 1._r8
+
+ ! Many outputs have to be initialized here at the top to work around
+ ! ifort problems, even if they are always overwritten later.
+ effc = 10._r8
+ lamcrad = 0._r8
+ pgamrad = 0._r8
+ effc_fn = 10._r8
+ effi = 25._r8
+ deffi = 50._r8
+
+ qrout2 = 0._r8
+ nrout2 = 0._r8
+ drout2 = 0._r8
+ qsout2 = 0._r8
+ nsout2 = 0._r8
+ dsout = 0._r8
+ dsout2 = 0._r8
+
+ freqr = 0._r8
+ freqs = 0._r8
+
+ reff_rain = 0._r8
+ reff_snow = 0._r8
+
+ refl = -9999._r8
+ arefl = 0._r8
+ areflz = 0._r8
+ frefl = 0._r8
+ csrfl = 0._r8
+ acsrfl = 0._r8
+ fcsrfl = 0._r8
+
+ ncal = 0._r8
+ ncai = 0._r8
+
+ nfice = 0._r8
+
+ !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+ ! droplet activation
+ ! get provisional droplet number after activation. This is used for
+ ! all microphysical process calculations, for consistency with update of
+ ! droplet mass before microphysics
+
+ ! calculate potential for droplet activation if cloud water is present
+ ! tendency from activation (npccn) is read in from companion routine
+
+ ! output activated liquid and ice (convert from #/kg -> #/m3)
+ !--------------------------------------------------
+ where (qc >= qsmall)
+ nc = max(nc + npccn*deltat, 0._r8)
+ ncal = nc*rho/lcldm ! sghan minimum in #/cm3
+ elsewhere
+ ncal = 0._r8
+ end where
+
+ where (t < icenuct)
+ ncai = naai*rho
+ elsewhere
+ ncai = 0._r8
+ end where
+
+ !===============================================
+
+ ! ice nucleation if activated nuclei exist at t<-5C AND rhmini + 5%
+ !-------------------------------------------------------
+
+ if (do_cldice) then
+ where (naai > 0._r8 .and. t < icenuct .and. &
+ relhum*esl/esi > rhmini+0.05_r8)
+
+ !if NAAI > 0. then set numice = naai (as before)
+ !note: this is gridbox averaged
+ nnuccd = (naai-ni/icldm)/mtime*icldm
+ nnuccd = max(nnuccd,0._r8)
+ nimax = naai*icldm
+
+ !Calc mass of new particles using new crystal mass...
+ !also this will be multiplied by mtime as nnuccd is...
+
+ mnuccd = nnuccd * mi0
+
+ elsewhere
+ nnuccd = 0._r8
+ nimax = 0._r8
+ mnuccd = 0._r8
+ end where
+
+ end if
+
+
+ !=============================================================================
+ pre_vert_loop: do k=1,nlev
+
+ pre_col_loop: do i=1,mgncol
+
+ ! calculate instantaneous precip processes (melting and homogeneous freezing)
+
+ ! melting of snow at +2 C
+
+ if (t(i,k) > snowmelt) then
+ if (qs(i,k) > 0._r8) then
+
+ ! make sure melting snow doesn't reduce temperature below threshold
+ dum = -xlf/cpp*qs(i,k)
+ if (t(i,k)+dum < snowmelt) then
+ dum = (t(i,k)-snowmelt)*cpp/xlf
+ dum = dum/qs(i,k)
+ dum = max(0._r8,dum)
+ dum = min(1._r8,dum)
+ else
+ dum = 1._r8
+ end if
+
+ minstsm(i,k) = dum*qs(i,k)
+ ninstsm(i,k) = dum*ns(i,k)
+
+ dum1=-xlf*minstsm(i,k)/deltat
+ tlat(i,k)=tlat(i,k)+dum1
+ meltsdttot(i,k)=meltsdttot(i,k) + dum1
+
+ qs(i,k) = max(qs(i,k) - minstsm(i,k), 0._r8)
+ ns(i,k) = max(ns(i,k) - ninstsm(i,k), 0._r8)
+ qr(i,k) = max(qr(i,k) + minstsm(i,k), 0._r8)
+ nr(i,k) = max(nr(i,k) + ninstsm(i,k), 0._r8)
+ end if
+ end if
+
+ ! freezing of rain at -5 C
+
+ if (t(i,k) < rainfrze) then
+
+ if (qr(i,k) > 0._r8) then
+
+ ! make sure freezing rain doesn't increase temperature above threshold
+ dum = xlf/cpp*qr(i,k)
+ if (t(i,k)+dum > rainfrze) then
+ dum = -(t(i,k)-rainfrze)*cpp/xlf
+ dum = dum/qr(i,k)
+ dum = max(0._r8,dum)
+ dum = min(1._r8,dum)
+ else
+ dum = 1._r8
+ end if
+
+ minstrf(i,k) = dum*qr(i,k)
+ ninstrf(i,k) = dum*nr(i,k)
+
+ ! heating tendency
+ dum1 = xlf*minstrf(i,k)/deltat
+ tlat(i,k)=tlat(i,k)+dum1
+ frzrdttot(i,k)=frzrdttot(i,k) + dum1
+
+ qr(i,k) = max(qr(i,k) - minstrf(i,k), 0._r8)
+ nr(i,k) = max(nr(i,k) - ninstrf(i,k), 0._r8)
+ qs(i,k) = max(qs(i,k) + minstrf(i,k), 0._r8)
+ ns(i,k) = max(ns(i,k) + ninstrf(i,k), 0._r8)
+
+ end if
+ end if
+
+ ! obtain in-cloud values of cloud water/ice mixing ratios and number concentrations
+ !-------------------------------------------------------
+ ! for microphysical process calculations
+ ! units are kg/kg for mixing ratio, 1/kg for number conc
+
+ if (qc(i,k).ge.qsmall) then
+ ! limit in-cloud values to 0.005 kg/kg
+ qcic(i,k)=min(qc(i,k)/lcldm(i,k),5.e-3_r8)
+ ncic(i,k)=max(nc(i,k)/lcldm(i,k),0._r8)
+
+ ! specify droplet concentration
+ if (nccons) then
+ ncic(i,k)=ncnst/rho(i,k)
+ end if
+ else
+ qcic(i,k)=0._r8
+ ncic(i,k)=0._r8
+ end if
+
+ if (qi(i,k).ge.qsmall) then
+ ! limit in-cloud values to 0.005 kg/kg
+ qiic(i,k)=min(qi(i,k)/icldm(i,k),5.e-3_r8)
+ niic(i,k)=max(ni(i,k)/icldm(i,k),0._r8)
+
+ ! switch for specification of cloud ice number
+ if (nicons) then
+ niic(i,k)=ninst/rho(i,k)
+ end if
+ else
+ qiic(i,k)=0._r8
+ niic(i,k)=0._r8
+ end if
+
+ end do pre_col_loop
+ end do pre_vert_loop
+
+ !========================================================================
+
+ ! for sub-columns cldm has already been set to 1 if cloud
+ ! water or ice is present, so precip_frac will be correctly set below
+ ! and nothing extra needs to be done here
+
+ precip_frac = cldm
+
+ micro_vert_loop: do k=1,nlev
+
+ if (trim(micro_mg_precip_frac_method) == 'in_cloud') then
+
+ if (k /= 1) then
+ where (qc(:,k) < qsmall .and. qi(:,k) < qsmall)
+ precip_frac(:,k) = precip_frac(:,k-1)
+ end where
+ endif
+
+ else if (trim(micro_mg_precip_frac_method) == 'max_overlap') then
+
+ ! calculate precip fraction based on maximum overlap assumption
+
+ ! if rain or snow mix ratios are smaller than threshold,
+ ! then leave precip_frac as cloud fraction at current level
+ if (k /= 1) then
+ where (qr(:,k-1) >= qsmall .or. qs(:,k-1) >= qsmall)
+ precip_frac(:,k)=max(precip_frac(:,k-1),precip_frac(:,k))
+ end where
+ end if
+
+ endif
+
+ do i = 1, mgncol
+
+ !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+ ! get size distribution parameters based on in-cloud cloud water
+ ! these calculations also ensure consistency between number and mixing ratio
+ !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+
+ ! cloud liquid
+ !-------------------------------------------
+
+ call size_dist_param_liq(mg_liq_props, qcic(i,k), ncic(i,k), rho(i,k), &
+ pgam(i,k), lamc(i,k))
+
+ end do
+
+ !========================================================================
+ ! autoconversion of cloud liquid water to rain
+ ! formula from Khrouditnov and Kogan (2000), modified for sub-grid distribution of qc
+ ! minimum qc of 1 x 10^-8 prevents floating point error
+
+ call kk2000_liq_autoconversion(microp_uniform, qcic(:,k), &
+ ncic(:,k), rho(:,k), relvar(:,k), prc(:,k), nprc(:,k), nprc1(:,k))
+
+ ! assign qric based on prognostic qr, using assumed precip fraction
+ ! note: this could be moved above for consistency with qcic and qiic calculations
+ qric(:,k) = qr(:,k)/precip_frac(:,k)
+ nric(:,k) = nr(:,k)/precip_frac(:,k)
+
+ ! limit in-precip mixing ratios to 10 g/kg
+ qric(:,k)=min(qric(:,k),0.01_r8)
+
+ ! add autoconversion to precip from above to get provisional rain mixing ratio
+ ! and number concentration (qric and nric)
+
+ where (qric(:,k).lt.qsmall)
+ qric(:,k)=0._r8
+ nric(:,k)=0._r8
+ end where
+
+ ! make sure number concentration is a positive number to avoid
+ ! taking root of negative later
+
+ nric(:,k)=max(nric(:,k),0._r8)
+
+ ! Get size distribution parameters for cloud ice
+
+ call size_dist_param_basic(mg_ice_props, qiic(:,k), niic(:,k), &
+ lami(:,k), n0i(:,k))
+
+ !.......................................................................
+ ! Autoconversion of cloud ice to snow
+ ! similar to Ferrier (1994)
+
+ if (do_cldice) then
+ call ice_autoconversion(t(:,k), qiic(:,k), lami(:,k), n0i(:,k), &
+ dcs, prci(:,k), nprci(:,k))
+ else
+ ! Add in the particles that we have already converted to snow, and
+ ! don't do any further autoconversion of ice.
+ prci(:,k) = tnd_qsnow(:,k) / cldm(:,k)
+ nprci(:,k) = tnd_nsnow(:,k) / cldm(:,k)
+ end if
+
+ ! note, currently we don't have this
+ ! inside the do_cldice block, should be changed later
+ ! assign qsic based on prognostic qs, using assumed precip fraction
+ qsic(:,k) = qs(:,k)/precip_frac(:,k)
+ nsic(:,k) = ns(:,k)/precip_frac(:,k)
+
+ ! limit in-precip mixing ratios to 10 g/kg
+ qsic(:,k)=min(qsic(:,k),0.01_r8)
+
+ ! if precip mix ratio is zero so should number concentration
+
+ where (qsic(:,k) < qsmall)
+ qsic(:,k)=0._r8
+ nsic(:,k)=0._r8
+ end where
+
+ ! make sure number concentration is a positive number to avoid
+ ! taking root of negative later
+
+ nsic(:,k)=max(nsic(:,k),0._r8)
+
+ !.......................................................................
+ ! get size distribution parameters for precip
+ !......................................................................
+ ! rain
+
+ call size_dist_param_basic(mg_rain_props, qric(:,k), nric(:,k), &
+ lamr(:,k), n0r(:,k))
+
+ where (lamr(:,k) >= qsmall)
+
+ ! provisional rain number and mass weighted mean fallspeed (m/s)
+
+ unr(:,k) = min(arn(:,k)*gamma_br_plus1/lamr(:,k)**br,9.1_r8*rhof(:,k))
+ umr(:,k) = min(arn(:,k)*gamma_br_plus4/(6._r8*lamr(:,k)**br),9.1_r8*rhof(:,k))
+
+ elsewhere
+ umr(:,k) = 0._r8
+ unr(:,k) = 0._r8
+ end where
+
+ !......................................................................
+ ! snow
+
+ call size_dist_param_basic(mg_snow_props, qsic(:,k), nsic(:,k), &
+ lams(:,k), n0s(:,k))
+
+ where (lams(:,k) > 0._r8)
+
+ ! provisional snow number and mass weighted mean fallspeed (m/s)
+
+ ums(:,k) = min(asn(:,k)*gamma_bs_plus4/(6._r8*lams(:,k)**bs),1.2_r8*rhof(:,k))
+ uns(:,k) = min(asn(:,k)*gamma_bs_plus1/lams(:,k)**bs,1.2_r8*rhof(:,k))
+
+ elsewhere
+ ums(:,k) = 0._r8
+ uns(:,k) = 0._r8
+ end where
+
+ if (do_cldice) then
+ if (.not. use_hetfrz_classnuc) then
+
+ ! heterogeneous freezing of cloud water
+ !----------------------------------------------
+
+ call immersion_freezing(microp_uniform, t(:,k), pgam(:,k), lamc(:,k), &
+ qcic(:,k), ncic(:,k), relvar(:,k), mnuccc(:,k), nnuccc(:,k))
+
+ ! make sure number of droplets frozen does not exceed available ice nuclei concentration
+ ! this prevents 'runaway' droplet freezing
+
+ where (qcic(:,k).ge.qsmall .and. t(:,k).lt.269.15_r8)
+ where (nnuccc(:,k)*lcldm(:,k).gt.nnuccd(:,k))
+ ! scale mixing ratio of droplet freezing with limit
+ mnuccc(:,k)=mnuccc(:,k)*(nnuccd(:,k)/(nnuccc(:,k)*lcldm(:,k)))
+ nnuccc(:,k)=nnuccd(:,k)/lcldm(:,k)
+ end where
+ end where
+
+ call contact_freezing(microp_uniform, t(:,k), p(:,k), rndst(:,k,:), &
+ nacon(:,k,:), pgam(:,k), lamc(:,k), qcic(:,k), ncic(:,k), &
+ relvar(:,k), mnucct(:,k), nnucct(:,k))
+
+ mnudep(:,k)=0._r8
+ nnudep(:,k)=0._r8
+
+ else
+
+ ! Mass of droplets frozen is the average droplet mass, except
+ ! with two limiters: concentration must be at least 1/cm^3, and
+ ! mass must be at least the minimum defined above.
+ mi0l = qcic(:,k)/max(ncic(:,k), 1.0e6_r8/rho(:,k))
+ mi0l = max(mi0l_min, mi0l)
+
+ where (qcic(:,k) >= qsmall)
+ nnuccc(:,k) = frzimm(:,k)*1.0e6_r8/rho(:,k)
+ mnuccc(:,k) = nnuccc(:,k)*mi0l
+
+ nnucct(:,k) = frzcnt(:,k)*1.0e6_r8/rho(:,k)
+ mnucct(:,k) = nnucct(:,k)*mi0l
+
+ nnudep(:,k) = frzdep(:,k)*1.0e6_r8/rho(:,k)
+ mnudep(:,k) = nnudep(:,k)*mi0
+ elsewhere
+ nnuccc(:,k) = 0._r8
+ mnuccc(:,k) = 0._r8
+
+ nnucct(:,k) = 0._r8
+ mnucct(:,k) = 0._r8
+
+ nnudep(:,k) = 0._r8
+ mnudep(:,k) = 0._r8
+ end where
+
+ end if
+
+ else
+ mnuccc(:,k)=0._r8
+ nnuccc(:,k)=0._r8
+ mnucct(:,k)=0._r8
+ nnucct(:,k)=0._r8
+ mnudep(:,k)=0._r8
+ nnudep(:,k)=0._r8
+ end if
+
+ call snow_self_aggregation(t(:,k), rho(:,k), asn(:,k), rhosn, qsic(:,k), nsic(:,k), &
+ nsagg(:,k))
+
+ call accrete_cloud_water_snow(t(:,k), rho(:,k), asn(:,k), uns(:,k), mu(:,k), &
+ qcic(:,k), ncic(:,k), qsic(:,k), pgam(:,k), lamc(:,k), lams(:,k), n0s(:,k), &
+ psacws(:,k), npsacws(:,k))
+
+ if (do_cldice) then
+ call secondary_ice_production(t(:,k), psacws(:,k), msacwi(:,k), nsacwi(:,k))
+ else
+ nsacwi(:,k) = 0.0_r8
+ msacwi(:,k) = 0.0_r8
+ end if
+
+ call accrete_rain_snow(t(:,k), rho(:,k), umr(:,k), ums(:,k), unr(:,k), uns(:,k), &
+ qric(:,k), qsic(:,k), lamr(:,k), n0r(:,k), lams(:,k), n0s(:,k), &
+ pracs(:,k), npracs(:,k))
+
+ call heterogeneous_rain_freezing(t(:,k), qric(:,k), nric(:,k), lamr(:,k), &
+ mnuccr(:,k), nnuccr(:,k))
+
+ call accrete_cloud_water_rain(microp_uniform, qric(:,k), qcic(:,k), &
+ ncic(:,k), relvar(:,k), accre_enhan(:,k), pra(:,k), npra(:,k))
+
+ call self_collection_rain(rho(:,k), qric(:,k), nric(:,k), nragg(:,k))
+
+ if (do_cldice) then
+ call accrete_cloud_ice_snow(t(:,k), rho(:,k), asn(:,k), qiic(:,k), niic(:,k), &
+ qsic(:,k), lams(:,k), n0s(:,k), prai(:,k), nprai(:,k))
+ else
+ prai(:,k) = 0._r8
+ nprai(:,k) = 0._r8
+ end if
+
+ call evaporate_sublimate_precip(t(:,k), rho(:,k), &
+ dv(:,k), mu(:,k), sc(:,k), q(:,k), qvl(:,k), qvi(:,k), &
+ lcldm(:,k), precip_frac(:,k), arn(:,k), asn(:,k), qcic(:,k), qiic(:,k), &
+ qric(:,k), qsic(:,k), lamr(:,k), n0r(:,k), lams(:,k), n0s(:,k), &
+ pre(:,k), prds(:,k))
+
+ call bergeron_process_snow(t(:,k), rho(:,k), dv(:,k), mu(:,k), sc(:,k), &
+ qvl(:,k), qvi(:,k), asn(:,k), qcic(:,k), qsic(:,k), lams(:,k), n0s(:,k), &
+ bergs(:,k))
+
+ bergs(:,k)=bergs(:,k)*micro_mg_berg_eff_factor
+
+ !+++PMC 12/3/12 - NEW VAPOR DEP/SUBLIMATION GOES HERE!!!
+ if (do_cldice) then
+
+ call ice_deposition_sublimation(t(:,k), q(:,k), qi(:,k), ni(:,k), &
+ icldm(:,k), rho(:,k), dv(:,k), qvl(:,k), qvi(:,k), &
+ berg(:,k), vap_dep(:,k), ice_sublim(:,k))
+
+ berg(:,k)=berg(:,k)*micro_mg_berg_eff_factor
+
+ where (vap_dep(:,k) < 0._r8 .and. qi(:,k) > qsmall .and. icldm(:,k) > mincld)
+ nsubi(:,k) = vap_dep(:,k) / qi(:,k) * ni(:,k) / icldm(:,k)
+ elsewhere
+ nsubi(:,k) = 0._r8
+ end where
+
+ ! bergeron process should not reduce nc unless
+ ! all ql is removed (which is handled elsewhere)
+ !in fact, nothing in this entire file makes nsubc nonzero.
+ nsubc(:,k) = 0._r8
+
+ end if !do_cldice
+ !---PMC 12/3/12
+
+ do i=1,mgncol
+
+ ! conservation to ensure no negative values of cloud water/precipitation
+ ! in case microphysical process rates are large
+ !===================================================================
+
+ ! note: for check on conservation, processes are multiplied by omsm
+ ! to prevent problems due to round off error
+
+ ! conservation of qc
+ !-------------------------------------------------------------------
+
+ dum = ((prc(i,k)+pra(i,k)+mnuccc(i,k)+mnucct(i,k)+msacwi(i,k)+ &
+ psacws(i,k)+bergs(i,k))*lcldm(i,k)+berg(i,k))*deltat
+
+ if (dum.gt.qc(i,k)) then
+ ratio = qc(i,k)/deltat/((prc(i,k)+pra(i,k)+mnuccc(i,k)+mnucct(i,k)+ &
+ msacwi(i,k)+psacws(i,k)+bergs(i,k))*lcldm(i,k)+berg(i,k))*omsm
+ prc(i,k) = prc(i,k)*ratio
+ pra(i,k) = pra(i,k)*ratio
+ mnuccc(i,k) = mnuccc(i,k)*ratio
+ mnucct(i,k) = mnucct(i,k)*ratio
+ msacwi(i,k) = msacwi(i,k)*ratio
+ psacws(i,k) = psacws(i,k)*ratio
+ bergs(i,k) = bergs(i,k)*ratio
+ berg(i,k) = berg(i,k)*ratio
+ qcrat(i,k) = ratio
+ else
+ qcrat(i,k) = 1._r8
+ end if
+
+ !PMC 12/3/12: ratio is also frac of step w/ liquid.
+ !thus we apply berg for "ratio" of timestep and vapor
+ !deposition for the remaining frac of the timestep.
+ if (qc(i,k) >= qsmall) then
+ vap_dep(i,k) = vap_dep(i,k)*(1._r8-qcrat(i,k))
+ end if
+
+ end do
+
+ do i=1,mgncol
+
+ !=================================================================
+ ! apply limiter to ensure that ice/snow sublimation and rain evap
+ ! don't push conditions into supersaturation, and ice deposition/nucleation don't
+ ! push conditions into sub-saturation
+ ! note this is done after qc conservation since we don't know how large
+ ! vap_dep is before then
+ ! estimates are only approximate since other process terms haven't been limited
+ ! for conservation yet
+
+ ! first limit ice deposition/nucleation vap_dep + mnuccd
+ dum1 = vap_dep(i,k) + mnuccd(i,k)
+ if (dum1 > 1.e-20_r8) then
+ dum = (q(i,k)-qvi(i,k))/(1._r8 + xxls_squared*qvi(i,k)/(cpp*rv*t(i,k)**2))/deltat
+ dum = max(dum,0._r8)
+ if (dum1 > dum) then
+ ! Allocate the limited "dum" tendency to mnuccd and vap_dep
+ ! processes. Don't divide by cloud fraction; these are grid-
+ ! mean rates.
+ dum1 = mnuccd(i,k) / (vap_dep(i,k)+mnuccd(i,k))
+ mnuccd(i,k) = dum*dum1
+ vap_dep(i,k) = dum - mnuccd(i,k)
+ end if
+ end if
+
+ end do
+
+ do i=1,mgncol
+
+ !===================================================================
+ ! conservation of nc
+ !-------------------------------------------------------------------
+ dum = (nprc1(i,k)+npra(i,k)+nnuccc(i,k)+nnucct(i,k)+ &
+ npsacws(i,k)-nsubc(i,k))*lcldm(i,k)*deltat
+
+ if (dum.gt.nc(i,k)) then
+ ratio = nc(i,k)/deltat/((nprc1(i,k)+npra(i,k)+nnuccc(i,k)+nnucct(i,k)+&
+ npsacws(i,k)-nsubc(i,k))*lcldm(i,k))*omsm
+
+ nprc1(i,k) = nprc1(i,k)*ratio
+ npra(i,k) = npra(i,k)*ratio
+ nnuccc(i,k) = nnuccc(i,k)*ratio
+ nnucct(i,k) = nnucct(i,k)*ratio
+ npsacws(i,k) = npsacws(i,k)*ratio
+ nsubc(i,k)=nsubc(i,k)*ratio
+ end if
+
+ mnuccri(i,k)=0._r8
+ nnuccri(i,k)=0._r8
+
+ if (do_cldice) then
+
+ ! freezing of rain to produce ice if mean rain size is smaller than Dcs
+ if (lamr(i,k) > qsmall .and. 1._r8/lamr(i,k) < Dcs) then
+ mnuccri(i,k)=mnuccr(i,k)
+ nnuccri(i,k)=nnuccr(i,k)
+ mnuccr(i,k)=0._r8
+ nnuccr(i,k)=0._r8
+ end if
+ end if
+
+ end do
+
+ do i=1,mgncol
+
+ ! conservation of rain mixing ratio
+ !-------------------------------------------------------------------
+ dum = ((-pre(i,k)+pracs(i,k)+mnuccr(i,k)+mnuccri(i,k))*precip_frac(i,k)- &
+ (pra(i,k)+prc(i,k))*lcldm(i,k))*deltat
+
+ ! note that qrtend is included below because of instantaneous freezing/melt
+ if (dum.gt.qr(i,k).and. &
+ (-pre(i,k)+pracs(i,k)+mnuccr(i,k)+mnuccri(i,k)).ge.qsmall) then
+ ratio = (qr(i,k)/deltat+(pra(i,k)+prc(i,k))*lcldm(i,k))/ &
+ precip_frac(i,k)/(-pre(i,k)+pracs(i,k)+mnuccr(i,k)+mnuccri(i,k))*omsm
+ pre(i,k)=pre(i,k)*ratio
+ pracs(i,k)=pracs(i,k)*ratio
+ mnuccr(i,k)=mnuccr(i,k)*ratio
+ mnuccri(i,k)=mnuccri(i,k)*ratio
+ end if
+
+ end do
+
+ do i=1,mgncol
+
+ ! conservation of rain number
+ !-------------------------------------------------------------------
+
+ ! Add evaporation of rain number.
+ if (pre(i,k) < 0._r8) then
+ dum = pre(i,k)*deltat/qr(i,k)
+ dum = max(-1._r8,dum)
+ nsubr(i,k) = dum*nr(i,k)/deltat
+ else
+ nsubr(i,k) = 0._r8
+ end if
+
+ end do
+
+ do i=1,mgncol
+
+ dum = ((-nsubr(i,k)+npracs(i,k)+nnuccr(i,k)+nnuccri(i,k)-nragg(i,k))*precip_frac(i,k)- &
+ nprc(i,k)*lcldm(i,k))*deltat
+
+ if (dum.gt.nr(i,k)) then
+ ratio = (nr(i,k)/deltat+nprc(i,k)*lcldm(i,k)/precip_frac(i,k))/ &
+ (-nsubr(i,k)+npracs(i,k)+nnuccr(i,k)+nnuccri(i,k)-nragg(i,k))*omsm
+
+ nragg(i,k)=nragg(i,k)*ratio
+ npracs(i,k)=npracs(i,k)*ratio
+ nnuccr(i,k)=nnuccr(i,k)*ratio
+ nsubr(i,k)=nsubr(i,k)*ratio
+ nnuccri(i,k)=nnuccri(i,k)*ratio
+ end if
+
+ end do
+
+ if (do_cldice) then
+
+ do i=1,mgncol
+
+ ! conservation of qi
+ !-------------------------------------------------------------------
+
+ dum = ((-mnuccc(i,k)-mnucct(i,k)-mnudep(i,k)-msacwi(i,k))*lcldm(i,k)+(prci(i,k)+ &
+ prai(i,k))*icldm(i,k)-mnuccri(i,k)*precip_frac(i,k) &
+ -ice_sublim(i,k)-vap_dep(i,k)-berg(i,k)-mnuccd(i,k))*deltat
+
+ if (dum.gt.qi(i,k)) then
+ ratio = (qi(i,k)/deltat+vap_dep(i,k)+berg(i,k)+mnuccd(i,k)+ &
+ (mnuccc(i,k)+mnucct(i,k)+mnudep(i,k)+msacwi(i,k))*lcldm(i,k)+ &
+ mnuccri(i,k)*precip_frac(i,k))/ &
+ ((prci(i,k)+prai(i,k))*icldm(i,k)-ice_sublim(i,k))*omsm
+ prci(i,k) = prci(i,k)*ratio
+ prai(i,k) = prai(i,k)*ratio
+ ice_sublim(i,k) = ice_sublim(i,k)*ratio
+ end if
+
+ end do
+
+ end if
+
+ if (do_cldice) then
+
+ do i=1,mgncol
+
+ ! conservation of ni
+ !-------------------------------------------------------------------
+ if (use_hetfrz_classnuc) then
+ tmpfrz = nnuccc(i,k)
+ else
+ tmpfrz = 0._r8
+ end if
+ dum = ((-nnucct(i,k)-tmpfrz-nnudep(i,k)-nsacwi(i,k))*lcldm(i,k)+(nprci(i,k)+ &
+ nprai(i,k)-nsubi(i,k))*icldm(i,k)-nnuccri(i,k)*precip_frac(i,k)- &
+ nnuccd(i,k))*deltat
+
+ if (dum.gt.ni(i,k)) then
+ ratio = (ni(i,k)/deltat+nnuccd(i,k)+ &
+ (nnucct(i,k)+tmpfrz+nnudep(i,k)+nsacwi(i,k))*lcldm(i,k)+ &
+ nnuccri(i,k)*precip_frac(i,k))/ &
+ ((nprci(i,k)+nprai(i,k)-nsubi(i,k))*icldm(i,k))*omsm
+ nprci(i,k) = nprci(i,k)*ratio
+ nprai(i,k) = nprai(i,k)*ratio
+ nsubi(i,k) = nsubi(i,k)*ratio
+ end if
+
+ end do
+
+ end if
+
+ do i=1,mgncol
+
+ ! conservation of snow mixing ratio
+ !-------------------------------------------------------------------
+ dum = (-(prds(i,k)+pracs(i,k)+mnuccr(i,k))*precip_frac(i,k)-(prai(i,k)+prci(i,k))*icldm(i,k) &
+ -(bergs(i,k)+psacws(i,k))*lcldm(i,k))*deltat
+
+ if (dum.gt.qs(i,k).and.-prds(i,k).ge.qsmall) then
+ ratio = (qs(i,k)/deltat+(prai(i,k)+prci(i,k))*icldm(i,k)+ &
+ (bergs(i,k)+psacws(i,k))*lcldm(i,k)+(pracs(i,k)+mnuccr(i,k))*precip_frac(i,k))/ &
+ precip_frac(i,k)/(-prds(i,k))*omsm
+ prds(i,k)=prds(i,k)*ratio
+ end if
+
+ end do
+
+ do i=1,mgncol
+
+ ! conservation of snow number
+ !-------------------------------------------------------------------
+ ! calculate loss of number due to sublimation
+ ! for now neglect sublimation of ns
+ nsubs(i,k)=0._r8
+
+ dum = ((-nsagg(i,k)-nsubs(i,k)-nnuccr(i,k))*precip_frac(i,k)-nprci(i,k)*icldm(i,k))*deltat
+
+ if (dum.gt.ns(i,k)) then
+ ratio = (ns(i,k)/deltat+nnuccr(i,k)* &
+ precip_frac(i,k)+nprci(i,k)*icldm(i,k))/precip_frac(i,k)/ &
+ (-nsubs(i,k)-nsagg(i,k))*omsm
+ nsubs(i,k)=nsubs(i,k)*ratio
+ nsagg(i,k)=nsagg(i,k)*ratio
+ end if
+
+ end do
+
+ do i=1,mgncol
+
+ ! next limit ice and snow sublimation and rain evaporation
+ ! get estimate of q and t at end of time step
+ ! don't include other microphysical processes since they haven't
+ ! been limited via conservation checks yet
+
+ if ((pre(i,k)+prds(i,k))*precip_frac(i,k)+ice_sublim(i,k) < -1.e-20_r8) then
+
+ qtmp=q(i,k)-(ice_sublim(i,k)+vap_dep(i,k)+mnuccd(i,k)+ &
+ (pre(i,k)+prds(i,k))*precip_frac(i,k))*deltat
+ ttmp=t(i,k)+((pre(i,k)*precip_frac(i,k))*xxlv+ &
+ (prds(i,k)*precip_frac(i,k)+vap_dep(i,k)+ice_sublim(i,k)+mnuccd(i,k))*xxls)*deltat/cpp
+
+ ! use rhw to allow ice supersaturation
+ call qsat_water(ttmp, p(i,k), esn, qvn)
+
+ ! modify ice/precip evaporation rate if q > qsat
+ if (qtmp > qvn) then
+
+ dum1=pre(i,k)*precip_frac(i,k)/((pre(i,k)+prds(i,k))*precip_frac(i,k)+ice_sublim(i,k))
+ dum2=prds(i,k)*precip_frac(i,k)/((pre(i,k)+prds(i,k))*precip_frac(i,k)+ice_sublim(i,k))
+ ! recalculate q and t after vap_dep and mnuccd but without evap or sublim
+ qtmp=q(i,k)-(vap_dep(i,k)+mnuccd(i,k))*deltat
+ ttmp=t(i,k)+((vap_dep(i,k)+mnuccd(i,k))*xxls)*deltat/cpp
+
+ ! use rhw to allow ice supersaturation
+ call qsat_water(ttmp, p(i,k), esn, qvn)
+
+ dum=(qtmp-qvn)/(1._r8 + xxlv_squared*qvn/(cpp*rv*ttmp**2))
+ dum=min(dum,0._r8)
+
+ ! modify rates if needed, divide by precip_frac to get local (in-precip) value
+ pre(i,k)=dum*dum1/deltat/precip_frac(i,k)
+
+ ! do separately using RHI for prds and ice_sublim
+ call qsat_ice(ttmp, p(i,k), esn, qvn)
+
+ dum=(qtmp-qvn)/(1._r8 + xxls_squared*qvn/(cpp*rv*ttmp**2))
+ dum=min(dum,0._r8)
+
+ ! modify rates if needed, divide by precip_frac to get local (in-precip) value
+ prds(i,k) = dum*dum2/deltat/precip_frac(i,k)
+
+ ! don't divide ice_sublim by cloud fraction since it is grid-averaged
+ dum1 = (1._r8-dum1-dum2)
+ ice_sublim(i,k) = dum*dum1/deltat
+ end if
+ end if
+
+ end do
+
+ ! Big "administration" loop enforces conservation, updates variables
+ ! that accumulate over substeps, and sets output variables.
+
+ do i=1,mgncol
+
+ ! get tendencies due to microphysical conversion processes
+ !==========================================================
+ ! note: tendencies are multiplied by appropriate cloud/precip
+ ! fraction to get grid-scale values
+ ! note: vap_dep is already grid-average values
+
+ ! The net tendencies need to be added to rather than overwritten,
+ ! because they may have a value already set for instantaneous
+ ! melting/freezing.
+
+ qvlat(i,k) = qvlat(i,k)-(pre(i,k)+prds(i,k))*precip_frac(i,k)-&
+ vap_dep(i,k)-ice_sublim(i,k)-mnuccd(i,k)-mnudep(i,k)*lcldm(i,k)
+
+ tlat(i,k) = tlat(i,k)+((pre(i,k)*precip_frac(i,k)) &
+ *xxlv+(prds(i,k)*precip_frac(i,k)+vap_dep(i,k)+ice_sublim(i,k)+mnuccd(i,k)+mnudep(i,k)*lcldm(i,k))*xxls+ &
+ ((bergs(i,k)+psacws(i,k)+mnuccc(i,k)+mnucct(i,k)+msacwi(i,k))*lcldm(i,k)+(mnuccr(i,k)+ &
+ pracs(i,k)+mnuccri(i,k))*precip_frac(i,k)+berg(i,k))*xlf)
+
+ qctend(i,k) = qctend(i,k)+ &
+ (-pra(i,k)-prc(i,k)-mnuccc(i,k)-mnucct(i,k)-msacwi(i,k)- &
+ psacws(i,k)-bergs(i,k))*lcldm(i,k)-berg(i,k)
+
+ if (do_cldice) then
+ qitend(i,k) = qitend(i,k)+ &
+ (mnuccc(i,k)+mnucct(i,k)+mnudep(i,k)+msacwi(i,k))*lcldm(i,k)+(-prci(i,k)- &
+ prai(i,k))*icldm(i,k)+vap_dep(i,k)+berg(i,k)+ice_sublim(i,k)+ &
+ mnuccd(i,k)+mnuccri(i,k)*precip_frac(i,k)
+ end if
+
+ qrtend(i,k) = qrtend(i,k)+ &
+ (pra(i,k)+prc(i,k))*lcldm(i,k)+(pre(i,k)-pracs(i,k)- &
+ mnuccr(i,k)-mnuccri(i,k))*precip_frac(i,k)
+
+ qstend(i,k) = qstend(i,k)+ &
+ (prai(i,k)+prci(i,k))*icldm(i,k)+(psacws(i,k)+bergs(i,k))*lcldm(i,k)+(prds(i,k)+ &
+ pracs(i,k)+mnuccr(i,k))*precip_frac(i,k)
+
+
+ cmeout(i,k) = vap_dep(i,k) + ice_sublim(i,k) + mnuccd(i,k)
+
+ ! add output for cmei (accumulate)
+ cmeitot(i,k) = vap_dep(i,k) + ice_sublim(i,k) + mnuccd(i,k)
+
+ ! assign variables for trop_mozart, these are grid-average
+ !-------------------------------------------------------------------
+ ! evaporation/sublimation is stored here as positive term
+
+ evapsnow(i,k) = -prds(i,k)*precip_frac(i,k)
+ nevapr(i,k) = -pre(i,k)*precip_frac(i,k)
+ prer_evap(i,k) = -pre(i,k)*precip_frac(i,k)
+
+ ! change to make sure prain is positive: do not remove snow from
+ ! prain used for wet deposition
+ prain(i,k) = (pra(i,k)+prc(i,k))*lcldm(i,k)+(-pracs(i,k)- &
+ mnuccr(i,k)-mnuccri(i,k))*precip_frac(i,k)
+ prodsnow(i,k) = (prai(i,k)+prci(i,k))*icldm(i,k)+(psacws(i,k)+bergs(i,k))*lcldm(i,k)+(&
+ pracs(i,k)+mnuccr(i,k))*precip_frac(i,k)
+
+ ! following are used to calculate 1st order conversion rate of cloud water
+ ! to rain and snow (1/s), for later use in aerosol wet removal routine
+ ! previously, wetdepa used (prain/qc) for this, and the qc in wetdepa may be smaller than the qc
+ ! used to calculate pra, prc, ... in this routine
+ ! qcsinksum_rate1ord = { rate of direct transfer of cloud water to rain & snow }
+ ! (no cloud ice or bergeron terms)
+ qcsinksum_rate1ord(i,k) = (pra(i,k)+prc(i,k)+psacws(i,k))*lcldm(i,k)
+ ! Avoid zero/near-zero division.
+ qcsinksum_rate1ord(i,k) = qcsinksum_rate1ord(i,k) / &
+ max(qc(i,k),1.0e-30_r8)
+
+
+ ! microphysics output, note this is grid-averaged
+ pratot(i,k) = pra(i,k)*lcldm(i,k)
+ prctot(i,k) = prc(i,k)*lcldm(i,k)
+ mnuccctot(i,k) = mnuccc(i,k)*lcldm(i,k)
+ mnuccttot(i,k) = mnucct(i,k)*lcldm(i,k)
+ msacwitot(i,k) = msacwi(i,k)*lcldm(i,k)
+ psacwstot(i,k) = psacws(i,k)*lcldm(i,k)
+ bergstot(i,k) = bergs(i,k)*lcldm(i,k)
+ bergtot(i,k) = berg(i,k)
+ prcitot(i,k) = prci(i,k)*icldm(i,k)
+ praitot(i,k) = prai(i,k)*icldm(i,k)
+ mnuccdtot(i,k) = mnuccd(i,k)*icldm(i,k)
+
+ pracstot(i,k) = pracs(i,k)*precip_frac(i,k)
+ mnuccrtot(i,k) = mnuccr(i,k)*precip_frac(i,k)
+
+
+ nctend(i,k) = nctend(i,k)+&
+ (-nnuccc(i,k)-nnucct(i,k)-npsacws(i,k)+nsubc(i,k) &
+ -npra(i,k)-nprc1(i,k))*lcldm(i,k)
+
+ if (do_cldice) then
+ if (use_hetfrz_classnuc) then
+ tmpfrz = nnuccc(i,k)
+ else
+ tmpfrz = 0._r8
+ end if
+ nitend(i,k) = nitend(i,k)+ nnuccd(i,k)+ &
+ (nnucct(i,k)+tmpfrz+nnudep(i,k)+nsacwi(i,k))*lcldm(i,k)+(nsubi(i,k)-nprci(i,k)- &
+ nprai(i,k))*icldm(i,k)+nnuccri(i,k)*precip_frac(i,k)
+ end if
+
+ nstend(i,k) = nstend(i,k)+(nsubs(i,k)+ &
+ nsagg(i,k)+nnuccr(i,k))*precip_frac(i,k)+nprci(i,k)*icldm(i,k)
+
+ nrtend(i,k) = nrtend(i,k)+ &
+ nprc(i,k)*lcldm(i,k)+(nsubr(i,k)-npracs(i,k)-nnuccr(i,k) &
+ -nnuccri(i,k)+nragg(i,k))*precip_frac(i,k)
+
+ ! make sure that ni at advanced time step does not exceed
+ ! maximum (existing N + source terms*dt), which is possible if mtime < deltat
+ ! note that currently mtime = deltat
+ !================================================================
+
+ if (do_cldice .and. nitend(i,k).gt.0._r8.and.ni(i,k)+nitend(i,k)*deltat.gt.nimax(i,k)) then
+ nitend(i,k)=max(0._r8,(nimax(i,k)-ni(i,k))/deltat)
+ end if
+
+ end do
+
+ ! End of "administration" loop
+
+ end do micro_vert_loop ! end k loop
+
+ !-----------------------------------------------------
+ ! convert rain/snow q and N for output to history, note,
+ ! output is for gridbox average
+
+ qrout = qr
+ nrout = nr * rho
+ qsout = qs
+ nsout = ns * rho
+
+ ! calculate precip fluxes
+ ! calculate the precip flux (kg/m2/s) as mixingratio(kg/kg)*airdensity(kg/m3)*massweightedfallspeed(m/s)
+ ! ---------------------------------------------------------------------
+
+ rflx(:,2:) = rflx(:,2:) + (qric*rho*umr*precip_frac)
+ sflx(:,2:) = sflx(:,2:) + (qsic*rho*ums*precip_frac)
+
+ ! calculate n0r and lamr from rain mass and number
+ ! divide by precip fraction to get in-precip (local) values of
+ ! rain mass and number, divide by rhow to get rain number in kg^-1
+
+ call size_dist_param_basic(mg_rain_props, qric, nric, lamr, n0r)
+
+ ! Calculate rercld
+
+ ! calculate mean size of combined rain and cloud water
+
+ call calc_rercld(lamr, n0r, lamc, pgam, qric, qcic, ncic, &
+ rercld)
+
+
+ ! Assign variables back to start-of-timestep values
+ ! Some state variables are changed before the main microphysics loop
+ ! to make "instantaneous" adjustments. Afterward, we must move those changes
+ ! back into the tendencies.
+ ! These processes:
+ ! - Droplet activation (npccn, impacts nc)
+ ! - Instantaneous snow melting (minstsm/ninstsm, impacts qr/qs/nr/ns)
+ ! - Instantaneous rain freezing (minstfr/ninstrf, impacts qr/qs/nr/ns)
+ !================================================================================
+
+ ! Re-apply droplet activation tendency
+ nc = ncn
+ nctend = nctend + npccn
+
+ ! Re-apply rain freezing and snow melting.
+ dum_2D = qs
+ qs = qsn
+ qstend = qstend + (dum_2D-qs)/deltat
+
+ dum_2D = ns
+ ns = nsn
+ nstend = nstend + (dum_2D-ns)/deltat
+
+ dum_2D = qr
+ qr = qrn
+ qrtend = qrtend + (dum_2D-qr)/deltat
+
+ dum_2D = nr
+ nr = nrn
+ nrtend = nrtend + (dum_2D-nr)/deltat
+
+ !.............................................................................
+
+ !================================================================================
+
+ ! modify to include snow. in prain & evap (diagnostic here: for wet dep)
+ nevapr = nevapr + evapsnow
+ prain = prain + prodsnow
+
+ sed_col_loop: do i=1,mgncol
+
+ do k=1,nlev
+
+ ! calculate sedimentation for cloud water and ice
+ !================================================================================
+
+ ! update in-cloud cloud mixing ratio and number concentration
+ ! with microphysical tendencies to calculate sedimentation, assign to dummy vars
+ ! note: these are in-cloud values***, hence we divide by cloud fraction
+
+ dumc(i,k) = (qc(i,k)+qctend(i,k)*deltat)/lcldm(i,k)
+ dumi(i,k) = (qi(i,k)+qitend(i,k)*deltat)/icldm(i,k)
+ dumnc(i,k) = max((nc(i,k)+nctend(i,k)*deltat)/lcldm(i,k),0._r8)
+ dumni(i,k) = max((ni(i,k)+nitend(i,k)*deltat)/icldm(i,k),0._r8)
+
+ dumr(i,k) = (qr(i,k)+qrtend(i,k)*deltat)/precip_frac(i,k)
+ dumnr(i,k) = max((nr(i,k)+nrtend(i,k)*deltat)/precip_frac(i,k),0._r8)
+ dums(i,k) = (qs(i,k)+qstend(i,k)*deltat)/precip_frac(i,k)
+ dumns(i,k) = max((ns(i,k)+nstend(i,k)*deltat)/precip_frac(i,k),0._r8)
+
+
+ ! switch for specification of droplet and crystal number
+ if (nccons) then
+ dumnc(i,k)=ncnst/rho(i,k)
+ end if
+
+ ! switch for specification of cloud ice number
+ if (nicons) then
+ dumni(i,k)=ninst/rho(i,k)
+ end if
+
+ ! obtain new slope parameter to avoid possible singularity
+
+ call size_dist_param_basic(mg_ice_props, dumi(i,k), dumni(i,k), &
+ lami(i,k))
+
+ call size_dist_param_liq(mg_liq_props, dumc(i,k), dumnc(i,k), rho(i,k), &
+ pgam(i,k), lamc(i,k))
+
+ ! calculate number and mass weighted fall velocity for droplets and cloud ice
+ !-------------------------------------------------------------------
+
+
+ if (dumc(i,k).ge.qsmall) then
+
+ vtrmc(i,k)=acn(i,k)*gamma(4._r8+bc+pgam(i,k))/ &
+ (lamc(i,k)**bc*gamma(pgam(i,k)+4._r8))
+
+ fc(k) = g*rho(i,k)*vtrmc(i,k)
+
+ fnc(k) = g*rho(i,k)* &
+ acn(i,k)*gamma(1._r8+bc+pgam(i,k))/ &
+ (lamc(i,k)**bc*gamma(pgam(i,k)+1._r8))
+ else
+ fc(k) = 0._r8
+ fnc(k)= 0._r8
+ end if
+
+ ! calculate number and mass weighted fall velocity for cloud ice
+
+ if (dumi(i,k).ge.qsmall) then
+
+ vtrmi(i,k)=min(ain(i,k)*gamma_bi_plus4/(6._r8*lami(i,k)**bi), &
+ 1.2_r8*rhof(i,k))
+
+ fi(k) = g*rho(i,k)*vtrmi(i,k)
+ fni(k) = g*rho(i,k)* &
+ min(ain(i,k)*gamma_bi_plus1/lami(i,k)**bi,1.2_r8*rhof(i,k))
+ else
+ fi(k) = 0._r8
+ fni(k)= 0._r8
+ end if
+
+ ! fallspeed for rain
+
+ call size_dist_param_basic(mg_rain_props, dumr(i,k), dumnr(i,k), &
+ lamr(i,k))
+
+ if (lamr(i,k).ge.qsmall) then
+
+ ! 'final' values of number and mass weighted mean fallspeed for rain (m/s)
+
+ unr(i,k) = min(arn(i,k)*gamma_br_plus1/lamr(i,k)**br,9.1_r8*rhof(i,k))
+ umr(i,k) = min(arn(i,k)*gamma_br_plus4/(6._r8*lamr(i,k)**br),9.1_r8*rhof(i,k))
+
+ fr(k) = g*rho(i,k)*umr(i,k)
+ fnr(k) = g*rho(i,k)*unr(i,k)
+
+ else
+ fr(k)=0._r8
+ fnr(k)=0._r8
+ end if
+
+ ! fallspeed for snow
+
+ call size_dist_param_basic(mg_snow_props, dums(i,k), dumns(i,k), &
+ lams(i,k))
+
+ if (lams(i,k).ge.qsmall) then
+
+ ! 'final' values of number and mass weighted mean fallspeed for snow (m/s)
+ ums(i,k) = min(asn(i,k)*gamma_bs_plus4/(6._r8*lams(i,k)**bs),1.2_r8*rhof(i,k))
+ uns(i,k) = min(asn(i,k)*gamma_bs_plus1/lams(i,k)**bs,1.2_r8*rhof(i,k))
+
+ fs(k) = g*rho(i,k)*ums(i,k)
+ fns(k) = g*rho(i,k)*uns(i,k)
+
+ else
+ fs(k)=0._r8
+ fns(k)=0._r8
+ end if
+
+ ! redefine dummy variables - sedimentation is calculated over grid-scale
+ ! quantities to ensure conservation
+
+ dumc(i,k) = (qc(i,k)+qctend(i,k)*deltat)
+ dumnc(i,k) = max((nc(i,k)+nctend(i,k)*deltat),0._r8)
+ dumi(i,k) = (qi(i,k)+qitend(i,k)*deltat)
+ dumni(i,k) = max((ni(i,k)+nitend(i,k)*deltat),0._r8)
+ dumr(i,k) = (qr(i,k)+qrtend(i,k)*deltat)
+ dumnr(i,k) = max((nr(i,k)+nrtend(i,k)*deltat),0._r8)
+ dums(i,k) = (qs(i,k)+qstend(i,k)*deltat)
+ dumns(i,k) = max((ns(i,k)+nstend(i,k)*deltat),0._r8)
+
+ if (dumc(i,k).lt.qsmall) dumnc(i,k)=0._r8
+ if (dumi(i,k).lt.qsmall) dumni(i,k)=0._r8
+ if (dumr(i,k).lt.qsmall) dumnr(i,k)=0._r8
+ if (dums(i,k).lt.qsmall) dumns(i,k)=0._r8
+
+ end do !!! vertical loop
+
+ ! initialize nstep for sedimentation sub-steps
+
+ ! calculate number of split time steps to ensure courant stability criteria
+ ! for sedimentation calculations
+ !-------------------------------------------------------------------
+ nstep = 1 + int(max( &
+ maxval( fi/pdel(i,:)), &
+ maxval(fni/pdel(i,:))) &
+ * deltat)
+
+
+ ! loop over sedimentation sub-time step to ensure stability
+ !==============================================================
+ do n = 1,nstep
+
+ if (do_cldice) then
+ falouti = fi * dumi(i,:)
+ faloutni = fni * dumni(i,:)
+ else
+ falouti = 0._r8
+ faloutni = 0._r8
+ end if
+
+ ! top of model
+
+ k = 1
+
+ ! add fallout terms to microphysical tendencies
+ faltndi = falouti(k)/pdel(i,k)
+ faltndni = faloutni(k)/pdel(i,k)
+ qitend(i,k) = qitend(i,k)-faltndi/nstep
+ nitend(i,k) = nitend(i,k)-faltndni/nstep
+
+ ! sedimentation tendency for output
+ qisedten(i,k)=qisedten(i,k)-faltndi/nstep
+
+ dumi(i,k) = dumi(i,k)-faltndi*deltat/nstep
+ dumni(i,k) = dumni(i,k)-faltndni*deltat/nstep
+
+ do k = 2,nlev
+
+ ! for cloud liquid and ice, if cloud fraction increases with height
+ ! then add flux from above to both vapor and cloud water of current level
+ ! this means that flux entering clear portion of cell from above evaporates
+ ! instantly
+
+ ! note: this is not an issue with precip, since we assume max overlap
+ dum1=icldm(i,k)/icldm(i,k-1)
+ dum1=min(dum1,1._r8)
+
+ faltndqie=(falouti(k)-falouti(k-1))/pdel(i,k)
+ faltndi=(falouti(k)-dum1*falouti(k-1))/pdel(i,k)
+ faltndni=(faloutni(k)-dum1*faloutni(k-1))/pdel(i,k)
+
+ ! add fallout terms to eulerian tendencies
+
+ qitend(i,k) = qitend(i,k)-faltndi/nstep
+ nitend(i,k) = nitend(i,k)-faltndni/nstep
+
+ ! sedimentation tendency for output
+ qisedten(i,k)=qisedten(i,k)-faltndi/nstep
+
+ ! add terms to to evap/sub of cloud water
+
+ qvlat(i,k)=qvlat(i,k)-(faltndqie-faltndi)/nstep
+ ! for output
+ qisevap(i,k)=qisevap(i,k)-(faltndqie-faltndi)/nstep
+
+ tlat(i,k)=tlat(i,k)+(faltndqie-faltndi)*xxls/nstep
+
+ dumi(i,k) = dumi(i,k)-faltndi*deltat/nstep
+ dumni(i,k) = dumni(i,k)-faltndni*deltat/nstep
+
+ end do
+
+ ! units below are m/s
+ ! sedimentation flux at surface is added to precip flux at surface
+ ! to get total precip (cloud + precip water) rate
+
+ prect(i) = prect(i)+falouti(nlev)/g/real(nstep)/1000._r8
+ preci(i) = preci(i)+falouti(nlev)/g/real(nstep)/1000._r8
+
+ end do
+
+ ! calculate number of split time steps to ensure courant stability criteria
+ ! for sedimentation calculations
+ !-------------------------------------------------------------------
+ nstep = 1 + int(max( &
+ maxval( fc/pdel(i,:)), &
+ maxval(fnc/pdel(i,:))) &
+ * deltat)
+
+ ! loop over sedimentation sub-time step to ensure stability
+ !==============================================================
+ do n = 1,nstep
+
+ faloutc = fc * dumc(i,:)
+ faloutnc = fnc * dumnc(i,:)
+
+ ! top of model
+ k = 1
+
+ ! add fallout terms to microphysical tendencies
+ faltndc = faloutc(k)/pdel(i,k)
+ faltndnc = faloutnc(k)/pdel(i,k)
+ qctend(i,k) = qctend(i,k)-faltndc/nstep
+ nctend(i,k) = nctend(i,k)-faltndnc/nstep
+
+ ! sedimentation tendency for output
+ qcsedten(i,k)=qcsedten(i,k)-faltndc/nstep
+
+ dumc(i,k) = dumc(i,k)-faltndc*deltat/nstep
+ dumnc(i,k) = dumnc(i,k)-faltndnc*deltat/nstep
+
+ do k = 2,nlev
+
+ dum=lcldm(i,k)/lcldm(i,k-1)
+ dum=min(dum,1._r8)
+ faltndqce=(faloutc(k)-faloutc(k-1))/pdel(i,k)
+ faltndc=(faloutc(k)-dum*faloutc(k-1))/pdel(i,k)
+ faltndnc=(faloutnc(k)-dum*faloutnc(k-1))/pdel(i,k)
+
+ ! add fallout terms to eulerian tendencies
+ qctend(i,k) = qctend(i,k)-faltndc/nstep
+ nctend(i,k) = nctend(i,k)-faltndnc/nstep
+
+ ! sedimentation tendency for output
+ qcsedten(i,k)=qcsedten(i,k)-faltndc/nstep
+
+ ! add terms to to evap/sub of cloud water
+ qvlat(i,k)=qvlat(i,k)-(faltndqce-faltndc)/nstep
+ ! for output
+ qcsevap(i,k)=qcsevap(i,k)-(faltndqce-faltndc)/nstep
+
+ tlat(i,k)=tlat(i,k)+(faltndqce-faltndc)*xxlv/nstep
+
+ dumc(i,k) = dumc(i,k)-faltndc*deltat/nstep
+ dumnc(i,k) = dumnc(i,k)-faltndnc*deltat/nstep
+
+ end do
+
+ prect(i) = prect(i)+faloutc(nlev)/g/real(nstep)/1000._r8
+
+ end do
+
+ ! calculate number of split time steps to ensure courant stability criteria
+ ! for sedimentation calculations
+ !-------------------------------------------------------------------
+ nstep = 1 + int(max( &
+ maxval( fr/pdel(i,:)), &
+ maxval(fnr/pdel(i,:))) &
+ * deltat)
+
+ ! loop over sedimentation sub-time step to ensure stability
+ !==============================================================
+ do n = 1,nstep
+
+ faloutr = fr * dumr(i,:)
+ faloutnr = fnr * dumnr(i,:)
+
+ ! top of model
+ k = 1
+
+ ! add fallout terms to microphysical tendencies
+ faltndr = faloutr(k)/pdel(i,k)
+ faltndnr = faloutnr(k)/pdel(i,k)
+ qrtend(i,k) = qrtend(i,k)-faltndr/nstep
+ nrtend(i,k) = nrtend(i,k)-faltndnr/nstep
+
+ ! sedimentation tendency for output
+ qrsedten(i,k)=qrsedten(i,k)-faltndr/nstep
+
+ dumr(i,k) = dumr(i,k)-faltndr*deltat/real(nstep)
+ dumnr(i,k) = dumnr(i,k)-faltndnr*deltat/real(nstep)
+
+ do k = 2,nlev
+
+ faltndr=(faloutr(k)-faloutr(k-1))/pdel(i,k)
+ faltndnr=(faloutnr(k)-faloutnr(k-1))/pdel(i,k)
+
+ ! add fallout terms to eulerian tendencies
+ qrtend(i,k) = qrtend(i,k)-faltndr/nstep
+ nrtend(i,k) = nrtend(i,k)-faltndnr/nstep
+
+ ! sedimentation tendency for output
+ qrsedten(i,k)=qrsedten(i,k)-faltndr/nstep
+
+ dumr(i,k) = dumr(i,k)-faltndr*deltat/real(nstep)
+ dumnr(i,k) = dumnr(i,k)-faltndnr*deltat/real(nstep)
+
+ end do
+
+ prect(i) = prect(i)+faloutr(nlev)/g/real(nstep)/1000._r8
+
+ end do
+
+ ! calculate number of split time steps to ensure courant stability criteria
+ ! for sedimentation calculations
+ !-------------------------------------------------------------------
+ nstep = 1 + int(max( &
+ maxval( fs/pdel(i,:)), &
+ maxval(fns/pdel(i,:))) &
+ * deltat)
+
+ ! loop over sedimentation sub-time step to ensure stability
+ !==============================================================
+ do n = 1,nstep
+
+ falouts = fs * dums(i,:)
+ faloutns = fns * dumns(i,:)
+
+ ! top of model
+ k = 1
+
+ ! add fallout terms to microphysical tendencies
+ faltnds = falouts(k)/pdel(i,k)
+ faltndns = faloutns(k)/pdel(i,k)
+ qstend(i,k) = qstend(i,k)-faltnds/nstep
+ nstend(i,k) = nstend(i,k)-faltndns/nstep
+
+ ! sedimentation tendency for output
+ qssedten(i,k)=qssedten(i,k)-faltnds/nstep
+
+ dums(i,k) = dums(i,k)-faltnds*deltat/real(nstep)
+ dumns(i,k) = dumns(i,k)-faltndns*deltat/real(nstep)
+
+ do k = 2,nlev
+
+ faltnds=(falouts(k)-falouts(k-1))/pdel(i,k)
+ faltndns=(faloutns(k)-faloutns(k-1))/pdel(i,k)
+
+ ! add fallout terms to eulerian tendencies
+ qstend(i,k) = qstend(i,k)-faltnds/nstep
+ nstend(i,k) = nstend(i,k)-faltndns/nstep
+
+ ! sedimentation tendency for output
+ qssedten(i,k)=qssedten(i,k)-faltnds/nstep
+
+ dums(i,k) = dums(i,k)-faltnds*deltat/real(nstep)
+ dumns(i,k) = dumns(i,k)-faltndns*deltat/real(nstep)
+
+ end do !! k loop
+
+ prect(i) = prect(i)+falouts(nlev)/g/real(nstep)/1000._r8
+ preci(i) = preci(i)+falouts(nlev)/g/real(nstep)/1000._r8
+
+ end do !! nstep loop
+
+ ! end sedimentation
+ !ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+
+ ! get new update for variables that includes sedimentation tendency
+ ! note : here dum variables are grid-average, NOT in-cloud
+
+ do k=1,nlev
+
+ dumc(i,k) = max(qc(i,k)+qctend(i,k)*deltat,0._r8)
+ dumi(i,k) = max(qi(i,k)+qitend(i,k)*deltat,0._r8)
+ dumnc(i,k) = max(nc(i,k)+nctend(i,k)*deltat,0._r8)
+ dumni(i,k) = max(ni(i,k)+nitend(i,k)*deltat,0._r8)
+
+ dumr(i,k) = max(qr(i,k)+qrtend(i,k)*deltat,0._r8)
+ dumnr(i,k) = max(nr(i,k)+nrtend(i,k)*deltat,0._r8)
+ dums(i,k) = max(qs(i,k)+qstend(i,k)*deltat,0._r8)
+ dumns(i,k) = max(ns(i,k)+nstend(i,k)*deltat,0._r8)
+
+ ! switch for specification of droplet and crystal number
+ if (nccons) then
+ dumnc(i,k)=ncnst/rho(i,k)*lcldm(i,k)
+ end if
+
+ ! switch for specification of cloud ice number
+ if (nicons) then
+ dumni(i,k)=ninst/rho(i,k)*icldm(i,k)
+ end if
+
+ if (dumc(i,k).lt.qsmall) dumnc(i,k)=0._r8
+ if (dumi(i,k).lt.qsmall) dumni(i,k)=0._r8
+ if (dumr(i,k).lt.qsmall) dumnr(i,k)=0._r8
+ if (dums(i,k).lt.qsmall) dumns(i,k)=0._r8
+
+ ! calculate instantaneous processes (melting, homogeneous freezing)
+ !====================================================================
+
+ ! melting of snow at +2 C
+
+ if (t(i,k)+tlat(i,k)/cpp*deltat > snowmelt) then
+ if (dums(i,k) > 0._r8) then
+
+ ! make sure melting snow doesn't reduce temperature below threshold
+ dum = -xlf/cpp*dums(i,k)
+ if (t(i,k)+tlat(i,k)/cpp*deltat+dum.lt. snowmelt) then
+ dum = (t(i,k)+tlat(i,k)/cpp*deltat-snowmelt)*cpp/xlf
+ dum = dum/dums(i,k)
+ dum = max(0._r8,dum)
+ dum = min(1._r8,dum)
+ else
+ dum = 1._r8
+ end if
+
+ qstend(i,k)=qstend(i,k)-dum*dums(i,k)/deltat
+ nstend(i,k)=nstend(i,k)-dum*dumns(i,k)/deltat
+ qrtend(i,k)=qrtend(i,k)+dum*dums(i,k)/deltat
+ nrtend(i,k)=nrtend(i,k)+dum*dumns(i,k)/deltat
+
+ dum1=-xlf*dum*dums(i,k)/deltat
+ tlat(i,k)=tlat(i,k)+dum1
+ meltsdttot(i,k)=meltsdttot(i,k) + dum1
+ end if
+ end if
+
+ ! freezing of rain at -5 C
+
+ if (t(i,k)+tlat(i,k)/cpp*deltat < rainfrze) then
+
+ if (dumr(i,k) > 0._r8) then
+
+ ! make sure freezing rain doesn't increase temperature above threshold
+ dum = xlf/cpp*dumr(i,k)
+ if (t(i,k)+tlat(i,k)/cpp*deltat+dum.gt.rainfrze) then
+ dum = -(t(i,k)+tlat(i,k)/cpp*deltat-rainfrze)*cpp/xlf
+ dum = dum/dumr(i,k)
+ dum = max(0._r8,dum)
+ dum = min(1._r8,dum)
+ else
+ dum = 1._r8
+ end if
+
+ qrtend(i,k)=qrtend(i,k)-dum*dumr(i,k)/deltat
+ nrtend(i,k)=nrtend(i,k)-dum*dumnr(i,k)/deltat
+
+ ! get mean size of rain = 1/lamr, add frozen rain to either snow or cloud ice
+ ! depending on mean rain size
+
+ call size_dist_param_basic(mg_rain_props, dumr(i,k), dumnr(i,k), &
+ lamr(i,k))
+
+ if (lamr(i,k) < 1._r8/Dcs) then
+ qstend(i,k)=qstend(i,k)+dum*dumr(i,k)/deltat
+ nstend(i,k)=nstend(i,k)+dum*dumnr(i,k)/deltat
+ else
+ qitend(i,k)=qitend(i,k)+dum*dumr(i,k)/deltat
+ nitend(i,k)=nitend(i,k)+dum*dumnr(i,k)/deltat
+ end if
+
+ ! heating tendency
+ dum1 = xlf*dum*dumr(i,k)/deltat
+ frzrdttot(i,k)=frzrdttot(i,k) + dum1
+ tlat(i,k)=tlat(i,k)+dum1
+
+ end if
+ end if
+
+
+ if (do_cldice) then
+ if (t(i,k)+tlat(i,k)/cpp*deltat > tmelt) then
+ if (dumi(i,k) > 0._r8) then
+
+ ! limit so that melting does not push temperature below freezing
+ !-----------------------------------------------------------------
+ dum = -dumi(i,k)*xlf/cpp
+ if (t(i,k)+tlat(i,k)/cpp*deltat+dum.lt.tmelt) then
+ dum = (t(i,k)+tlat(i,k)/cpp*deltat-tmelt)*cpp/xlf
+ dum = dum/dumi(i,k)
+ dum = max(0._r8,dum)
+ dum = min(1._r8,dum)
+ else
+ dum = 1._r8
+ end if
+
+ qctend(i,k)=qctend(i,k)+dum*dumi(i,k)/deltat
+
+ ! for output
+ melttot(i,k)=dum*dumi(i,k)/deltat
+
+ ! assume melting ice produces droplet
+ ! mean volume radius of 8 micron
+
+ nctend(i,k)=nctend(i,k)+3._r8*dum*dumi(i,k)/deltat/ &
+ (4._r8*pi*5.12e-16_r8*rhow)
+
+ qitend(i,k)=((1._r8-dum)*dumi(i,k)-qi(i,k))/deltat
+ nitend(i,k)=((1._r8-dum)*dumni(i,k)-ni(i,k))/deltat
+ tlat(i,k)=tlat(i,k)-xlf*dum*dumi(i,k)/deltat
+ end if
+ end if
+
+ ! homogeneously freeze droplets at -40 C
+ !-----------------------------------------------------------------
+
+ if (t(i,k)+tlat(i,k)/cpp*deltat < 233.15_r8) then
+ if (dumc(i,k) > 0._r8) then
+
+ ! limit so that freezing does not push temperature above threshold
+ dum = dumc(i,k)*xlf/cpp
+ if (t(i,k)+tlat(i,k)/cpp*deltat+dum.gt.233.15_r8) then
+ dum = -(t(i,k)+tlat(i,k)/cpp*deltat-233.15_r8)*cpp/xlf
+ dum = dum/dumc(i,k)
+ dum = max(0._r8,dum)
+ dum = min(1._r8,dum)
+ else
+ dum = 1._r8
+ end if
+
+ qitend(i,k)=qitend(i,k)+dum*dumc(i,k)/deltat
+ ! for output
+ homotot(i,k)=dum*dumc(i,k)/deltat
+
+ ! assume 25 micron mean volume radius of homogeneously frozen droplets
+ ! consistent with size of detrained ice in stratiform.F90
+ nitend(i,k)=nitend(i,k)+dum*3._r8*dumc(i,k)/(4._r8*3.14_r8*1.563e-14_r8* &
+ 500._r8)/deltat
+ qctend(i,k)=((1._r8-dum)*dumc(i,k)-qc(i,k))/deltat
+ nctend(i,k)=((1._r8-dum)*dumnc(i,k)-nc(i,k))/deltat
+ tlat(i,k)=tlat(i,k)+xlf*dum*dumc(i,k)/deltat
+ end if
+ end if
+
+ ! remove any excess over-saturation, which is possible due to non-linearity when adding
+ ! together all microphysical processes
+ !-----------------------------------------------------------------
+ ! follow code similar to old CAM scheme
+
+ qtmp=q(i,k)+qvlat(i,k)*deltat
+ ttmp=t(i,k)+tlat(i,k)/cpp*deltat
+
+ ! use rhw to allow ice supersaturation
+ call qsat_water(ttmp, p(i,k), esn, qvn)
+
+ if (qtmp > qvn .and. qvn > 0 .and. allow_sed_supersat) then
+ ! expression below is approximate since there may be ice deposition
+ dum = (qtmp-qvn)/(1._r8+xxlv_squared*qvn/(cpp*rv*ttmp**2))/deltat
+ ! add to output cme
+ cmeout(i,k) = cmeout(i,k)+dum
+ ! now add to tendencies, partition between liquid and ice based on temperature
+ if (ttmp > 268.15_r8) then
+ dum1=0.0_r8
+ ! now add to tendencies, partition between liquid and ice based on te
+ !-------------------------------------------------------
+ else if (ttmp < 238.15_r8) then
+ dum1=1.0_r8
+ else
+ dum1=(268.15_r8-ttmp)/30._r8
+ end if
+
+ dum = (qtmp-qvn)/(1._r8+(xxls*dum1+xxlv*(1._r8-dum1))**2 &
+ *qvn/(cpp*rv*ttmp**2))/deltat
+ qctend(i,k)=qctend(i,k)+dum*(1._r8-dum1)
+ ! for output
+ qcrestot(i,k)=dum*(1._r8-dum1)
+ qitend(i,k)=qitend(i,k)+dum*dum1
+ qirestot(i,k)=dum*dum1
+ qvlat(i,k)=qvlat(i,k)-dum
+ ! for output
+ qvres(i,k)=-dum
+ tlat(i,k)=tlat(i,k)+dum*(1._r8-dum1)*xxlv+dum*dum1*xxls
+ end if
+ end if
+
+ ! calculate effective radius for pass to radiation code
+ !=========================================================
+ ! if no cloud water, default value is 10 micron for droplets,
+ ! 25 micron for cloud ice
+
+ ! update cloud variables after instantaneous processes to get effective radius
+ ! variables are in-cloud to calculate size dist parameters
+
+ dumc(i,k) = max(qc(i,k)+qctend(i,k)*deltat,0._r8)/lcldm(i,k)
+ dumi(i,k) = max(qi(i,k)+qitend(i,k)*deltat,0._r8)/icldm(i,k)
+ dumnc(i,k) = max(nc(i,k)+nctend(i,k)*deltat,0._r8)/lcldm(i,k)
+ dumni(i,k) = max(ni(i,k)+nitend(i,k)*deltat,0._r8)/icldm(i,k)
+
+ dumr(i,k) = max(qr(i,k)+qrtend(i,k)*deltat,0._r8)/precip_frac(i,k)
+ dumnr(i,k) = max(nr(i,k)+nrtend(i,k)*deltat,0._r8)/precip_frac(i,k)
+ dums(i,k) = max(qs(i,k)+qstend(i,k)*deltat,0._r8)/precip_frac(i,k)
+ dumns(i,k) = max(ns(i,k)+nstend(i,k)*deltat,0._r8)/precip_frac(i,k)
+
+ ! switch for specification of droplet and crystal number
+ if (nccons) then
+ dumnc(i,k)=ncnst/rho(i,k)
+ end if
+
+ ! switch for specification of cloud ice number
+ if (nicons) then
+ dumni(i,k)=ninst/rho(i,k)
+ end if
+
+ ! limit in-cloud mixing ratio to reasonable value of 5 g kg-1
+ dumc(i,k)=min(dumc(i,k),5.e-3_r8)
+ dumi(i,k)=min(dumi(i,k),5.e-3_r8)
+ ! limit in-precip mixing ratios
+ dumr(i,k)=min(dumr(i,k),10.e-3_r8)
+ dums(i,k)=min(dums(i,k),10.e-3_r8)
+
+ ! cloud ice effective radius
+ !-----------------------------------------------------------------
+
+ if (do_cldice) then
+ if (dumi(i,k).ge.qsmall) then
+
+ dum_2D(i,k) = dumni(i,k)
+ call size_dist_param_basic(mg_ice_props, dumi(i,k), dumni(i,k), &
+ lami(i,k))
+
+ if (dumni(i,k) /=dum_2D(i,k)) then
+ ! adjust number conc if needed to keep mean size in reasonable range
+ nitend(i,k)=(dumni(i,k)*icldm(i,k)-ni(i,k))/deltat
+ end if
+
+ effi(i,k) = 1.5_r8/lami(i,k)*1.e6_r8
+
+ else
+ effi(i,k) = 25._r8
+ end if
+
+ ! ice effective diameter for david mitchell's optics
+ deffi(i,k)=effi(i,k)*rhoi/rhows*2._r8
+ else
+ ! NOTE: If CARMA is doing the ice microphysics, then the ice effective
+ ! radius has already been determined from the size distribution.
+ effi(i,k) = re_ice(i,k) * 1.e6_r8 ! m -> um
+ deffi(i,k)=effi(i,k) * 2._r8
+ end if
+
+ ! cloud droplet effective radius
+ !-----------------------------------------------------------------
+ if (dumc(i,k).ge.qsmall) then
+
+
+ ! switch for specification of droplet and crystal number
+ if (nccons) then
+ ! make sure nc is consistence with the constant N by adjusting tendency, need
+ ! to multiply by cloud fraction
+ ! note that nctend may be further adjusted below if mean droplet size is
+ ! out of bounds
+
+ nctend(i,k)=(ncnst/rho(i,k)*lcldm(i,k)-nc(i,k))/deltat
+
+ end if
+
+ dum = dumnc(i,k)
+
+ call size_dist_param_liq(mg_liq_props, dumc(i,k), dumnc(i,k), rho(i,k), &
+ pgam(i,k), lamc(i,k))
+
+ if (dum /= dumnc(i,k)) then
+ ! adjust number conc if needed to keep mean size in reasonable range
+ nctend(i,k)=(dumnc(i,k)*lcldm(i,k)-nc(i,k))/deltat
+ end if
+
+ effc(i,k) = (pgam(i,k)+3._r8)/lamc(i,k)/2._r8*1.e6_r8
+ !assign output fields for shape here
+ lamcrad(i,k)=lamc(i,k)
+ pgamrad(i,k)=pgam(i,k)
+
+
+ ! recalculate effective radius for constant number, in order to separate
+ ! first and second indirect effects
+ !======================================
+ ! assume constant number of 10^8 kg-1
+
+ dumnc(i,k)=1.e8_r8
+
+ ! Pass in "false" adjust flag to prevent number from being changed within
+ ! size distribution subroutine.
+ call size_dist_param_liq(mg_liq_props, dumc(i,k), dumnc(i,k), rho(i,k), &
+ pgam(i,k), lamc(i,k))
+
+ effc_fn(i,k) = (pgam(i,k)+3._r8)/lamc(i,k)/2._r8*1.e6_r8
+
+ else
+ effc(i,k) = 10._r8
+ lamcrad(i,k)=0._r8
+ pgamrad(i,k)=0._r8
+ effc_fn(i,k) = 10._r8
+ end if
+
+ ! recalculate 'final' rain size distribution parameters
+ ! to ensure that rain size is in bounds, adjust rain number if needed
+
+ if (dumr(i,k).ge.qsmall) then
+
+ dum = dumnr(i,k)
+
+ call size_dist_param_basic(mg_rain_props, dumr(i,k), dumnr(i,k), &
+ lamr(i,k))
+
+ if (dum /= dumnr(i,k)) then
+ ! adjust number conc if needed to keep mean size in reasonable range
+ nrtend(i,k)=(dumnr(i,k)*precip_frac(i,k)-nr(i,k))/deltat
+ end if
+
+ end if
+
+ ! recalculate 'final' snow size distribution parameters
+ ! to ensure that snow size is in bounds, adjust snow number if needed
+
+ if (dums(i,k).ge.qsmall) then
+
+ dum = dumns(i,k)
+
+ call size_dist_param_basic(mg_snow_props, dums(i,k), dumns(i,k), &
+ lams(i,k))
+
+ if (dum /= dumns(i,k)) then
+ ! adjust number conc if needed to keep mean size in reasonable range
+ nstend(i,k)=(dumns(i,k)*precip_frac(i,k)-ns(i,k))/deltat
+ end if
+
+ end if
+
+
+ end do ! vertical k loop
+
+ do k=1,nlev
+ ! if updated q (after microphysics) is zero, then ensure updated n is also zero
+ !=================================================================================
+ if (qc(i,k)+qctend(i,k)*deltat.lt.qsmall) nctend(i,k)=-nc(i,k)/deltat
+ if (do_cldice .and. qi(i,k)+qitend(i,k)*deltat.lt.qsmall) nitend(i,k)=-ni(i,k)/deltat
+ if (qr(i,k)+qrtend(i,k)*deltat.lt.qsmall) nrtend(i,k)=-nr(i,k)/deltat
+ if (qs(i,k)+qstend(i,k)*deltat.lt.qsmall) nstend(i,k)=-ns(i,k)/deltat
+
+ end do
+
+ end do sed_col_loop! i loop
+
+ ! DO STUFF FOR OUTPUT:
+ !==================================================
+
+ ! qc and qi are only used for output calculations past here,
+ ! so add qctend and qitend back in one more time
+ qc = qc + qctend*deltat
+ qi = qi + qitend*deltat
+
+ ! averaging for snow and rain number and diameter
+ !--------------------------------------------------
+
+ ! drout2/dsout2:
+ ! diameter of rain and snow
+ ! dsout:
+ ! scaled diameter of snow (passed to radiation in CAM)
+ ! reff_rain/reff_snow:
+ ! calculate effective radius of rain and snow in microns for COSP using Eq. 9 of COSP v1.3 manual
+
+ where (qrout .gt. 1.e-7_r8 &
+ .and. nrout.gt.0._r8)
+ qrout2 = qrout * precip_frac
+ nrout2 = nrout * precip_frac
+ ! The avg_diameter call does the actual calculation; other diameter
+ ! outputs are just drout2 times constants.
+ drout2 = avg_diameter(qrout, nrout, rho, rhow)
+ freqr = precip_frac
+
+ reff_rain=1.5_r8*drout2*1.e6_r8
+ elsewhere
+ qrout2 = 0._r8
+ nrout2 = 0._r8
+ drout2 = 0._r8
+ freqr = 0._r8
+ reff_rain = 0._r8
+ end where
+
+ where (qsout .gt. 1.e-7_r8 &
+ .and. nsout.gt.0._r8)
+ qsout2 = qsout * precip_frac
+ nsout2 = nsout * precip_frac
+ ! The avg_diameter call does the actual calculation; other diameter
+ ! outputs are just dsout2 times constants.
+ dsout2 = avg_diameter(qsout, nsout, rho, rhosn)
+ freqs = precip_frac
+
+ dsout=3._r8*rhosn/rhows*dsout2
+
+ reff_snow=1.5_r8*dsout2*1.e6_r8
+ elsewhere
+ dsout = 0._r8
+ qsout2 = 0._r8
+ nsout2 = 0._r8
+ dsout2 = 0._r8
+ freqs = 0._r8
+ reff_snow=0._r8
+ end where
+
+ ! analytic radar reflectivity
+ !--------------------------------------------------
+ ! formulas from Matthew Shupe, NOAA/CERES
+ ! *****note: radar reflectivity is local (in-precip average)
+ ! units of mm^6/m^3
+
+ do i = 1,mgncol
+ do k=1,nlev
+ if (qc(i,k).ge.qsmall) then
+ dum=(qc(i,k)/lcldm(i,k)*rho(i,k)*1000._r8)**2 &
+ /(0.109_r8*(nc(i,k)+nctend(i,k)*deltat)/lcldm(i,k)*rho(i,k)/1.e6_r8)*lcldm(i,k)/precip_frac(i,k)
+ else
+ dum=0._r8
+ end if
+ if (qi(i,k).ge.qsmall) then
+ dum1=(qi(i,k)*rho(i,k)/icldm(i,k)*1000._r8/0.1_r8)**(1._r8/0.63_r8)*icldm(i,k)/precip_frac(i,k)
+ else
+ dum1=0._r8
+ end if
+
+ if (qsout(i,k).ge.qsmall) then
+ dum1=dum1+(qsout(i,k)*rho(i,k)*1000._r8/0.1_r8)**(1._r8/0.63_r8)
+ end if
+
+ refl(i,k)=dum+dum1
+
+ ! add rain rate, but for 37 GHz formulation instead of 94 GHz
+ ! formula approximated from data of Matrasov (2007)
+ ! rainrt is the rain rate in mm/hr
+ ! reflectivity (dum) is in DBz
+
+ if (rainrt(i,k).ge.0.001_r8) then
+ dum=log10(rainrt(i,k)**6._r8)+16._r8
+
+ ! convert from DBz to mm^6/m^3
+
+ dum = 10._r8**(dum/10._r8)
+ else
+ ! don't include rain rate in R calculation for values less than 0.001 mm/hr
+ dum=0._r8
+ end if
+
+ ! add to refl
+
+ refl(i,k)=refl(i,k)+dum
+
+ !output reflectivity in Z.
+ areflz(i,k)=refl(i,k) * precip_frac(i,k)
+
+ ! convert back to DBz
+
+ if (refl(i,k).gt.minrefl) then
+ refl(i,k)=10._r8*log10(refl(i,k))
+ else
+ refl(i,k)=-9999._r8
+ end if
+
+ !set averaging flag
+ if (refl(i,k).gt.mindbz) then
+ arefl(i,k)=refl(i,k) * precip_frac(i,k)
+ frefl(i,k)=precip_frac(i,k)
+ else
+ arefl(i,k)=0._r8
+ areflz(i,k)=0._r8
+ frefl(i,k)=0._r8
+ end if
+
+ ! bound cloudsat reflectivity
+
+ csrfl(i,k)=min(csmax,refl(i,k))
+
+ !set averaging flag
+ if (csrfl(i,k).gt.csmin) then
+ acsrfl(i,k)=refl(i,k) * precip_frac(i,k)
+ fcsrfl(i,k)=precip_frac(i,k)
+ else
+ acsrfl(i,k)=0._r8
+ fcsrfl(i,k)=0._r8
+ end if
+
+ end do
+ end do
+
+ !redefine fice here....
+ dum_2D = qsout + qrout + qc + qi
+ dumi = qsout + qi
+ where (dumi .gt. qsmall .and. dum_2D .gt. qsmall)
+ nfice=min(dumi/dum_2D,1._r8)
+ elsewhere
+ nfice=0._r8
+ end where
+
+end subroutine micro_mg_tend
+
+!========================================================================
+!OUTPUT CALCULATIONS
+!========================================================================
+
+elemental subroutine calc_rercld(lamr, n0r, lamc, pgam, qric, qcic, ncic, &
+ rercld)
+ real(r8), intent(in) :: lamr ! rain size parameter (slope)
+ real(r8), intent(in) :: n0r ! rain size parameter (intercept)
+ real(r8), intent(in) :: lamc ! size distribution parameter (slope)
+ real(r8), intent(in) :: pgam ! droplet size parameter
+ real(r8), intent(in) :: qric ! in-cloud rain mass mixing ratio
+ real(r8), intent(in) :: qcic ! in-cloud cloud liquid
+ real(r8), intent(in) :: ncic ! in-cloud droplet number concentration
+
+ real(r8), intent(inout) :: rercld ! effective radius calculation for rain + cloud
+
+ ! combined size of precip & cloud drops
+ real(r8) :: Atmp
+
+ ! Rain drops
+ if (lamr > 0._r8) then
+ Atmp = n0r * pi / (2._r8 * lamr**3._r8)
+ else
+ Atmp = 0._r8
+ end if
+
+ ! Add cloud drops
+ if (lamc > 0._r8) then
+ Atmp = Atmp + &
+ ncic * pi * rising_factorial(pgam+1._r8, 2)/(4._r8 * lamc**2._r8)
+ end if
+
+ if (Atmp > 0._r8) then
+ rercld = rercld + 3._r8 *(qric + qcic) / (4._r8 * rhow * Atmp)
+ end if
+
+end subroutine calc_rercld
+
+!========================================================================
+!UTILITIES
+!========================================================================
+
+pure subroutine micro_mg_get_cols(ncol, nlev, top_lev, qcn, qin, &
+ qrn, qsn, mgncol, mgcols)
+
+ ! Determines which columns microphysics should operate over by
+ ! checking for non-zero cloud water/ice.
+
+ integer, intent(in) :: ncol ! Number of columns with meaningful data
+ integer, intent(in) :: nlev ! Number of levels to use
+ integer, intent(in) :: top_lev ! Top level for microphysics
+
+ real(r8), intent(in) :: qcn(:,:) ! cloud water mixing ratio (kg/kg)
+ real(r8), intent(in) :: qin(:,:) ! cloud ice mixing ratio (kg/kg)
+ real(r8), intent(in) :: qrn(:,:) ! rain mixing ratio (kg/kg)
+ real(r8), intent(in) :: qsn(:,:) ! snow mixing ratio (kg/kg)
+
+ integer, intent(out) :: mgncol ! Number of columns MG will use
+ integer, allocatable, intent(out) :: mgcols(:) ! column indices
+
+ integer :: lev_offset ! top_lev - 1 (defined here for consistency)
+ logical :: ltrue(ncol) ! store tests for each column
+
+ integer :: i, ii ! column indices
+
+ if (allocated(mgcols)) deallocate(mgcols)
+
+ lev_offset = top_lev - 1
+
+ ! Using "any" along dimension 2 collapses across levels, but
+ ! not columns, so we know if water is present at any level
+ ! in each column.
+
+ ltrue = any(qcn(:ncol,top_lev:(nlev+lev_offset)) >= qsmall, 2)
+ ltrue = ltrue .or. any(qin(:ncol,top_lev:(nlev+lev_offset)) >= qsmall, 2)
+ ltrue = ltrue .or. any(qrn(:ncol,top_lev:(nlev+lev_offset)) >= qsmall, 2)
+ ltrue = ltrue .or. any(qsn(:ncol,top_lev:(nlev+lev_offset)) >= qsmall, 2)
+
+ ! Scan for true values to get a usable list of indices.
+
+ mgncol = count(ltrue)
+ allocate(mgcols(mgncol))
+ i = 0
+ do ii = 1,ncol
+ if (ltrue(ii)) then
+ i = i + 1
+ mgcols(i) = ii
+ end if
+ end do
+
+end subroutine micro_mg_get_cols
+
+end module micro_mg2_0
diff --git a/models/atm/cam/src/physics/cam/micro_mg_cam.F90 b/models/atm/cam/src/physics/cam/micro_mg_cam.F90
index 9e70712f3355..2cfef4c255da 100644
--- a/models/atm/cam/src/physics/cam/micro_mg_cam.F90
+++ b/models/atm/cam/src/physics/cam/micro_mg_cam.F90
@@ -5,31 +5,92 @@ module micro_mg_cam
! CAM Interfaces for MG microphysics
!
!---------------------------------------------------------------------------------
+!
+! How to add new packed MG inputs to micro_mg_cam_tend:
+!
+! If you have an input with first dimension [psetcols, pver], the procedure
+! for adding inputs is as follows:
+!
+! 1) In addition to any variables you need to declare for the "unpacked"
+! (CAM format) version, you must declare an allocatable or pointer array
+! for the "packed" (MG format) version.
+!
+! 2) After micro_mg_get_cols is called, allocate the "packed" array with
+! size [mgncol, nlev].
+!
+! 3) Add a call similar to the following line (look before the
+! micro_mg_tend calls to see similar lines):
+!
+! packed_array = packer%pack(original_array)
+!
+! The packed array can then be passed into any of the MG schemes.
+!
+! This same procedure will also work for 1D arrays of size psetcols, 3-D
+! arrays with psetcols and pver as the first dimensions, and for arrays of
+! dimension [psetcols, pverp]. You only have to modify the allocation of
+! the packed array before the "pack" call.
+!
+!---------------------------------------------------------------------------------
+!
+! How to add new packed MG outputs to micro_mg_cam_tend:
+!
+! 1) As with inputs, in addition to the unpacked outputs you must declare
+! an allocatable or pointer array for packed data. The unpacked and
+! packed arrays must *also* be targets or pointers (but cannot be both).
+!
+! 2) Again as for inputs, allocate the packed array using mgncol and nlev,
+! which are set in micro_mg_get_cols.
+!
+! 3) Add the field to post-processing as in the following line (again,
+! there are many examples before the micro_mg_tend calls):
+!
+! call post_proc%add_field(p(final_array),p(packed_array))
+!
+! This registers the field for post-MG averaging, and to scatter to the
+! final, unpacked version of the array.
+!
+! By default, any columns/levels that are not operated on by MG will be
+! set to 0 on output; this value can be adjusted using the "fillvalue"
+! optional argument to post_proc%add_field.
+!
+! Also by default, outputs from multiple substeps will be averaged after
+! MG's substepping is complete. Passing the optional argument
+! "accum_method=accum_null" will change this behavior so that the last
+! substep is always output.
+!
+! This procedure works on 1-D and 2-D outputs. Note that the final,
+! unpacked arrays are not set until the call to
+! "post_proc%process_and_unpack", which sets every single field that was
+! added with post_proc%add_field.
+!
+!---------------------------------------------------------------------------------
use shr_kind_mod, only: r8=>shr_kind_r8
use spmd_utils, only: masterproc
-use ppgrid, only: pver, pverp, psubcols
+use ppgrid, only: pcols, pver, pverp, psubcols
use physconst, only: gravit, rair, tmelt, cpair, rh2o, rhoh2o, &
- latvap, latice, mwdry
-use phys_control, only: phys_getopts
+ latvap, latice, mwh2o
+use phys_control, only: phys_getopts, use_hetfrz_classnuc
-use physics_types, only: physics_state, physics_ptend, physics_ptend_init, &
- physics_state_copy, physics_ptend_copy, &
- physics_update, physics_state_dealloc, &
- physics_ptend_sum
+use physics_types, only: physics_state, physics_ptend, &
+ physics_ptend_init, physics_state_copy, &
+ physics_update, physics_state_dealloc, &
+ physics_ptend_sum, physics_ptend_scale
+
use physics_buffer, only: physics_buffer_desc, pbuf_add_field, dyn_time_lvls, &
- pbuf_old_tim_idx, pbuf_get_index, dtype_r8, dtype_i4, &
- pbuf_get_field, pbuf_set_field, col_type_subcol, pbuf_register_subcol
+ pbuf_old_tim_idx, pbuf_get_index, dtype_r8, dtype_i4, &
+ pbuf_get_field, pbuf_set_field, col_type_subcol, &
+ pbuf_register_subcol
use constituents, only: cnst_add, cnst_get_ind, &
- cnst_name, cnst_longname, sflxnam, apcnst, bpcnst, pcnst
+ cnst_name, cnst_longname, sflxnam, apcnst, bpcnst, pcnst
-use cldwat2m_macro, only: rhmini
+use cldfrc2m, only: rhmini=>rhmini_const
use cam_history, only: addfld, add_default, phys_decomp, outfld
use cam_logfile, only: iulog
-use cam_abortutils, only: endrun
+use cam_abortutils, only: endrun
use error_messages, only: handle_errmsg
use ref_pres, only: top_lev=>trop_cloud_top_lev
@@ -40,55 +101,76 @@ module micro_mg_cam
save
public :: &
- micro_mg_cam_readnl, &
- micro_mg_cam_register, &
- micro_mg_cam_init_cnst, &
- micro_mg_cam_implements_cnst, &
- micro_mg_cam_init, &
- micro_mg_cam_tend
+ micro_mg_cam_readnl, &
+ micro_mg_cam_register, &
+ micro_mg_cam_init_cnst, &
+ micro_mg_cam_implements_cnst, &
+ micro_mg_cam_init, &
+ micro_mg_cam_tend, &
+ micro_mg_version
integer :: micro_mg_version = 1 ! Version number for MG.
integer :: micro_mg_sub_version = 0 ! Second part of version number.
+real(r8) :: micro_mg_dcs = -1._r8
+
logical :: microp_uniform
+character(len=16) :: micro_mg_precip_frac_method = 'max_overlap' ! type of precipitation fraction method
+
+real(r8) :: micro_mg_berg_eff_factor = 1.0_r8 ! berg efficiency factor
+
logical, public :: do_cldliq ! Prognose cldliq flag
logical, public :: do_cldice ! Prognose cldice flag
-real(r8) :: dcs !autoconversion size threshold for cloud ice to snow (m)
-integer, parameter :: ncnst = 4 ! Number of constituents
+integer :: num_steps ! Number of MG substeps
+
+integer :: ncnst = 4 ! Number of constituents
+
character(len=8), parameter :: & ! Constituent names
- cnst_names(ncnst) = (/'CLDLIQ', 'CLDICE','NUMLIQ','NUMICE'/)
+ cnst_names(8) = (/'CLDLIQ', 'CLDICE','NUMLIQ','NUMICE', &
+ 'RAINQM', 'SNOWQM','NUMRAI','NUMSNO'/)
integer :: &
- ixcldliq, &! cloud liquid amount index
- ixcldice, &! cloud ice amount index
- ixnumliq, &! cloud liquid number index
- ixnumice ! cloud ice water index
+ ixcldliq = -1, &! cloud liquid amount index
+ ixcldice = -1, &! cloud ice amount index
+ ixnumliq = -1, &! cloud liquid number index
+ ixnumice = -1, &! cloud ice water index
+ ixrain = -1, &! rain index
+ ixsnow = -1, &! snow index
+ ixnumrain = -1, &! rain number index
+ ixnumsnow = -1 ! snow number index
! Physics buffer indices for fields registered by this module
integer :: &
- cldo_idx, &
- qme_idx, &
- prain_idx, &
- nevapr_idx, &
- wsedl_idx, &
- rei_idx, &
- rel_idx, &
- dei_idx, &
- mu_idx, &
- lambdac_idx, &
- iciwpst_idx, &
- iclwpst_idx, &
- des_idx, &
- icswp_idx, &
- cldfsnow_idx, &
- rate1_cw2pr_st_idx = -1, &
- ls_flxprc_idx, &
- ls_flxsnw_idx, &
- relvar_idx, &
- cmeliq_idx, &
- accre_enhan_idx
+ cldo_idx, &
+ qme_idx, &
+ prain_idx, &
+ nevapr_idx, &
+ wsedl_idx, &
+ rei_idx, &
+ rel_idx, &
+ dei_idx, &
+ mu_idx, &
+ prer_evap_idx, &
+ lambdac_idx, &
+ iciwpst_idx, &
+ iclwpst_idx, &
+ des_idx, &
+ icswp_idx, &
+ cldfsnow_idx, &
+ rate1_cw2pr_st_idx = -1, &
+ ls_flxprc_idx, &
+ ls_flxsnw_idx, &
+ relvar_idx, &
+ cmeliq_idx, &
+ accre_enhan_idx
+
+! Fields for UNICON
+integer :: &
+ am_evp_st_idx, &! Evaporation area of stratiform precipitation
+ evprain_st_idx, &! Evaporation rate of stratiform rain [kg/kg/s]. >= 0.
+ evpsnow_st_idx ! Evaporation rate of stratiform snow [kg/kg/s]. >= 0.
! Fields needed as inputs to COSP
integer :: &
@@ -105,36 +187,53 @@ module micro_mg_cam
! Used to replace aspects of MG microphysics
! (e.g. by CARMA)
-integer :: tnd_qsnow_idx, tnd_nsnow_idx, re_ice_idx
+integer :: &
+ tnd_qsnow_idx = -1, &
+ tnd_nsnow_idx = -1, &
+ re_ice_idx = -1
! Index fields for precipitation efficiency.
-integer :: acpr_idx, acgcme_idx, acnum_idx
+integer :: &
+ acpr_idx = -1, &
+ acgcme_idx = -1, &
+ acnum_idx = -1
! Physics buffer indices for fields registered by other modules
integer :: &
- ast_idx = -1, &
- aist_idx = -1, &
- alst_idx = -1, &
- cld_idx = -1, &
- concld_idx = -1
+ ast_idx = -1, &
+ cld_idx = -1, &
+ concld_idx = -1
! Pbuf fields needed for subcol_SILHS
integer :: &
- qrain_idx=-1, qsnow_idx=-1, &
- nrain_idx=-1, nsnow_idx=-1
+ qrain_idx=-1, qsnow_idx=-1, &
+ nrain_idx=-1, nsnow_idx=-1
integer :: &
- naai_idx = -1, &
- naai_hom_idx = -1, &
- npccn_idx = -1, &
- rndst_idx = -1, &
- nacon_idx = -1, &
- prec_str_idx = -1, &
- snow_str_idx = -1, &
- prec_pcw_idx = -1, &
- snow_pcw_idx = -1, &
- prec_sed_idx = -1, &
- snow_sed_idx = -1
+ naai_idx = -1, &
+ naai_hom_idx = -1, &
+ npccn_idx = -1, &
+ rndst_idx = -1, &
+ nacon_idx = -1, &
+ prec_str_idx = -1, &
+ snow_str_idx = -1, &
+ prec_pcw_idx = -1, &
+ snow_pcw_idx = -1, &
+ prec_sed_idx = -1, &
+ snow_sed_idx = -1
+
+! pbuf fields for heterogeneous freezing
+integer :: &
+ frzimm_idx = -1, &
+ frzcnt_idx = -1, &
+ frzdep_idx = -1
+
+ logical :: allow_sed_supersat ! allow supersaturated conditions after sedimentation loop
+
+interface p
+ module procedure p1
+ module procedure p2
+end interface p
!===============================================================================
@@ -150,17 +249,18 @@ subroutine micro_mg_cam_readnl(nlfile)
character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
! Namelist variables
- logical :: micro_mg_do_cldice = .true. ! do_cldice = .true., MG microphysics is prognosing cldice
- logical :: micro_mg_do_cldliq = .true. ! do_cldliq = .true., MG microphysics is prognosing cldliq
- real(r8) :: micro_mg_dcs !autoconversion size threshold for cloud ice to snow (m)
+ logical :: micro_mg_do_cldice = .true. ! do_cldice = .true., MG microphysics is prognosing cldice
+ logical :: micro_mg_do_cldliq = .true. ! do_cldliq = .true., MG microphysics is prognosing cldliq
+ integer :: micro_mg_num_steps = 1 ! Number of substepping iterations done by MG (1.5 only for now).
+
! Local variables
integer :: unitn, ierr
character(len=*), parameter :: subname = 'micro_mg_cam_readnl'
namelist /micro_mg_nl/ micro_mg_version, micro_mg_sub_version, &
- micro_mg_do_cldice, micro_mg_do_cldliq, microp_uniform, &
- micro_mg_dcs
+ micro_mg_do_cldice, micro_mg_do_cldliq, micro_mg_num_steps, &
+ microp_uniform, micro_mg_dcs, micro_mg_precip_frac_method, micro_mg_berg_eff_factor
!-----------------------------------------------------------------------------
@@ -178,9 +278,9 @@ subroutine micro_mg_cam_readnl(nlfile)
call freeunit(unitn)
! set local variables
- do_cldice = micro_mg_do_cldice
- do_cldliq = micro_mg_do_cldliq
- dcs = micro_mg_dcs
+ do_cldice = micro_mg_do_cldice
+ do_cldliq = micro_mg_do_cldliq
+ num_steps = micro_mg_num_steps
! Verify that version numbers are valid.
select case (micro_mg_version)
@@ -193,20 +293,33 @@ subroutine micro_mg_cam_readnl(nlfile)
case default
call bad_version_endrun()
end select
+ case (2)
+ select case (micro_mg_sub_version)
+ case(0)
+ ! MG version 2.0
+ case default
+ call bad_version_endrun()
+ end select
case default
call bad_version_endrun()
end select
+ if (micro_mg_dcs < 0._r8) call endrun( "micro_mg_cam_readnl: &
+ µ_mg_dcs has not been set to a valid value.")
end if
#ifdef SPMD
! Broadcast namelist variables
- call mpibcast(micro_mg_version, 1, mpiint, 0, mpicom)
- call mpibcast(micro_mg_sub_version, 1, mpiint, 0, mpicom)
- call mpibcast(do_cldice, 1, mpilog, 0, mpicom)
- call mpibcast(do_cldliq, 1, mpilog, 0, mpicom)
- call mpibcast(microp_uniform, 1, mpilog, 0, mpicom)
- call mpibcast(dcs, 1, mpir8, 0, mpicom)
+ call mpibcast(micro_mg_version, 1, mpiint, 0, mpicom)
+ call mpibcast(micro_mg_sub_version, 1, mpiint, 0, mpicom)
+ call mpibcast(do_cldice, 1, mpilog, 0, mpicom)
+ call mpibcast(do_cldliq, 1, mpilog, 0, mpicom)
+ call mpibcast(num_steps, 1, mpiint, 0, mpicom)
+ call mpibcast(microp_uniform, 1, mpilog, 0, mpicom)
+ call mpibcast(micro_mg_dcs, 1, mpir8, 0, mpicom)
+ call mpibcast(micro_mg_berg_eff_factor, 1, mpir8, 0, mpicom)
+ call mpibcast(micro_mg_precip_frac_method, 16, mpichar,0, mpicom)
+
#endif
contains
@@ -225,174 +338,198 @@ end subroutine micro_mg_cam_readnl
subroutine micro_mg_cam_register
- ! Register microphysics constituents and fields in the physics buffer.
- !-----------------------------------------------------------------------
-
- use ppgrid, only: pcols
-
- logical :: prog_modal_aero
- logical :: use_subcol_microp ! If true, then are using subcolumns in microphysics
- logical :: save_subcol_microp ! If true, then need to store sub-columnized fields in pbuf
-
- call phys_getopts(use_subcol_microp_out = use_subcol_microp, &
- prog_modal_aero_out = prog_modal_aero )
-
- ! Register microphysics constituents and save indices.
-
- call cnst_add(cnst_names(1), mwdry, cpair, 0._r8, ixcldliq, &
- longname='Grid box averaged cloud liquid amount', is_convtran1=.true.)
- call cnst_add(cnst_names(2), mwdry, cpair, 0._r8, ixcldice, &
- longname='Grid box averaged cloud ice amount', is_convtran1=.true.)
- ! The next statements should have "is_convtran1=.true.", but this would change
- ! answers.
- call cnst_add(cnst_names(3), mwdry, cpair, 0._r8, ixnumliq, &
- longname='Grid box averaged cloud liquid number', is_convtran1=.false.)
- call cnst_add(cnst_names(4), mwdry, cpair, 0._r8, ixnumice, &
- longname='Grid box averaged cloud ice number', is_convtran1=.false.)
-
- ! Request physics buffer space for fields that persist across timesteps.
-
- call pbuf_add_field('CLDO','global',dtype_r8,(/pcols,pver,dyn_time_lvls/), cldo_idx)
-
- ! Physics buffer variables for convective cloud properties.
-
- call pbuf_add_field('QME', 'physpkg',dtype_r8,(/pcols,pver/), qme_idx)
- call pbuf_add_field('PRAIN', 'physpkg',dtype_r8,(/pcols,pver/), prain_idx)
- call pbuf_add_field('NEVAPR', 'physpkg',dtype_r8,(/pcols,pver/), nevapr_idx)
-
- call pbuf_add_field('WSEDL', 'physpkg',dtype_r8,(/pcols,pver/), wsedl_idx)
-
- call pbuf_add_field('REI', 'physpkg',dtype_r8,(/pcols,pver/), rei_idx)
- call pbuf_add_field('REL', 'physpkg',dtype_r8,(/pcols,pver/), rel_idx)
-
- ! Mitchell ice effective diameter for radiation
- call pbuf_add_field('DEI', 'physpkg',dtype_r8,(/pcols,pver/), dei_idx)
- ! Size distribution shape parameter for radiation
- call pbuf_add_field('MU', 'physpkg',dtype_r8,(/pcols,pver/), mu_idx)
- ! Size distribution shape parameter for radiation
- call pbuf_add_field('LAMBDAC', 'physpkg',dtype_r8,(/pcols,pver/), lambdac_idx)
-
- ! Stratiform only in cloud ice water path for radiation
- call pbuf_add_field('ICIWPST', 'physpkg',dtype_r8,(/pcols,pver/), iciwpst_idx)
- ! Stratiform in cloud liquid water path for radiation
- call pbuf_add_field('ICLWPST', 'physpkg',dtype_r8,(/pcols,pver/), iclwpst_idx)
-
- ! Snow effective diameter for radiation
- call pbuf_add_field('DES', 'physpkg',dtype_r8,(/pcols,pver/), des_idx)
- ! In cloud snow water path for radiation
- call pbuf_add_field('ICSWP', 'physpkg',dtype_r8,(/pcols,pver/), icswp_idx)
- ! Cloud fraction for liquid drops + snow
- call pbuf_add_field('CLDFSNOW ', 'physpkg',dtype_r8,(/pcols,pver,dyn_time_lvls/), cldfsnow_idx)
-
- if (prog_modal_aero) then
- call pbuf_add_field('RATE1_CW2PR_ST','physpkg',dtype_r8,(/pcols,pver/), rate1_cw2pr_st_idx)
- endif
-
- call pbuf_add_field('LS_FLXPRC', 'physpkg',dtype_r8,(/pcols,pverp/), ls_flxprc_idx)
- call pbuf_add_field('LS_FLXSNW', 'physpkg',dtype_r8,(/pcols,pverp/), ls_flxsnw_idx)
-
-
- ! Fields needed as inputs to COSP
- call pbuf_add_field('LS_MRPRC', 'physpkg',dtype_r8,(/pcols,pver/), ls_mrprc_idx)
- call pbuf_add_field('LS_MRSNW', 'physpkg',dtype_r8,(/pcols,pver/), ls_mrsnw_idx)
- call pbuf_add_field('LS_REFFRAIN','physpkg',dtype_r8,(/pcols,pver/), ls_reffrain_idx)
- call pbuf_add_field('LS_REFFSNOW','physpkg',dtype_r8,(/pcols,pver/), ls_reffsnow_idx)
- call pbuf_add_field('CV_REFFLIQ', 'physpkg',dtype_r8,(/pcols,pver/), cv_reffliq_idx)
- call pbuf_add_field('CV_REFFICE', 'physpkg',dtype_r8,(/pcols,pver/), cv_reffice_idx)
-
- ! CC_* Fields needed by Park macrophysics
- call pbuf_add_field('CC_T', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_t_idx)
- call pbuf_add_field('CC_qv', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_qv_idx)
- call pbuf_add_field('CC_ql', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_ql_idx)
- call pbuf_add_field('CC_qi', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_qi_idx)
- call pbuf_add_field('CC_nl', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_nl_idx)
- call pbuf_add_field('CC_ni', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_ni_idx)
- call pbuf_add_field('CC_qlst', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_qlst_idx)
-
- ! Register subcolumn pbuf fields
- if (use_subcol_microp) then
- ! Global pbuf fields
- call pbuf_register_subcol('CLDO', 'micro_mg_cam_register', cldo_idx)
-
- ! CC_* Fields needed by Park macrophysics
- call pbuf_register_subcol('CC_T', 'micro_mg_cam_register', cc_t_idx)
- call pbuf_register_subcol('CC_qv', 'micro_mg_cam_register', cc_qv_idx)
- call pbuf_register_subcol('CC_ql', 'micro_mg_cam_register', cc_ql_idx)
- call pbuf_register_subcol('CC_qi', 'micro_mg_cam_register', cc_qi_idx)
- call pbuf_register_subcol('CC_nl', 'micro_mg_cam_register', cc_nl_idx)
- call pbuf_register_subcol('CC_ni', 'micro_mg_cam_register', cc_ni_idx)
- call pbuf_register_subcol('CC_qlst', 'micro_mg_cam_register', cc_qlst_idx)
-
- ! Physpkg pbuf fields
- ! Physics buffer variables for convective cloud properties.
-
- call pbuf_register_subcol('QME', 'micro_mg_cam_register', qme_idx)
- call pbuf_register_subcol('PRAIN', 'micro_mg_cam_register', prain_idx)
- call pbuf_register_subcol('NEVAPR', 'micro_mg_cam_register', nevapr_idx)
-
- call pbuf_register_subcol('WSEDL', 'micro_mg_cam_register', wsedl_idx)
-
- call pbuf_register_subcol('REI', 'micro_mg_cam_register', rei_idx)
- call pbuf_register_subcol('REL', 'micro_mg_cam_register', rel_idx)
-
- ! Mitchell ice effective diameter for radiation
- call pbuf_register_subcol('DEI', 'micro_mg_cam_register', dei_idx)
- ! Size distribution shape parameter for radiation
- call pbuf_register_subcol('MU', 'micro_mg_cam_register', mu_idx)
- ! Size distribution shape parameter for radiation
- call pbuf_register_subcol('LAMBDAC', 'micro_mg_cam_register', lambdac_idx)
-
- ! Stratiform only in cloud ice water path for radiation
- call pbuf_register_subcol('ICIWPST', 'micro_mg_cam_register', iciwpst_idx)
- ! Stratiform in cloud liquid water path for radiation
- call pbuf_register_subcol('ICLWPST', 'micro_mg_cam_register', iclwpst_idx)
-
- ! Snow effective diameter for radiation
- call pbuf_register_subcol('DES', 'micro_mg_cam_register', des_idx)
- ! In cloud snow water path for radiation
- call pbuf_register_subcol('ICSWP', 'micro_mg_cam_register', icswp_idx)
- ! Cloud fraction for liquid drops + snow
- call pbuf_register_subcol('CLDFSNOW ', 'micro_mg_cam_register', cldfsnow_idx)
-
- if (prog_modal_aero) then
- call pbuf_register_subcol('RATE1_CW2PR_ST', 'micro_mg_cam_register', rate1_cw2pr_st_idx)
- end if
-
- call pbuf_register_subcol('LS_FLXPRC', 'micro_mg_cam_register', ls_flxprc_idx)
- call pbuf_register_subcol('LS_FLXSNW', 'micro_mg_cam_register', ls_flxsnw_idx)
-
- ! Fields needed as inputs to COSP
- call pbuf_register_subcol('LS_MRPRC', 'micro_mg_cam_register', ls_mrprc_idx)
- call pbuf_register_subcol('LS_MRSNW', 'micro_mg_cam_register', ls_mrsnw_idx)
- call pbuf_register_subcol('LS_REFFRAIN', 'micro_mg_cam_register', ls_reffrain_idx)
- call pbuf_register_subcol('LS_REFFSNOW', 'micro_mg_cam_register', ls_reffsnow_idx)
- call pbuf_register_subcol('CV_REFFLIQ', 'micro_mg_cam_register', cv_reffliq_idx)
- call pbuf_register_subcol('CV_REFFICE', 'micro_mg_cam_register', cv_reffice_idx)
- end if
-
- ! Additional pbuf for CARMA interface
- call pbuf_add_field('TND_QSNOW', 'physpkg',dtype_r8,(/pcols,pver/), tnd_qsnow_idx)
- call pbuf_add_field('TND_NSNOW', 'physpkg',dtype_r8,(/pcols,pver/), tnd_nsnow_idx)
- call pbuf_add_field('RE_ICE', 'physpkg',dtype_r8,(/pcols,pver/), re_ice_idx)
-
- ! Precipitation efficiency fields across timesteps.
- call pbuf_add_field('ACPRECL', 'global',dtype_r8,(/pcols/), acpr_idx) ! accumulated precip
- call pbuf_add_field('ACGCME', 'global',dtype_r8,(/pcols/), acgcme_idx) ! accumulated condensation
- call pbuf_add_field('ACNUM', 'global',dtype_i4,(/pcols/), acnum_idx) ! counter for accumulated # timesteps
-
- ! SGS variability -- These could be reset by CLUBB so they need to be grid only
- call pbuf_add_field('RELVAR', 'global',dtype_r8,(/pcols,pver/), relvar_idx)
- call pbuf_add_field('ACCRE_ENHAN','global',dtype_r8,(/pcols,pver/), accre_enhan_idx)
-
- ! Diagnostic fields needed for subcol_SILHS, need to be grid-only
- if (subcol_get_scheme() == 'SILHS') then
- call pbuf_add_field('QRAIN', 'global',dtype_r8,(/pcols,pver/), qrain_idx)
- call pbuf_add_field('QSNOW', 'global',dtype_r8,(/pcols,pver/), qsnow_idx)
- call pbuf_add_field('NRAIN', 'global',dtype_r8,(/pcols,pver/), nrain_idx)
- call pbuf_add_field('NSNOW', 'global',dtype_r8,(/pcols,pver/), nsnow_idx)
- end if
-
-
+ ! Register microphysics constituents and fields in the physics buffer.
+ !-----------------------------------------------------------------------
+
+ logical :: prog_modal_aero
+ logical :: use_subcol_microp ! If true, then are using subcolumns in microphysics
+
+ call phys_getopts(use_subcol_microp_out = use_subcol_microp, &
+ prog_modal_aero_out = prog_modal_aero)
+
+ ! Register microphysics constituents and save indices.
+
+ call cnst_add(cnst_names(1), mwh2o, cpair, 0._r8, ixcldliq, &
+ longname='Grid box averaged cloud liquid amount', is_convtran1=.true.)
+ call cnst_add(cnst_names(2), mwh2o, cpair, 0._r8, ixcldice, &
+ longname='Grid box averaged cloud ice amount', is_convtran1=.true.)
+
+ ! The next statements should have "is_convtran1=.true.", but this would change
+ ! answers for MG 1.0. Thus make an exception for that version only.
+ if (micro_mg_version == 1 .and. micro_mg_sub_version == 0) then
+ call cnst_add(cnst_names(3), mwh2o, cpair, 0._r8, ixnumliq, &
+ longname='Grid box averaged cloud liquid number', is_convtran1=.false.)
+ call cnst_add(cnst_names(4), mwh2o, cpair, 0._r8, ixnumice, &
+ longname='Grid box averaged cloud ice number', is_convtran1=.false.)
+ else
+ call cnst_add(cnst_names(3), mwh2o, cpair, 0._r8, ixnumliq, &
+ longname='Grid box averaged cloud liquid number', is_convtran1=.true.)
+ call cnst_add(cnst_names(4), mwh2o, cpair, 0._r8, ixnumice, &
+ longname='Grid box averaged cloud ice number', is_convtran1=.true.)
+ end if
+
+ ! Note is_convtran1 is set to .true.
+ if (micro_mg_version > 1) then
+ call cnst_add(cnst_names(5), mwh2o, cpair, 0._r8, ixrain, &
+ longname='Grid box averaged rain amount', is_convtran1=.true.)
+ call cnst_add(cnst_names(6), mwh2o, cpair, 0._r8, ixsnow, &
+ longname='Grid box averaged snow amount', is_convtran1=.true.)
+ call cnst_add(cnst_names(7), mwh2o, cpair, 0._r8, ixnumrain, &
+ longname='Grid box averaged rain number', is_convtran1=.true.)
+ call cnst_add(cnst_names(8), mwh2o, cpair, 0._r8, ixnumsnow, &
+ longname='Grid box averaged snow number', is_convtran1=.true.)
+ end if
+
+ ! Request physics buffer space for fields that persist across timesteps.
+
+ call pbuf_add_field('CLDO','global',dtype_r8,(/pcols,pver,dyn_time_lvls/), cldo_idx)
+
+ ! Physics buffer variables for convective cloud properties.
+
+ call pbuf_add_field('QME', 'physpkg',dtype_r8,(/pcols,pver/), qme_idx)
+ call pbuf_add_field('PRAIN', 'physpkg',dtype_r8,(/pcols,pver/), prain_idx)
+ call pbuf_add_field('NEVAPR', 'physpkg',dtype_r8,(/pcols,pver/), nevapr_idx)
+ call pbuf_add_field('PRER_EVAP', 'global', dtype_r8,(/pcols,pver/), prer_evap_idx)
+
+ call pbuf_add_field('WSEDL', 'physpkg',dtype_r8,(/pcols,pver/), wsedl_idx)
+
+ call pbuf_add_field('REI', 'physpkg',dtype_r8,(/pcols,pver/), rei_idx)
+ call pbuf_add_field('REL', 'physpkg',dtype_r8,(/pcols,pver/), rel_idx)
+
+ ! Mitchell ice effective diameter for radiation
+ call pbuf_add_field('DEI', 'physpkg',dtype_r8,(/pcols,pver/), dei_idx)
+ ! Size distribution shape parameter for radiation
+ call pbuf_add_field('MU', 'physpkg',dtype_r8,(/pcols,pver/), mu_idx)
+ ! Size distribution shape parameter for radiation
+ call pbuf_add_field('LAMBDAC', 'physpkg',dtype_r8,(/pcols,pver/), lambdac_idx)
+
+ ! Stratiform only in cloud ice water path for radiation
+ call pbuf_add_field('ICIWPST', 'physpkg',dtype_r8,(/pcols,pver/), iciwpst_idx)
+ ! Stratiform in cloud liquid water path for radiation
+ call pbuf_add_field('ICLWPST', 'physpkg',dtype_r8,(/pcols,pver/), iclwpst_idx)
+
+ ! Snow effective diameter for radiation
+ call pbuf_add_field('DES', 'physpkg',dtype_r8,(/pcols,pver/), des_idx)
+ ! In cloud snow water path for radiation
+ call pbuf_add_field('ICSWP', 'physpkg',dtype_r8,(/pcols,pver/), icswp_idx)
+ ! Cloud fraction for liquid drops + snow
+ call pbuf_add_field('CLDFSNOW ', 'physpkg',dtype_r8,(/pcols,pver,dyn_time_lvls/), cldfsnow_idx)
+
+ if (prog_modal_aero) then
+ call pbuf_add_field('RATE1_CW2PR_ST','physpkg',dtype_r8,(/pcols,pver/), rate1_cw2pr_st_idx)
+ endif
+
+ call pbuf_add_field('LS_FLXPRC', 'physpkg',dtype_r8,(/pcols,pverp/), ls_flxprc_idx)
+ call pbuf_add_field('LS_FLXSNW', 'physpkg',dtype_r8,(/pcols,pverp/), ls_flxsnw_idx)
+
+
+ ! Fields needed as inputs to COSP
+ call pbuf_add_field('LS_MRPRC', 'physpkg',dtype_r8,(/pcols,pver/), ls_mrprc_idx)
+ call pbuf_add_field('LS_MRSNW', 'physpkg',dtype_r8,(/pcols,pver/), ls_mrsnw_idx)
+ call pbuf_add_field('LS_REFFRAIN','physpkg',dtype_r8,(/pcols,pver/), ls_reffrain_idx)
+ call pbuf_add_field('LS_REFFSNOW','physpkg',dtype_r8,(/pcols,pver/), ls_reffsnow_idx)
+ call pbuf_add_field('CV_REFFLIQ', 'physpkg',dtype_r8,(/pcols,pver/), cv_reffliq_idx)
+ call pbuf_add_field('CV_REFFICE', 'physpkg',dtype_r8,(/pcols,pver/), cv_reffice_idx)
+
+ ! CC_* Fields needed by Park macrophysics
+ call pbuf_add_field('CC_T', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_t_idx)
+ call pbuf_add_field('CC_qv', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_qv_idx)
+ call pbuf_add_field('CC_ql', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_ql_idx)
+ call pbuf_add_field('CC_qi', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_qi_idx)
+ call pbuf_add_field('CC_nl', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_nl_idx)
+ call pbuf_add_field('CC_ni', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_ni_idx)
+ call pbuf_add_field('CC_qlst', 'global', dtype_r8, (/pcols,pver,dyn_time_lvls/), cc_qlst_idx)
+
+ ! Fields for UNICON
+ call pbuf_add_field('am_evp_st', 'global', dtype_r8, (/pcols,pver/), am_evp_st_idx)
+ call pbuf_add_field('evprain_st', 'global', dtype_r8, (/pcols,pver/), evprain_st_idx)
+ call pbuf_add_field('evpsnow_st', 'global', dtype_r8, (/pcols,pver/), evpsnow_st_idx)
+
+ ! Register subcolumn pbuf fields
+ if (use_subcol_microp) then
+ ! Global pbuf fields
+ call pbuf_register_subcol('CLDO', 'micro_mg_cam_register', cldo_idx)
+
+ ! CC_* Fields needed by Park macrophysics
+ call pbuf_register_subcol('CC_T', 'micro_mg_cam_register', cc_t_idx)
+ call pbuf_register_subcol('CC_qv', 'micro_mg_cam_register', cc_qv_idx)
+ call pbuf_register_subcol('CC_ql', 'micro_mg_cam_register', cc_ql_idx)
+ call pbuf_register_subcol('CC_qi', 'micro_mg_cam_register', cc_qi_idx)
+ call pbuf_register_subcol('CC_nl', 'micro_mg_cam_register', cc_nl_idx)
+ call pbuf_register_subcol('CC_ni', 'micro_mg_cam_register', cc_ni_idx)
+ call pbuf_register_subcol('CC_qlst', 'micro_mg_cam_register', cc_qlst_idx)
+
+ ! Physpkg pbuf fields
+ ! Physics buffer variables for convective cloud properties.
+
+ call pbuf_register_subcol('QME', 'micro_mg_cam_register', qme_idx)
+ call pbuf_register_subcol('PRAIN', 'micro_mg_cam_register', prain_idx)
+ call pbuf_register_subcol('NEVAPR', 'micro_mg_cam_register', nevapr_idx)
+ call pbuf_register_subcol('PRER_EVAP', 'micro_mg_cam_register', prer_evap_idx)
+
+ call pbuf_register_subcol('WSEDL', 'micro_mg_cam_register', wsedl_idx)
+
+ call pbuf_register_subcol('REI', 'micro_mg_cam_register', rei_idx)
+ call pbuf_register_subcol('REL', 'micro_mg_cam_register', rel_idx)
+
+ ! Mitchell ice effective diameter for radiation
+ call pbuf_register_subcol('DEI', 'micro_mg_cam_register', dei_idx)
+ ! Size distribution shape parameter for radiation
+ call pbuf_register_subcol('MU', 'micro_mg_cam_register', mu_idx)
+ ! Size distribution shape parameter for radiation
+ call pbuf_register_subcol('LAMBDAC', 'micro_mg_cam_register', lambdac_idx)
+
+ ! Stratiform only in cloud ice water path for radiation
+ call pbuf_register_subcol('ICIWPST', 'micro_mg_cam_register', iciwpst_idx)
+ ! Stratiform in cloud liquid water path for radiation
+ call pbuf_register_subcol('ICLWPST', 'micro_mg_cam_register', iclwpst_idx)
+
+ ! Snow effective diameter for radiation
+ call pbuf_register_subcol('DES', 'micro_mg_cam_register', des_idx)
+ ! In cloud snow water path for radiation
+ call pbuf_register_subcol('ICSWP', 'micro_mg_cam_register', icswp_idx)
+ ! Cloud fraction for liquid drops + snow
+ call pbuf_register_subcol('CLDFSNOW ', 'micro_mg_cam_register', cldfsnow_idx)
+
+ if (prog_modal_aero) then
+ call pbuf_register_subcol('RATE1_CW2PR_ST', 'micro_mg_cam_register', rate1_cw2pr_st_idx)
+ end if
+
+ call pbuf_register_subcol('LS_FLXPRC', 'micro_mg_cam_register', ls_flxprc_idx)
+ call pbuf_register_subcol('LS_FLXSNW', 'micro_mg_cam_register', ls_flxsnw_idx)
+
+ ! Fields needed as inputs to COSP
+ call pbuf_register_subcol('LS_MRPRC', 'micro_mg_cam_register', ls_mrprc_idx)
+ call pbuf_register_subcol('LS_MRSNW', 'micro_mg_cam_register', ls_mrsnw_idx)
+ call pbuf_register_subcol('LS_REFFRAIN', 'micro_mg_cam_register', ls_reffrain_idx)
+ call pbuf_register_subcol('LS_REFFSNOW', 'micro_mg_cam_register', ls_reffsnow_idx)
+ call pbuf_register_subcol('CV_REFFLIQ', 'micro_mg_cam_register', cv_reffliq_idx)
+ call pbuf_register_subcol('CV_REFFICE', 'micro_mg_cam_register', cv_reffice_idx)
+ end if
+
+ ! Additional pbuf for CARMA interface
+ if (.not. do_cldice) then
+ call pbuf_add_field('TND_QSNOW', 'physpkg',dtype_r8,(/pcols,pver/), tnd_qsnow_idx)
+ call pbuf_add_field('TND_NSNOW', 'physpkg',dtype_r8,(/pcols,pver/), tnd_nsnow_idx)
+ call pbuf_add_field('RE_ICE', 'physpkg',dtype_r8,(/pcols,pver/), re_ice_idx)
+ end if
+
+ ! Precipitation efficiency fields across timesteps.
+ call pbuf_add_field('ACPRECL', 'global',dtype_r8,(/pcols/), acpr_idx) ! accumulated precip
+ call pbuf_add_field('ACGCME', 'global',dtype_r8,(/pcols/), acgcme_idx) ! accumulated condensation
+ call pbuf_add_field('ACNUM', 'global',dtype_i4,(/pcols/), acnum_idx) ! counter for accumulated # timesteps
+
+ ! SGS variability -- These could be reset by CLUBB so they need to be grid only
+ call pbuf_add_field('RELVAR', 'global',dtype_r8,(/pcols,pver/), relvar_idx)
+ call pbuf_add_field('ACCRE_ENHAN','global',dtype_r8,(/pcols,pver/), accre_enhan_idx)
+
+ ! Diagnostic fields needed for subcol_SILHS, need to be grid-only
+ if (subcol_get_scheme() == 'SILHS') then
+ call pbuf_add_field('QRAIN', 'global',dtype_r8,(/pcols,pver/), qrain_idx)
+ call pbuf_add_field('QSNOW', 'global',dtype_r8,(/pcols,pver/), qsnow_idx)
+ call pbuf_add_field('NRAIN', 'global',dtype_r8,(/pcols,pver/), nrain_idx)
+ call pbuf_add_field('NSNOW', 'global',dtype_r8,(/pcols,pver/), nsnow_idx)
+ end if
end subroutine micro_mg_cam_register
@@ -400,17 +537,15 @@ end subroutine micro_mg_cam_register
function micro_mg_cam_implements_cnst(name)
- ! Return true if specified constituent is implemented by the
- ! microphysics package
+ ! Return true if specified constituent is implemented by the
+ ! microphysics package
- character(len=*), intent(in) :: name ! constituent name
- logical :: micro_mg_cam_implements_cnst ! return value
+ character(len=*), intent(in) :: name ! constituent name
+ logical :: micro_mg_cam_implements_cnst ! return value
- ! Local workspace
- integer :: m
- !-----------------------------------------------------------------------
+ !-----------------------------------------------------------------------
- micro_mg_cam_implements_cnst = any(name == cnst_names)
+ micro_mg_cam_implements_cnst = any(name == cnst_names)
end function micro_mg_cam_implements_cnst
@@ -418,1694 +553,2428 @@ end function micro_mg_cam_implements_cnst
subroutine micro_mg_cam_init_cnst(name, q, gcid)
- ! Initialize the microphysics constituents, if they are
- ! not read from the initial file.
+ ! Initialize the microphysics constituents, if they are
+ ! not read from the initial file.
- character(len=*), intent(in) :: name ! constituent name
- real(r8), intent(out) :: q(:,:) ! mass mixing ratio (gcol, plev)
- integer, intent(in) :: gcid(:) ! global column id
- !-----------------------------------------------------------------------
+ character(len=*), intent(in) :: name ! constituent name
+ real(r8), intent(out) :: q(:,:) ! mass mixing ratio (gcol, plev)
+ integer, intent(in) :: gcid(:) ! global column id
+ !-----------------------------------------------------------------------
- if (micro_mg_cam_implements_cnst(name)) q = 0.0_r8
+ if (micro_mg_cam_implements_cnst(name)) q = 0.0_r8
end subroutine micro_mg_cam_init_cnst
!===============================================================================
subroutine micro_mg_cam_init(pbuf2d)
- use time_manager, only: is_first_step
- use micro_mg_utils, only: micro_mg_utils_init
- use micro_mg1_0, only: micro_mg_init1_0 => micro_mg_init
- use micro_mg1_5, only: micro_mg_init1_5 => micro_mg_init
-
- !-----------------------------------------------------------------------
- !
- ! Initialization for MG microphysics
- !
- !-----------------------------------------------------------------------
-
- type(physics_buffer_desc), pointer :: pbuf2d(:,:)
-
- integer :: m, mm
- logical :: history_amwg ! output the variables used by the AMWG diag package
- logical :: history_budget ! Output tendencies and state variables for CAM4
- ! temperature, water vapor, cloud ice and cloud
- ! liquid budgets.
- logical :: use_subcol_microp
- integer :: budget_histfile ! output history file number for budget fields
- integer :: ierr
-
- character(128) :: errstring ! return status (non-blank for error return)
-
- !-----------------------------------------------------------------------
-
- call phys_getopts(use_subcol_microp_out = use_subcol_microp)
-
- if (masterproc) then
- write(iulog,"(A,I2,A,I2)") "Initializing MG version ",micro_mg_version,".",micro_mg_sub_version
- if (.not. do_cldliq) &
- write(iulog,*) "MG prognostic cloud liquid has been turned off via namelist."
- if (.not. do_cldice) &
- write(iulog,*) "MG prognostic cloud ice has been turned off via namelist."
- end if
-
- select case (micro_mg_version)
- case (1)
- ! MG 1 does not initialize micro_mg_utils, so have to do it here.
- call micro_mg_utils_init(r8, rh2o, cpair, tmelt, latvap, latice, &
- errstring, dcs)
- call handle_errmsg(errstring, subname="micro_mg_utils_init")
-
- select case (micro_mg_sub_version)
- case (0)
- call micro_mg_init1_0( &
- r8, gravit, rair, rh2o, cpair, &
- rhoh2o, tmelt, latvap, latice, &
- rhmini, errstring, dcs)
- case (5)
- call micro_mg_init1_5( &
- r8, gravit, rair, rh2o, cpair, &
- tmelt, latvap, latice, rhmini, &
- microp_uniform, do_cldice, errstring, dcs)
- end select
- end select
-
- call handle_errmsg(errstring, subname="micro_mg_init")
-
- ! Register history variables
- do m = 1, ncnst
- call cnst_get_ind(cnst_names(m), mm)
- if ( any(mm == (/ ixcldliq, ixcldice /)) ) then
- ! mass mixing ratios
- call addfld(cnst_name(mm), 'kg/kg ', pver, 'A', cnst_longname(mm) , phys_decomp)
- call addfld(sflxnam(mm), 'kg/m2/s ', 1, 'A', trim(cnst_name(mm))//' surface flux', phys_decomp)
- else if ( any(mm == (/ ixnumliq, ixnumice /)) ) then
- ! number concentrations
- call addfld(cnst_name(mm), '1/kg ', pver, 'A', cnst_longname(mm) , phys_decomp)
- call addfld(sflxnam(mm), '1/m2/s ', 1, 'A', trim(cnst_name(mm))//' surface flux', phys_decomp)
- else
- call endrun( "micro_mg_cam_init: &
- &Could not call addfld for constituent with unknown units.")
- endif
- end do
-
- call addfld(apcnst(ixcldliq), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldliq))//' after physics' , phys_decomp)
- call addfld(apcnst(ixcldice), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldice))//' after physics' , phys_decomp)
- call addfld(bpcnst(ixcldliq), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldliq))//' before physics' , phys_decomp)
- call addfld(bpcnst(ixcldice), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldice))//' before physics' , phys_decomp)
-
- call addfld ('CME ', 'kg/kg/s ', pver, 'A', 'Rate of cond-evap within the cloud' ,phys_decomp)
- call addfld ('PRODPREC ', 'kg/kg/s ', pver, 'A', 'Rate of conversion of condensate to precip' ,phys_decomp)
- call addfld ('EVAPPREC ', 'kg/kg/s ', pver, 'A', 'Rate of evaporation of falling precip' ,phys_decomp)
- call addfld ('EVAPSNOW ', 'kg/kg/s ', pver, 'A', 'Rate of evaporation of falling snow' ,phys_decomp)
- call addfld ('HPROGCLD ', 'W/kg' , pver, 'A', 'Heating from prognostic clouds' ,phys_decomp)
- call addfld ('FICE ', 'fraction', pver, 'A', 'Fractional ice content within cloud' ,phys_decomp)
- call addfld ('ICWMRST ', 'kg/kg ', pver, 'A', 'Prognostic in-stratus water mixing ratio' ,phys_decomp)
- call addfld ('ICIMRST ', 'kg/kg ', pver, 'A', 'Prognostic in-stratus ice mixing ratio' ,phys_decomp)
-
- ! MG microphysics diagnostics
- call addfld ('QCSEVAP ', 'kg/kg/s ', pver, 'A', 'Rate of evaporation of falling cloud water' ,phys_decomp)
- call addfld ('QISEVAP ', 'kg/kg/s ', pver, 'A', 'Rate of sublimation of falling cloud ice' ,phys_decomp)
- call addfld ('QVRES ', 'kg/kg/s ', pver, 'A', 'Rate of residual condensation term' ,phys_decomp)
- call addfld ('CMEIOUT ', 'kg/kg/s ', pver, 'A', 'Rate of deposition/sublimation of cloud ice' ,phys_decomp)
- call addfld ('VTRMC ', 'm/s ', pver, 'A', 'Mass-weighted cloud water fallspeed' ,phys_decomp)
- call addfld ('VTRMI ', 'm/s ', pver, 'A', 'Mass-weighted cloud ice fallspeed' ,phys_decomp)
- call addfld ('QCSEDTEN ', 'kg/kg/s ', pver, 'A', 'Cloud water mixing ratio tendency from sedimentation' ,phys_decomp)
- call addfld ('QISEDTEN ', 'kg/kg/s ', pver, 'A', 'Cloud ice mixing ratio tendency from sedimentation' ,phys_decomp)
- call addfld ('PRAO ', 'kg/kg/s ', pver, 'A', 'Accretion of cloud water by rain' ,phys_decomp)
- call addfld ('PRCO ', 'kg/kg/s ', pver, 'A', 'Autoconversion of cloud water' ,phys_decomp)
- call addfld ('MNUCCCO ', 'kg/kg/s ', pver, 'A', 'Immersion freezing of cloud water' ,phys_decomp)
- call addfld ('MNUCCTO ', 'kg/kg/s ', pver, 'A', 'Contact freezing of cloud water' ,phys_decomp)
- call addfld ('MNUCCDO ', 'kg/kg/s ', pver, 'A', 'Homogeneous and heterogeneous nucleation from vapor' ,phys_decomp)
- call addfld ('MNUCCDOhet','kg/kg/s ', pver, 'A', 'Heterogeneous nucleation from vapor' ,phys_decomp)
- call addfld ('MSACWIO ', 'kg/kg/s ', pver, 'A', 'Conversion of cloud water from rime-splintering' ,phys_decomp)
- call addfld ('PSACWSO ', 'kg/kg/s ', pver, 'A', 'Accretion of cloud water by snow' ,phys_decomp)
- call addfld ('BERGSO ', 'kg/kg/s ', pver, 'A', 'Conversion of cloud water to snow from bergeron' ,phys_decomp)
- call addfld ('BERGO ', 'kg/kg/s ', pver, 'A', 'Conversion of cloud water to cloud ice from bergeron' ,phys_decomp)
- call addfld ('MELTO ', 'kg/kg/s ', pver, 'A', 'Melting of cloud ice' ,phys_decomp)
- call addfld ('HOMOO ', 'kg/kg/s ', pver, 'A', 'Homogeneous freezing of cloud water' ,phys_decomp)
- call addfld ('QCRESO ', 'kg/kg/s ', pver, 'A', 'Residual condensation term for cloud water' ,phys_decomp)
- call addfld ('PRCIO ', 'kg/kg/s ', pver, 'A', 'Autoconversion of cloud ice' ,phys_decomp)
- call addfld ('PRAIO ', 'kg/kg/s ', pver, 'A', 'Accretion of cloud ice by rain' ,phys_decomp)
- call addfld ('QIRESO ', 'kg/kg/s ', pver, 'A', 'Residual deposition term for cloud ice' ,phys_decomp)
- call addfld ('MNUCCRO ', 'kg/kg/s ', pver, 'A', 'Heterogeneous freezing of rain to snow' ,phys_decomp)
- call addfld ('PRACSO ', 'kg/kg/s ', pver, 'A', 'Accretion of rain by snow' ,phys_decomp)
- call addfld ('MELTSDT ', 'W/kg ', pver, 'A', 'Latent heating rate due to melting of snow' ,phys_decomp)
- call addfld ('FRZRDT ', 'W/kg ', pver, 'A', 'Latent heating rate due to homogeneous freezing of rain' ,phys_decomp)
-
- ! History variables for CAM5 microphysics
- call addfld ('MPDT ', 'W/kg ', pver, 'A', 'Heating tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDQ ', 'kg/kg/s ', pver, 'A', 'Q tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDLIQ ', 'kg/kg/s ', pver, 'A', 'CLDLIQ tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDICE ', 'kg/kg/s ', pver, 'A', 'CLDICE tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDW2V ', 'kg/kg/s ', pver, 'A', 'Water <--> Vapor tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDW2I ', 'kg/kg/s ', pver, 'A', 'Water <--> Ice tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDW2P ', 'kg/kg/s ', pver, 'A', 'Water <--> Precip tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDI2V ', 'kg/kg/s ', pver, 'A', 'Ice <--> Vapor tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDI2W ', 'kg/kg/s ', pver, 'A', 'Ice <--> Water tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('MPDI2P ', 'kg/kg/s ', pver, 'A', 'Ice <--> Precip tendency - Morrison microphysics' ,phys_decomp)
- call addfld ('ICWNC ', 'm-3 ', pver, 'A', 'Prognostic in-cloud water number conc' ,phys_decomp)
- call addfld ('ICINC ', 'm-3 ', pver, 'A', 'Prognostic in-cloud ice number conc' ,phys_decomp)
- call addfld ('EFFLIQ_IND','Micron ', pver, 'A', 'Prognostic droplet effective radius (indirect effect)' ,phys_decomp)
- call addfld ('CDNUMC ', '1/m2 ', 1, 'A', 'Vertically-integrated droplet concentration' ,phys_decomp)
- call addfld ('MPICLWPI ', 'kg/m2 ', 1, 'A', 'Vertically-integrated &
- &in-cloud Initial Liquid WP (Before Micro)' ,phys_decomp)
- call addfld ('MPICIWPI ', 'kg/m2 ', 1, 'A', 'Vertically-integrated &
- &in-cloud Initial Ice WP (Before Micro)' ,phys_decomp)
-
- ! This is provided as an example on how to write out subcolumn output
- ! NOTE -- only 'I' should be used for sub-column fields as subc-columns could shift from time-step to time-step
- if (use_subcol_microp) then
- call addfld('FICE_SCOL', 'fraction', psubcols*pver, 'I', &
- 'Sub-column fractional ice content within cloud', phys_decomp, &
- mdimnames=(/'psubcols','lev '/), flag_xyfill=.true., fill_value=1.e30_r8)
- end if
-
- ! Averaging for cloud particle number and size
- call addfld ('AWNC ', 'm-3 ', pver, 'A', 'Average cloud water number conc' ,phys_decomp)
- call addfld ('AWNI ', 'm-3 ', pver, 'A', 'Average cloud ice number conc' ,phys_decomp)
- call addfld ('AREL ', 'Micron ', pver, 'A', 'Average droplet effective radius' ,phys_decomp)
- call addfld ('AREI ', 'Micron ', pver, 'A', 'Average ice effective radius' ,phys_decomp)
- ! Frequency arrays for above
- call addfld ('FREQL ', 'fraction', pver, 'A', 'Fractional occurrence of liquid' ,phys_decomp)
- call addfld ('FREQI ', 'fraction', pver, 'A', 'Fractional occurrence of ice' ,phys_decomp)
-
- ! Average cloud top particle size and number (liq, ice) and frequency
- call addfld ('ACTREL ', 'Micron ', 1, 'A', 'Average Cloud Top droplet effective radius' ,phys_decomp)
- call addfld ('ACTREI ', 'Micron ', 1, 'A', 'Average Cloud Top ice effective radius' ,phys_decomp)
- call addfld ('ACTNL ', 'Micron ', 1, 'A', 'Average Cloud Top droplet number' ,phys_decomp)
- call addfld ('ACTNI ', 'Micron ', 1, 'A', 'Average Cloud Top ice number' ,phys_decomp)
-
- call addfld ('FCTL ', 'fraction', 1, 'A', 'Fractional occurrence of cloud top liquid' ,phys_decomp)
- call addfld ('FCTI ', 'fraction', 1, 'A', 'Fractional occurrence of cloud top ice' ,phys_decomp)
-
- call addfld ('LS_FLXPRC', 'kg/m2/s', pverp, 'A', 'ls stratiform gbm interface rain+snow flux', phys_decomp)
- call addfld ('LS_FLXSNW', 'kg/m2/s', pverp, 'A', 'ls stratiform gbm interface snow flux', phys_decomp)
-
- call addfld ('REL', 'micron', pver, 'A', 'MG REL stratiform cloud effective radius liquid', phys_decomp)
- call addfld ('REI', 'micron', pver, 'A', 'MG REI stratiform cloud effective radius ice', phys_decomp)
- call addfld ('LS_REFFRAIN', 'micron', pver, 'A', 'ls stratiform rain effective radius', phys_decomp)
- call addfld ('LS_REFFSNOW', 'micron', pver, 'A', 'ls stratiform snow effective radius', phys_decomp)
- call addfld ('CV_REFFLIQ', 'micron', pver, 'A', 'convective cloud liq effective radius', phys_decomp)
- call addfld ('CV_REFFICE', 'micron', pver, 'A', 'convective cloud ice effective radius', phys_decomp)
-
- ! diagnostic precip
- call addfld ('QRAIN ','kg/kg ',pver, 'A','Diagnostic grid-mean rain mixing ratio' ,phys_decomp)
- call addfld ('QSNOW ','kg/kg ',pver, 'A','Diagnostic grid-mean snow mixing ratio' ,phys_decomp)
- call addfld ('NRAIN ','m-3 ',pver, 'A','Diagnostic grid-mean rain number conc' ,phys_decomp)
- call addfld ('NSNOW ','m-3 ',pver, 'A','Diagnostic grid-mean snow number conc' ,phys_decomp)
-
- ! size of precip
- call addfld ('RERCLD ','m ',pver, 'A','Diagnostic effective radius of Liquid Cloud and Rain' ,phys_decomp)
- call addfld ('DSNOW ','m ',pver, 'A','Diagnostic grid-mean snow diameter' ,phys_decomp)
-
- ! diagnostic radar reflectivity, cloud-averaged
- call addfld ('REFL ','DBz ',pver, 'A','94 GHz radar reflectivity' ,phys_decomp)
- call addfld ('AREFL ','DBz ',pver, 'A','Average 94 GHz radar reflectivity' ,phys_decomp)
- call addfld ('FREFL ','fraction ',pver, 'A','Fractional occurrence of radar reflectivity' ,phys_decomp)
-
- call addfld ('CSRFL ','DBz ',pver, 'A','94 GHz radar reflectivity (CloudSat thresholds)' ,phys_decomp)
- call addfld ('ACSRFL ','DBz ',pver, 'A','Average 94 GHz radar reflectivity (CloudSat thresholds)' ,phys_decomp)
- call addfld ('FCSRFL ','fraction ',pver, 'A','Fractional occurrence of radar reflectivity (CloudSat thresholds)' &
- ,phys_decomp)
-
- call addfld ('AREFLZ ','mm^6/m^3 ',pver, 'A','Average 94 GHz radar reflectivity' ,phys_decomp)
-
- ! Aerosol information
- call addfld ('NCAL ','1/m3 ',pver, 'A','Number Concentation Activated for Liquid',phys_decomp)
- call addfld ('NCAI ','1/m3 ',pver, 'A','Number Concentation Activated for Ice',phys_decomp)
-
- ! Average rain and snow mixing ratio (Q), number (N) and diameter (D), with frequency
- call addfld ('AQRAIN ','kg/kg ',pver, 'A','Average rain mixing ratio' ,phys_decomp)
- call addfld ('AQSNOW ','kg/kg ',pver, 'A','Average snow mixing ratio' ,phys_decomp)
- call addfld ('ANRAIN ','m-3 ',pver, 'A','Average rain number conc' ,phys_decomp)
- call addfld ('ANSNOW ','m-3 ',pver, 'A','Average snow number conc' ,phys_decomp)
- call addfld ('ADRAIN ','Micron ',pver, 'A','Average rain effective Diameter' ,phys_decomp)
- call addfld ('ADSNOW ','Micron ',pver, 'A','Average snow effective Diameter' ,phys_decomp)
- call addfld ('FREQR ','fraction ',pver, 'A','Fractional occurrence of rain' ,phys_decomp)
- call addfld ('FREQS ','fraction ',pver, 'A','Fractional occurrence of snow' ,phys_decomp)
-
- ! precipitation efficiency & other diagnostic fields
- call addfld('PE' , '1', 1, 'A', 'Stratiform Precipitation Efficiency (precip/cmeliq)', phys_decomp )
- call addfld('APRL' , 'm/s', 1, 'A', 'Average Stratiform Precip Rate over efficiency calculation', phys_decomp )
- call addfld('PEFRAC', '1', 1, 'A', 'Fraction of timesteps precip efficiency reported', phys_decomp )
- call addfld('VPRCO' , 'kg/kg/s', 1, 'A', 'Vertical average of autoconversion rate', phys_decomp )
- call addfld('VPRAO' , 'kg/kg/s', 1, 'A', 'Vertical average of accretion rate', phys_decomp )
- call addfld('RACAU' , 'kg/kg/s', 1, 'A', 'Accretion/autoconversion ratio from vertical average', phys_decomp )
-
- ! determine the add_default fields
- call phys_getopts(history_amwg_out = history_amwg , &
- history_budget_out = history_budget , &
- history_budget_histfile_num_out = budget_histfile)
-
- if (history_amwg) then
- call add_default ('FICE ', 1, ' ')
- call add_default ('AQRAIN ', 1, ' ')
- call add_default ('AQSNOW ', 1, ' ')
- call add_default ('ANRAIN ', 1, ' ')
- call add_default ('ANSNOW ', 1, ' ')
- call add_default ('AREI ', 1, ' ')
- call add_default ('AREL ', 1, ' ')
- call add_default ('AWNC ', 1, ' ')
- call add_default ('AWNI ', 1, ' ')
- call add_default ('CDNUMC ', 1, ' ')
- call add_default ('FREQR ', 1, ' ')
- call add_default ('FREQS ', 1, ' ')
- call add_default ('FREQL ', 1, ' ')
- call add_default ('FREQI ', 1, ' ')
- do m = 1, ncnst
- call cnst_get_ind(cnst_names(m), mm)
- call add_default(cnst_name(mm), 1, ' ')
- ! call add_default(sflxnam(mm), 1, ' ')
- end do
- end if
-
- if ( history_budget ) then
- call add_default ('EVAPSNOW ', budget_histfile, ' ')
- call add_default ('EVAPPREC ', budget_histfile, ' ')
- call add_default ('QVRES ', budget_histfile, ' ')
- call add_default ('QISEVAP ', budget_histfile, ' ')
- call add_default ('QCSEVAP ', budget_histfile, ' ')
- call add_default ('QISEDTEN ', budget_histfile, ' ')
- call add_default ('QCSEDTEN ', budget_histfile, ' ')
- call add_default ('QIRESO ', budget_histfile, ' ')
- call add_default ('QCRESO ', budget_histfile, ' ')
- call add_default ('PSACWSO ', budget_histfile, ' ')
- call add_default ('PRCO ', budget_histfile, ' ')
- call add_default ('PRCIO ', budget_histfile, ' ')
- call add_default ('PRAO ', budget_histfile, ' ')
- call add_default ('PRAIO ', budget_histfile, ' ')
- call add_default ('PRACSO ', budget_histfile, ' ')
- call add_default ('MSACWIO ', budget_histfile, ' ')
- call add_default ('MPDW2V ', budget_histfile, ' ')
- call add_default ('MPDW2P ', budget_histfile, ' ')
- call add_default ('MPDW2I ', budget_histfile, ' ')
- call add_default ('MPDT ', budget_histfile, ' ')
- call add_default ('MPDQ ', budget_histfile, ' ')
- call add_default ('MPDLIQ ', budget_histfile, ' ')
- call add_default ('MPDICE ', budget_histfile, ' ')
- call add_default ('MPDI2W ', budget_histfile, ' ')
- call add_default ('MPDI2V ', budget_histfile, ' ')
- call add_default ('MPDI2P ', budget_histfile, ' ')
- call add_default ('MNUCCTO ', budget_histfile, ' ')
- call add_default ('MNUCCRO ', budget_histfile, ' ')
- call add_default ('MNUCCCO ', budget_histfile, ' ')
- call add_default ('MELTSDT ', budget_histfile, ' ')
- call add_default ('MELTO ', budget_histfile, ' ')
- call add_default ('HOMOO ', budget_histfile, ' ')
- call add_default ('FRZRDT ', budget_histfile, ' ')
- call add_default ('CMEIOUT ', budget_histfile, ' ')
- call add_default ('BERGSO ', budget_histfile, ' ')
- call add_default ('BERGO ', budget_histfile, ' ')
-
- call add_default(cnst_name(ixcldliq), budget_histfile, ' ')
- call add_default(cnst_name(ixcldice), budget_histfile, ' ')
- call add_default(apcnst (ixcldliq), budget_histfile, ' ')
- call add_default(apcnst (ixcldice), budget_histfile, ' ')
- call add_default(bpcnst (ixcldliq), budget_histfile, ' ')
- call add_default(bpcnst (ixcldice), budget_histfile, ' ')
-
- end if
-
- ! physics buffer indices
- ast_idx = pbuf_get_index('AST')
- aist_idx = pbuf_get_index('AIST')
- alst_idx = pbuf_get_index('ALST')
- cld_idx = pbuf_get_index('CLD')
- concld_idx = pbuf_get_index('CONCLD')
-
- naai_idx = pbuf_get_index('NAAI')
- naai_hom_idx = pbuf_get_index('NAAI_HOM')
- npccn_idx = pbuf_get_index('NPCCN')
- rndst_idx = pbuf_get_index('RNDST')
- nacon_idx = pbuf_get_index('NACON')
-
- prec_str_idx = pbuf_get_index('PREC_STR')
- snow_str_idx = pbuf_get_index('SNOW_STR')
- prec_sed_idx = pbuf_get_index('PREC_SED')
- snow_sed_idx = pbuf_get_index('SNOW_SED')
- prec_pcw_idx = pbuf_get_index('PREC_PCW')
- snow_pcw_idx = pbuf_get_index('SNOW_PCW')
-
- cmeliq_idx = pbuf_get_index('CMELIQ')
-
- ! These fields may have been added, so don't abort if they have not been
- qrain_idx = pbuf_get_index('QRAIN', ierr)
- qsnow_idx = pbuf_get_index('QSNOW', ierr)
- nrain_idx = pbuf_get_index('NRAIN', ierr)
- nsnow_idx = pbuf_get_index('NSNOW', ierr)
+ use time_manager, only: is_first_step
+ use micro_mg_utils, only: micro_mg_utils_init
+ use micro_mg1_0, only: micro_mg_init1_0 => micro_mg_init
+ use micro_mg1_5, only: micro_mg_init1_5 => micro_mg_init
+ use micro_mg2_0, only: micro_mg_init2_0 => micro_mg_init
+
+ !-----------------------------------------------------------------------
+ !
+ ! Initialization for MG microphysics
+ !
+ !-----------------------------------------------------------------------
+
+ type(physics_buffer_desc), pointer :: pbuf2d(:,:)
+
+ integer :: m, mm
+ logical :: history_amwg ! output the variables used by the AMWG diag package
+ logical :: history_budget ! Output tendencies and state variables for CAM4
+ ! temperature, water vapor, cloud ice and cloud
+ ! liquid budgets.
+ logical :: use_subcol_microp
+ logical :: do_clubb_sgs
+ integer :: budget_histfile ! output history file number for budget fields
+ integer :: ierr
+ character(128) :: errstring ! return status (non-blank for error return)
+
+ !-----------------------------------------------------------------------
+
+ call phys_getopts(use_subcol_microp_out=use_subcol_microp, &
+ do_clubb_sgs_out =do_clubb_sgs)
+
+ if (do_clubb_sgs) then
+ allow_sed_supersat = .false.
+ else
+ allow_sed_supersat = .true.
+ endif
+
+ if (masterproc) then
+ write(iulog,"(A,I2,A,I2)") "Initializing MG version ",micro_mg_version,".",micro_mg_sub_version
+ if (.not. do_cldliq) &
+ write(iulog,*) "MG prognostic cloud liquid has been turned off via namelist."
+ if (.not. do_cldice) &
+ write(iulog,*) "MG prognostic cloud ice has been turned off via namelist."
+ write(iulog,*) "Number of microphysics substeps is: ",num_steps
+ end if
+
+ select case (micro_mg_version)
+ case (1)
+ ! Set constituent number for later loops.
+ ncnst = 4
+
+ select case (micro_mg_sub_version)
+ case (0)
+ ! MG 1 does not initialize micro_mg_utils, so have to do it here.
+ call micro_mg_utils_init(r8, rh2o, cpair, tmelt, latvap, latice, &
+ micro_mg_dcs, errstring)
+ call handle_errmsg(errstring, subname="micro_mg_utils_init")
+
+ call micro_mg_init1_0( &
+ r8, gravit, rair, rh2o, cpair, &
+ rhoh2o, tmelt, latvap, latice, &
+ rhmini, micro_mg_dcs, use_hetfrz_classnuc, &
+ micro_mg_precip_frac_method, micro_mg_berg_eff_factor, errstring)
+ case (5)
+ ! MG 1 does not initialize micro_mg_utils, so have to do it here.
+ call micro_mg_utils_init(r8, rh2o, cpair, tmelt, latvap, latice, &
+ micro_mg_dcs, errstring)
+ call handle_errmsg(errstring, subname="micro_mg_utils_init")
+
+ call micro_mg_init1_5( &
+ r8, gravit, rair, rh2o, cpair, &
+ tmelt, latvap, latice, rhmini, &
+ micro_mg_dcs, &
+ microp_uniform, do_cldice, use_hetfrz_classnuc, &
+ micro_mg_precip_frac_method, micro_mg_berg_eff_factor, errstring)
+ end select
+ case (2)
+ ! Set constituent number for later loops.
+ ncnst = 8
+
+ select case (micro_mg_sub_version)
+ case (0)
+ call micro_mg_init2_0( &
+ r8, gravit, rair, rh2o, cpair, &
+ tmelt, latvap, latice, rhmini, &
+ micro_mg_dcs, &
+ microp_uniform, do_cldice, use_hetfrz_classnuc, &
+ micro_mg_precip_frac_method, micro_mg_berg_eff_factor, &
+ allow_sed_supersat, errstring)
+ end select
+ end select
+
+ call handle_errmsg(errstring, subname="micro_mg_init")
+
+ ! Register history variables
+ do m = 1, ncnst
+ call cnst_get_ind(cnst_names(m), mm)
+ if ( any(mm == (/ ixcldliq, ixcldice, ixrain, ixsnow /)) ) then
+ ! mass mixing ratios
+ call addfld(cnst_name(mm), 'kg/kg ', pver, 'A', cnst_longname(mm) , phys_decomp)
+ call addfld(sflxnam(mm), 'kg/m2/s ', 1, 'A', trim(cnst_name(mm))//' surface flux', phys_decomp)
+ else if ( any(mm == (/ ixnumliq, ixnumice, ixnumrain, ixnumsnow /)) ) then
+ ! number concentrations
+ call addfld(cnst_name(mm), '1/kg ', pver, 'A', cnst_longname(mm) , phys_decomp)
+ call addfld(sflxnam(mm), '1/m2/s ', 1, 'A', trim(cnst_name(mm))//' surface flux', phys_decomp)
+ else
+ call endrun( "micro_mg_cam_init: &
+ &Could not call addfld for constituent with unknown units.")
+ endif
+ end do
+
+ call addfld(apcnst(ixcldliq), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldliq))//' after physics' , phys_decomp)
+ call addfld(apcnst(ixcldice), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldice))//' after physics' , phys_decomp)
+ call addfld(bpcnst(ixcldliq), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldliq))//' before physics' , phys_decomp)
+ call addfld(bpcnst(ixcldice), 'kg/kg ', pver, 'A', trim(cnst_name(ixcldice))//' before physics' , phys_decomp)
+
+ if (micro_mg_version > 1) then
+ call addfld(apcnst(ixrain), 'kg/kg ', pver, 'A', trim(cnst_name(ixrain))//' after physics' , phys_decomp)
+ call addfld(apcnst(ixsnow), 'kg/kg ', pver, 'A', trim(cnst_name(ixsnow))//' after physics' , phys_decomp)
+ call addfld(bpcnst(ixrain), 'kg/kg ', pver, 'A', trim(cnst_name(ixrain))//' before physics' , phys_decomp)
+ call addfld(bpcnst(ixsnow), 'kg/kg ', pver, 'A', trim(cnst_name(ixsnow))//' before physics' , phys_decomp)
+ end if
+
+ call addfld ('CME ', 'kg/kg/s ', pver, 'A', 'Rate of cond-evap within the cloud' ,phys_decomp)
+ call addfld ('PRODPREC ', 'kg/kg/s ', pver, 'A', 'Rate of conversion of condensate to precip' ,phys_decomp)
+ call addfld ('EVAPPREC ', 'kg/kg/s ', pver, 'A', 'Rate of evaporation of falling precip' ,phys_decomp)
+ call addfld ('EVAPSNOW ', 'kg/kg/s ', pver, 'A', 'Rate of evaporation of falling snow' ,phys_decomp)
+ call addfld ('HPROGCLD ', 'W/kg' , pver, 'A', 'Heating from prognostic clouds' ,phys_decomp)
+ call addfld ('FICE ', 'fraction', pver, 'A', 'Fractional ice content within cloud' ,phys_decomp)
+ call addfld ('ICWMRST ', 'kg/kg ', pver, 'A', 'Prognostic in-stratus water mixing ratio' ,phys_decomp)
+ call addfld ('ICIMRST ', 'kg/kg ', pver, 'A', 'Prognostic in-stratus ice mixing ratio' ,phys_decomp)
+
+ ! MG microphysics diagnostics
+ call addfld ('QCSEVAP ', 'kg/kg/s ', pver, 'A', 'Rate of evaporation of falling cloud water' ,phys_decomp)
+ call addfld ('QISEVAP ', 'kg/kg/s ', pver, 'A', 'Rate of sublimation of falling cloud ice' ,phys_decomp)
+ call addfld ('QVRES ', 'kg/kg/s ', pver, 'A', 'Rate of residual condensation term' ,phys_decomp)
+ call addfld ('CMEIOUT ', 'kg/kg/s ', pver, 'A', 'Rate of deposition/sublimation of cloud ice' ,phys_decomp)
+ call addfld ('VTRMC ', 'm/s ', pver, 'A', 'Mass-weighted cloud water fallspeed' ,phys_decomp)
+ call addfld ('VTRMI ', 'm/s ', pver, 'A', 'Mass-weighted cloud ice fallspeed' ,phys_decomp)
+ call addfld ('QCSEDTEN ', 'kg/kg/s ', pver, 'A', 'Cloud water mixing ratio tendency from sedimentation' ,phys_decomp)
+ call addfld ('QISEDTEN ', 'kg/kg/s ', pver, 'A', 'Cloud ice mixing ratio tendency from sedimentation' ,phys_decomp)
+ call addfld ('PRAO ', 'kg/kg/s ', pver, 'A', 'Accretion of cloud water by rain' ,phys_decomp)
+ call addfld ('PRCO ', 'kg/kg/s ', pver, 'A', 'Autoconversion of cloud water' ,phys_decomp)
+ call addfld ('MNUCCCO ', 'kg/kg/s ', pver, 'A', 'Immersion freezing of cloud water' ,phys_decomp)
+ call addfld ('MNUCCTO ', 'kg/kg/s ', pver, 'A', 'Contact freezing of cloud water' ,phys_decomp)
+ call addfld ('MNUCCDO ', 'kg/kg/s ', pver, 'A', 'Homogeneous and heterogeneous nucleation from vapor' ,phys_decomp)
+ call addfld ('MNUCCDOhet','kg/kg/s ', pver, 'A', 'Heterogeneous nucleation from vapor' ,phys_decomp)
+ call addfld ('MSACWIO ', 'kg/kg/s ', pver, 'A', 'Conversion of cloud water from rime-splintering' ,phys_decomp)
+ call addfld ('PSACWSO ', 'kg/kg/s ', pver, 'A', 'Accretion of cloud water by snow' ,phys_decomp)
+ call addfld ('BERGSO ', 'kg/kg/s ', pver, 'A', 'Conversion of cloud water to snow from bergeron' ,phys_decomp)
+ call addfld ('BERGO ', 'kg/kg/s ', pver, 'A', 'Conversion of cloud water to cloud ice from bergeron' ,phys_decomp)
+ call addfld ('MELTO ', 'kg/kg/s ', pver, 'A', 'Melting of cloud ice' ,phys_decomp)
+ call addfld ('HOMOO ', 'kg/kg/s ', pver, 'A', 'Homogeneous freezing of cloud water' ,phys_decomp)
+ call addfld ('QCRESO ', 'kg/kg/s ', pver, 'A', 'Residual condensation term for cloud water' ,phys_decomp)
+ call addfld ('PRCIO ', 'kg/kg/s ', pver, 'A', 'Autoconversion of cloud ice' ,phys_decomp)
+ call addfld ('PRAIO ', 'kg/kg/s ', pver, 'A', 'Accretion of cloud ice by rain' ,phys_decomp)
+ call addfld ('QIRESO ', 'kg/kg/s ', pver, 'A', 'Residual deposition term for cloud ice' ,phys_decomp)
+ call addfld ('MNUCCRO ', 'kg/kg/s ', pver, 'A', 'Heterogeneous freezing of rain to snow' ,phys_decomp)
+ call addfld ('PRACSO ', 'kg/kg/s ', pver, 'A', 'Accretion of rain by snow' ,phys_decomp)
+ call addfld ('MELTSDT ', 'W/kg ', pver, 'A', 'Latent heating rate due to melting of snow' ,phys_decomp)
+ call addfld ('FRZRDT ', 'W/kg ', pver, 'A', 'Latent heating rate due to homogeneous freezing of rain' ,phys_decomp)
+ if (micro_mg_version > 1) then
+ call addfld ('QRSEDTEN ', 'kg/kg/s ', pver, 'A', 'Rain mixing ratio tendency from sedimentation' ,phys_decomp)
+ call addfld ('QSSEDTEN ', 'kg/kg/s ', pver, 'A', 'Snow mixing ratio tendency from sedimentation' ,phys_decomp)
+ end if
+
+ ! History variables for CAM5 microphysics
+ call addfld ('MPDT ', 'W/kg ', pver, 'A', 'Heating tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDQ ', 'kg/kg/s ', pver, 'A', 'Q tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDLIQ ', 'kg/kg/s ', pver, 'A', 'CLDLIQ tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDICE ', 'kg/kg/s ', pver, 'A', 'CLDICE tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDW2V ', 'kg/kg/s ', pver, 'A', 'Water <--> Vapor tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDW2I ', 'kg/kg/s ', pver, 'A', 'Water <--> Ice tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDW2P ', 'kg/kg/s ', pver, 'A', 'Water <--> Precip tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDI2V ', 'kg/kg/s ', pver, 'A', 'Ice <--> Vapor tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDI2W ', 'kg/kg/s ', pver, 'A', 'Ice <--> Water tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('MPDI2P ', 'kg/kg/s ', pver, 'A', 'Ice <--> Precip tendency - Morrison microphysics' ,phys_decomp)
+ call addfld ('ICWNC ', 'm-3 ', pver, 'A', 'Prognostic in-cloud water number conc' ,phys_decomp)
+ call addfld ('ICINC ', 'm-3 ', pver, 'A', 'Prognostic in-cloud ice number conc' ,phys_decomp)
+ call addfld ('EFFLIQ_IND','Micron ', pver, 'A', 'Prognostic droplet effective radius (indirect effect)' ,phys_decomp)
+ call addfld ('CDNUMC ', '1/m2 ', 1, 'A', 'Vertically-integrated droplet concentration' ,phys_decomp)
+ call addfld ('MPICLWPI ', 'kg/m2 ', 1, 'A', 'Vertically-integrated &
+ &in-cloud Initial Liquid WP (Before Micro)' ,phys_decomp)
+ call addfld ('MPICIWPI ', 'kg/m2 ', 1, 'A', 'Vertically-integrated &
+ &in-cloud Initial Ice WP (Before Micro)' ,phys_decomp)
+
+ ! This is provided as an example on how to write out subcolumn output
+ ! NOTE -- only 'I' should be used for sub-column fields as subc-columns could shift from time-step to time-step
+ if (use_subcol_microp) then
+ call addfld('FICE_SCOL', 'fraction', psubcols*pver, 'I', &
+ 'Sub-column fractional ice content within cloud', phys_decomp, &
+ mdimnames=(/'psubcols','lev '/), flag_xyfill=.true., fill_value=1.e30_r8)
+ end if
+
+ ! Averaging for cloud particle number and size
+ call addfld ('AWNC ', 'm-3 ', pver, 'A', 'Average cloud water number conc' ,phys_decomp)
+ call addfld ('AWNI ', 'm-3 ', pver, 'A', 'Average cloud ice number conc' ,phys_decomp)
+ call addfld ('AREL ', 'Micron ', pver, 'A', 'Average droplet effective radius' ,phys_decomp)
+ call addfld ('AREI ', 'Micron ', pver, 'A', 'Average ice effective radius' ,phys_decomp)
+ ! Frequency arrays for above
+ call addfld ('FREQL ', 'fraction', pver, 'A', 'Fractional occurrence of liquid' ,phys_decomp)
+ call addfld ('FREQI ', 'fraction', pver, 'A', 'Fractional occurrence of ice' ,phys_decomp)
+
+ ! Average cloud top particle size and number (liq, ice) and frequency
+ call addfld ('ACTREL ', 'Micron ', 1, 'A', 'Average Cloud Top droplet effective radius' ,phys_decomp)
+ call addfld ('ACTREI ', 'Micron ', 1, 'A', 'Average Cloud Top ice effective radius' ,phys_decomp)
+ call addfld ('ACTNL ', 'Micron ', 1, 'A', 'Average Cloud Top droplet number' ,phys_decomp)
+ call addfld ('ACTNI ', 'Micron ', 1, 'A', 'Average Cloud Top ice number' ,phys_decomp)
+
+ call addfld ('FCTL ', 'fraction', 1, 'A', 'Fractional occurrence of cloud top liquid' ,phys_decomp)
+ call addfld ('FCTI ', 'fraction', 1, 'A', 'Fractional occurrence of cloud top ice' ,phys_decomp)
+
+ call addfld ('LS_FLXPRC', 'kg/m2/s', pverp, 'A', 'ls stratiform gbm interface rain+snow flux', phys_decomp)
+ call addfld ('LS_FLXSNW', 'kg/m2/s', pverp, 'A', 'ls stratiform gbm interface snow flux', phys_decomp)
+
+ call addfld ('REL', 'micron', pver, 'A', 'MG REL stratiform cloud effective radius liquid', phys_decomp)
+ call addfld ('REI', 'micron', pver, 'A', 'MG REI stratiform cloud effective radius ice', phys_decomp)
+ call addfld ('LS_REFFRAIN', 'micron', pver, 'A', 'ls stratiform rain effective radius', phys_decomp)
+ call addfld ('LS_REFFSNOW', 'micron', pver, 'A', 'ls stratiform snow effective radius', phys_decomp)
+ call addfld ('CV_REFFLIQ', 'micron', pver, 'A', 'convective cloud liq effective radius', phys_decomp)
+ call addfld ('CV_REFFICE', 'micron', pver, 'A', 'convective cloud ice effective radius', phys_decomp)
+
+ ! diagnostic precip
+ call addfld ('QRAIN ','kg/kg ',pver, 'A','Diagnostic grid-mean rain mixing ratio' ,phys_decomp)
+ call addfld ('QSNOW ','kg/kg ',pver, 'A','Diagnostic grid-mean snow mixing ratio' ,phys_decomp)
+ call addfld ('NRAIN ','m-3 ',pver, 'A','Diagnostic grid-mean rain number conc' ,phys_decomp)
+ call addfld ('NSNOW ','m-3 ',pver, 'A','Diagnostic grid-mean snow number conc' ,phys_decomp)
+
+ ! size of precip
+ call addfld ('RERCLD ','m ',pver, 'A','Diagnostic effective radius of Liquid Cloud and Rain' ,phys_decomp)
+ call addfld ('DSNOW ','m ',pver, 'A','Diagnostic grid-mean snow diameter' ,phys_decomp)
+
+ ! diagnostic radar reflectivity, cloud-averaged
+ call addfld ('REFL ','DBz ',pver, 'A','94 GHz radar reflectivity' ,phys_decomp)
+ call addfld ('AREFL ','DBz ',pver, 'A','Average 94 GHz radar reflectivity' ,phys_decomp)
+ call addfld ('FREFL ','fraction ',pver, 'A','Fractional occurrence of radar reflectivity' ,phys_decomp)
+
+ call addfld ('CSRFL ','DBz ',pver, 'A','94 GHz radar reflectivity (CloudSat thresholds)' ,phys_decomp)
+ call addfld ('ACSRFL ','DBz ',pver, 'A','Average 94 GHz radar reflectivity (CloudSat thresholds)' ,phys_decomp)
+ call addfld ('FCSRFL ','fraction ',pver, 'A','Fractional occurrence of radar reflectivity (CloudSat thresholds)' &
+ ,phys_decomp)
+
+ call addfld ('AREFLZ ','mm^6/m^3 ',pver, 'A','Average 94 GHz radar reflectivity' ,phys_decomp)
+
+ ! Aerosol information
+ call addfld ('NCAL ','1/m3 ',pver, 'A','Number Concentation Activated for Liquid',phys_decomp)
+ call addfld ('NCAI ','1/m3 ',pver, 'A','Number Concentation Activated for Ice',phys_decomp)
+
+ ! Average rain and snow mixing ratio (Q), number (N) and diameter (D), with frequency
+ call addfld ('AQRAIN ','kg/kg ',pver, 'A','Average rain mixing ratio' ,phys_decomp)
+ call addfld ('AQSNOW ','kg/kg ',pver, 'A','Average snow mixing ratio' ,phys_decomp)
+ call addfld ('ANRAIN ','m-3 ',pver, 'A','Average rain number conc' ,phys_decomp)
+ call addfld ('ANSNOW ','m-3 ',pver, 'A','Average snow number conc' ,phys_decomp)
+ call addfld ('ADRAIN ','Micron ',pver, 'A','Average rain effective Diameter' ,phys_decomp)
+ call addfld ('ADSNOW ','Micron ',pver, 'A','Average snow effective Diameter' ,phys_decomp)
+ call addfld ('FREQR ','fraction ',pver, 'A','Fractional occurrence of rain' ,phys_decomp)
+ call addfld ('FREQS ','fraction ',pver, 'A','Fractional occurrence of snow' ,phys_decomp)
+
+ ! precipitation efficiency & other diagnostic fields
+ call addfld('PE' , '1', 1, 'A', 'Stratiform Precipitation Efficiency (precip/cmeliq)', phys_decomp )
+ call addfld('APRL' , 'm/s', 1, 'A', 'Average Stratiform Precip Rate over efficiency calculation', phys_decomp )
+ call addfld('PEFRAC', '1', 1, 'A', 'Fraction of timesteps precip efficiency reported', phys_decomp )
+ call addfld('VPRCO' , 'kg/kg/s', 1, 'A', 'Vertical average of autoconversion rate', phys_decomp )
+ call addfld('VPRAO' , 'kg/kg/s', 1, 'A', 'Vertical average of accretion rate', phys_decomp )
+ call addfld('RACAU' , 'kg/kg/s', 1, 'A', 'Accretion/autoconversion ratio from vertical average', phys_decomp )
+
+ if (micro_mg_version > 1) then
+ call addfld('UMR', 'm/s ', pver, 'A', 'Mass-weighted rain fallspeed' , phys_decomp)
+ call addfld('UMS', 'm/s ', pver, 'A', 'Mass-weighted snow fallspeed' , phys_decomp)
+ end if
+
+ ! qc limiter (only output in versions 1.5 and later)
+ if (.not. (micro_mg_version == 1 .and. micro_mg_sub_version == 0)) then
+ call addfld('QCRAT', 'fraction', pver, 'A', 'Qc Limiter: Fraction of qc tendency applied', phys_decomp)
+ end if
+
+ ! determine the add_default fields
+ call phys_getopts(history_amwg_out = history_amwg , &
+ history_budget_out = history_budget , &
+ history_budget_histfile_num_out = budget_histfile)
+
+ if (history_amwg) then
+ call add_default ('FICE ', 1, ' ')
+ call add_default ('AQRAIN ', 1, ' ')
+ call add_default ('AQSNOW ', 1, ' ')
+ call add_default ('ANRAIN ', 1, ' ')
+ call add_default ('ANSNOW ', 1, ' ')
+ call add_default ('ADRAIN ', 1, ' ')
+ call add_default ('ADSNOW ', 1, ' ')
+ call add_default ('AREI ', 1, ' ')
+ call add_default ('AREL ', 1, ' ')
+ call add_default ('AWNC ', 1, ' ')
+ call add_default ('AWNI ', 1, ' ')
+ call add_default ('CDNUMC ', 1, ' ')
+ call add_default ('FREQR ', 1, ' ')
+ call add_default ('FREQS ', 1, ' ')
+ call add_default ('FREQL ', 1, ' ')
+ call add_default ('FREQI ', 1, ' ')
+ do m = 1, ncnst
+ call cnst_get_ind(cnst_names(m), mm)
+ call add_default(cnst_name(mm), 1, ' ')
+ ! call add_default(sflxnam(mm), 1, ' ')
+ end do
+ end if
+
+ if ( history_budget ) then
+ call add_default ('EVAPSNOW ', budget_histfile, ' ')
+ call add_default ('EVAPPREC ', budget_histfile, ' ')
+ call add_default ('QVRES ', budget_histfile, ' ')
+ call add_default ('QISEVAP ', budget_histfile, ' ')
+ call add_default ('QCSEVAP ', budget_histfile, ' ')
+ call add_default ('QISEDTEN ', budget_histfile, ' ')
+ call add_default ('QCSEDTEN ', budget_histfile, ' ')
+ call add_default ('QIRESO ', budget_histfile, ' ')
+ call add_default ('QCRESO ', budget_histfile, ' ')
+ if (micro_mg_version > 1) then
+ call add_default ('QRSEDTEN ', budget_histfile, ' ')
+ call add_default ('QSSEDTEN ', budget_histfile, ' ')
+ end if
+ call add_default ('PSACWSO ', budget_histfile, ' ')
+ call add_default ('PRCO ', budget_histfile, ' ')
+ call add_default ('PRCIO ', budget_histfile, ' ')
+ call add_default ('PRAO ', budget_histfile, ' ')
+ call add_default ('PRAIO ', budget_histfile, ' ')
+ call add_default ('PRACSO ', budget_histfile, ' ')
+ call add_default ('MSACWIO ', budget_histfile, ' ')
+ call add_default ('MPDW2V ', budget_histfile, ' ')
+ call add_default ('MPDW2P ', budget_histfile, ' ')
+ call add_default ('MPDW2I ', budget_histfile, ' ')
+ call add_default ('MPDT ', budget_histfile, ' ')
+ call add_default ('MPDQ ', budget_histfile, ' ')
+ call add_default ('MPDLIQ ', budget_histfile, ' ')
+ call add_default ('MPDICE ', budget_histfile, ' ')
+ call add_default ('MPDI2W ', budget_histfile, ' ')
+ call add_default ('MPDI2V ', budget_histfile, ' ')
+ call add_default ('MPDI2P ', budget_histfile, ' ')
+ call add_default ('MNUCCTO ', budget_histfile, ' ')
+ call add_default ('MNUCCRO ', budget_histfile, ' ')
+ call add_default ('MNUCCCO ', budget_histfile, ' ')
+ call add_default ('MELTSDT ', budget_histfile, ' ')
+ call add_default ('MELTO ', budget_histfile, ' ')
+ call add_default ('HOMOO ', budget_histfile, ' ')
+ call add_default ('FRZRDT ', budget_histfile, ' ')
+ call add_default ('CMEIOUT ', budget_histfile, ' ')
+ call add_default ('BERGSO ', budget_histfile, ' ')
+ call add_default ('BERGO ', budget_histfile, ' ')
+
+ call add_default(cnst_name(ixcldliq), budget_histfile, ' ')
+ call add_default(cnst_name(ixcldice), budget_histfile, ' ')
+ call add_default(apcnst (ixcldliq), budget_histfile, ' ')
+ call add_default(apcnst (ixcldice), budget_histfile, ' ')
+ call add_default(bpcnst (ixcldliq), budget_histfile, ' ')
+ call add_default(bpcnst (ixcldice), budget_histfile, ' ')
+ if (micro_mg_version > 1) then
+ call add_default(cnst_name(ixrain), budget_histfile, ' ')
+ call add_default(cnst_name(ixsnow), budget_histfile, ' ')
+ call add_default(apcnst (ixrain), budget_histfile, ' ')
+ call add_default(apcnst (ixsnow), budget_histfile, ' ')
+ call add_default(bpcnst (ixrain), budget_histfile, ' ')
+ call add_default(bpcnst (ixsnow), budget_histfile, ' ')
+ end if
+
+ end if
+
+ ! physics buffer indices
+ ast_idx = pbuf_get_index('AST')
+ cld_idx = pbuf_get_index('CLD')
+ concld_idx = pbuf_get_index('CONCLD')
+
+ naai_idx = pbuf_get_index('NAAI')
+ naai_hom_idx = pbuf_get_index('NAAI_HOM')
+ npccn_idx = pbuf_get_index('NPCCN')
+ rndst_idx = pbuf_get_index('RNDST')
+ nacon_idx = pbuf_get_index('NACON')
+
+ prec_str_idx = pbuf_get_index('PREC_STR')
+ snow_str_idx = pbuf_get_index('SNOW_STR')
+ prec_sed_idx = pbuf_get_index('PREC_SED')
+ snow_sed_idx = pbuf_get_index('SNOW_SED')
+ prec_pcw_idx = pbuf_get_index('PREC_PCW')
+ snow_pcw_idx = pbuf_get_index('SNOW_PCW')
+
+ cmeliq_idx = pbuf_get_index('CMELIQ')
+
+ ! These fields may have been added, so don't abort if they have not been
+ qrain_idx = pbuf_get_index('QRAIN', ierr)
+ qsnow_idx = pbuf_get_index('QSNOW', ierr)
+ nrain_idx = pbuf_get_index('NRAIN', ierr)
+ nsnow_idx = pbuf_get_index('NSNOW', ierr)
+
+ ! fields for heterogeneous freezing
+ frzimm_idx = pbuf_get_index('FRZIMM', ierr)
+ frzcnt_idx = pbuf_get_index('FRZCNT', ierr)
+ frzdep_idx = pbuf_get_index('FRZDEP', ierr)
! Initialize physics buffer grid fields for accumulating precip and condensation
- if (is_first_step()) then
- call pbuf_set_field(pbuf2d, cldo_idx, 0._r8)
- call pbuf_set_field(pbuf2d, cc_t_idx, 0._r8)
- call pbuf_set_field(pbuf2d, cc_qv_idx, 0._r8)
- call pbuf_set_field(pbuf2d, cc_ql_idx, 0._r8)
- call pbuf_set_field(pbuf2d, cc_qi_idx, 0._r8)
- call pbuf_set_field(pbuf2d, cc_nl_idx, 0._r8)
- call pbuf_set_field(pbuf2d, cc_ni_idx, 0._r8)
- call pbuf_set_field(pbuf2d, cc_qlst_idx,0._r8)
- call pbuf_set_field(pbuf2d, acpr_idx, 0._r8)
- call pbuf_set_field(pbuf2d, acgcme_idx, 0._r8)
- call pbuf_set_field(pbuf2d, acnum_idx, 0)
- call pbuf_set_field(pbuf2d, relvar_idx, 2._r8)
- call pbuf_set_field(pbuf2d, accre_enhan_idx, 1._r8)
-
- if (qrain_idx > 0) call pbuf_set_field(pbuf2d, qrain_idx, 0._r8)
- if (qsnow_idx > 0) call pbuf_set_field(pbuf2d, qsnow_idx, 0._r8)
- if (nrain_idx > 0) call pbuf_set_field(pbuf2d, nrain_idx, 0._r8)
- if (nsnow_idx > 0) call pbuf_set_field(pbuf2d, nsnow_idx, 0._r8)
-
- ! If sub-columns turned on, need to set the sub-column fields as well
- if (use_subcol_microp) then
- call pbuf_set_field(pbuf2d, cldo_idx, 0._r8, col_type=col_type_subcol)
- call pbuf_set_field(pbuf2d, cc_t_idx, 0._r8, col_type=col_type_subcol)
- call pbuf_set_field(pbuf2d, cc_qv_idx, 0._r8, col_type=col_type_subcol)
- call pbuf_set_field(pbuf2d, cc_ql_idx, 0._r8, col_type=col_type_subcol)
- call pbuf_set_field(pbuf2d, cc_qi_idx, 0._r8, col_type=col_type_subcol)
- call pbuf_set_field(pbuf2d, cc_nl_idx, 0._r8, col_type=col_type_subcol)
- call pbuf_set_field(pbuf2d, cc_ni_idx, 0._r8, col_type=col_type_subcol)
- call pbuf_set_field(pbuf2d, cc_qlst_idx,0._r8, col_type=col_type_subcol)
- end if
-
- end if
+ if (is_first_step()) then
+ call pbuf_set_field(pbuf2d, cldo_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cc_t_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cc_qv_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cc_ql_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cc_qi_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cc_nl_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cc_ni_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, cc_qlst_idx,0._r8)
+ call pbuf_set_field(pbuf2d, acpr_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, acgcme_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, acnum_idx, 0)
+ call pbuf_set_field(pbuf2d, relvar_idx, 2._r8)
+ call pbuf_set_field(pbuf2d, accre_enhan_idx, 1._r8)
+ call pbuf_set_field(pbuf2d, am_evp_st_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, evprain_st_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, evpsnow_st_idx, 0._r8)
+ call pbuf_set_field(pbuf2d, prer_evap_idx, 0._r8)
+
+ if (qrain_idx > 0) call pbuf_set_field(pbuf2d, qrain_idx, 0._r8)
+ if (qsnow_idx > 0) call pbuf_set_field(pbuf2d, qsnow_idx, 0._r8)
+ if (nrain_idx > 0) call pbuf_set_field(pbuf2d, nrain_idx, 0._r8)
+ if (nsnow_idx > 0) call pbuf_set_field(pbuf2d, nsnow_idx, 0._r8)
+
+ ! If sub-columns turned on, need to set the sub-column fields as well
+ if (use_subcol_microp) then
+ call pbuf_set_field(pbuf2d, cldo_idx, 0._r8, col_type=col_type_subcol)
+ call pbuf_set_field(pbuf2d, cc_t_idx, 0._r8, col_type=col_type_subcol)
+ call pbuf_set_field(pbuf2d, cc_qv_idx, 0._r8, col_type=col_type_subcol)
+ call pbuf_set_field(pbuf2d, cc_ql_idx, 0._r8, col_type=col_type_subcol)
+ call pbuf_set_field(pbuf2d, cc_qi_idx, 0._r8, col_type=col_type_subcol)
+ call pbuf_set_field(pbuf2d, cc_nl_idx, 0._r8, col_type=col_type_subcol)
+ call pbuf_set_field(pbuf2d, cc_ni_idx, 0._r8, col_type=col_type_subcol)
+ call pbuf_set_field(pbuf2d, cc_qlst_idx,0._r8, col_type=col_type_subcol)
+ end if
+
+ end if
end subroutine micro_mg_cam_init
-
!===============================================================================
subroutine micro_mg_cam_tend(state, ptend, dtime, pbuf)
- use micro_mg_utils, only: size_dist_param_basic, size_dist_param_liq, &
- mg_liq_props, mg_ice_props, avg_diameter, rhoi, rhosn, rhow, rhows, &
- qsmall, mincld
- use micro_mg1_0, only: micro_mg_tend1_0 => micro_mg_tend
- use micro_mg1_5, only: micro_mg_tend1_5 => micro_mg_tend, &
- micro_mg_get_cols1_5 => micro_mg_get_cols
-
- use ppgrid, only: pcols
- use physics_buffer, only: pbuf_col_type_index
- use subcol, only: subcol_field_avg
-
- type(physics_state), intent(in) :: state
- type(physics_ptend), intent(out) :: ptend
- real(r8), intent(in) :: dtime
- type(physics_buffer_desc), pointer :: pbuf(:)
-
- ! Local variables
- logical :: microp_uniform = .false. ! True = configure microphysics for sub-columns
- ! False = use in regular mode w/o sub-columns
- integer :: lchnk, ncol, psetcols, ngrdcol
-
- integer :: i, k, itim_old, it
-
- real(r8), pointer :: naai(:,:) ! ice nucleation number
- real(r8), pointer :: naai_hom(:,:) ! ice nucleation number (homogeneous)
- real(r8), pointer :: npccn(:,:) ! liquid activation number tendency
- real(r8), pointer :: rndst(:,:,:)
- real(r8), pointer :: nacon(:,:,:)
-
- real(r8), pointer :: prec_str(:) ! [Total] Sfc flux of precip from stratiform [ m/s ]
- real(r8), pointer :: snow_str(:) ! [Total] Sfc flux of snow from stratiform [ m/s ]
- real(r8), pointer :: prec_sed(:) ! Surface flux of total cloud water from sedimentation
- real(r8), pointer :: snow_sed(:) ! Surface flux of cloud ice from sedimentation
- real(r8), pointer :: prec_pcw(:) ! Sfc flux of precip from microphysics [ m/s ]
- real(r8), pointer :: snow_pcw(:) ! Sfc flux of snow from microphysics [ m/s ]
-
- real(r8), pointer :: ast(:,:) ! Relative humidity cloud fraction
- real(r8), pointer :: alst_mic(:,:)
- real(r8), pointer :: aist_mic(:,:)
- real(r8), pointer :: cldo(:,:) ! Old cloud fraction
- real(r8), pointer :: nevapr(:,:) ! Evaporation of total precipitation (rain + snow)
- real(r8), pointer :: relvar(:,:) ! relative variance of cloud water
- real(r8), pointer :: accre_enhan(:,:) ! optional accretion enhancement for experimentation
- real(r8), pointer :: prain(:,:) ! Total precipitation (rain + snow)
- real(r8), pointer :: dei(:,:) ! Ice effective diameter (meters) (AG: microns?)
- real(r8), pointer :: mu(:,:) ! Size distribution shape parameter for radiation
- real(r8), pointer :: lambdac(:,:) ! Size distribution slope parameter for radiation
- real(r8), pointer :: des(:,:) ! Snow effective diameter (m)
-
- real(r8) :: rho(state%psetcols,pver)
- real(r8) :: ncic(state%psetcols,pver)
- real(r8) :: niic(state%psetcols,pver)
-
- real(r8) :: rate1cld(state%psetcols,pver) ! array to hold rate1ord_cw2pr_st from microphysics
-
- real(r8) :: tlat(state%psetcols,pver)
- real(r8) :: qvlat(state%psetcols,pver)
- real(r8) :: qcten(state%psetcols,pver)
- real(r8) :: qiten(state%psetcols,pver)
- real(r8) :: ncten(state%psetcols,pver)
- real(r8) :: niten(state%psetcols,pver)
- real(r8) :: prect(state%psetcols)
- real(r8) :: preci(state%psetcols)
-
-
- real(r8) :: evapsnow(state%psetcols,pver) ! Local evaporation of snow
- real(r8) :: prodsnow(state%psetcols,pver) ! Local production of snow
- real(r8) :: cmeice(state%psetcols,pver) ! Rate of cond-evap of ice within the cloud
- real(r8) :: qsout(state%psetcols,pver) ! Snow mixing ratio
- real(r8) :: rflx(state%psetcols,pver+1) ! grid-box average rain flux (kg m^-2 s^-1)
- real(r8) :: sflx(state%psetcols,pver+1) ! grid-box average snow flux (kg m^-2 s^-1)
- real(r8) :: qrout(state%psetcols,pver) ! Rain mixing ratio
- real(r8) :: reff_rain(state%psetcols,pver) ! rain effective radius (um)
- real(r8) :: reff_snow(state%psetcols,pver) ! snow effective radius (um)
- real(r8) :: qcsevap(state%psetcols,pver) ! Evaporation of falling cloud water
- real(r8) :: qisevap(state%psetcols,pver) ! Sublimation of falling cloud ice
- real(r8) :: qvres(state%psetcols,pver) ! Residual condensation term to remove excess saturation
- real(r8) :: cmeiout(state%psetcols,pver) ! Deposition/sublimation rate of cloud ice
- real(r8) :: vtrmc(state%psetcols,pver) ! Mass-weighted cloud water fallspeed
- real(r8) :: vtrmi(state%psetcols,pver) ! Mass-weighted cloud ice fallspeed
- real(r8) :: qcsedten(state%psetcols,pver) ! Cloud water mixing ratio tendency from sedimentation
- real(r8) :: qisedten(state%psetcols,pver) ! Cloud ice mixing ratio tendency from sedimentation
- real(r8) :: prao(state%psetcols,pver)
- real(r8) :: prco(state%psetcols,pver)
- real(r8) :: mnuccco(state%psetcols,pver)
- real(r8) :: mnuccto(state%psetcols,pver)
- real(r8) :: msacwio(state%psetcols,pver)
- real(r8) :: psacwso(state%psetcols,pver)
- real(r8) :: bergso(state%psetcols,pver)
- real(r8) :: bergo(state%psetcols,pver)
- real(r8) :: melto(state%psetcols,pver)
- real(r8) :: homoo(state%psetcols,pver)
- real(r8) :: qcreso(state%psetcols,pver)
- real(r8) :: prcio(state%psetcols,pver)
- real(r8) :: praio(state%psetcols,pver)
- real(r8) :: qireso(state%psetcols,pver)
- real(r8) :: mnuccro(state%psetcols,pver)
- real(r8) :: pracso (state%psetcols,pver)
- real(r8) :: meltsdt(state%psetcols,pver)
- real(r8) :: frzrdt (state%psetcols,pver)
- real(r8) :: mnuccdo(state%psetcols,pver)
- real(r8) :: nrout(state%psetcols,pver)
- real(r8) :: nsout(state%psetcols,pver)
- real(r8) :: refl(state%psetcols,pver) ! analytic radar reflectivity
- real(r8) :: arefl(state%psetcols,pver) !average reflectivity will zero points outside valid range
- real(r8) :: areflz(state%psetcols,pver) !average reflectivity in z.
- real(r8) :: frefl(state%psetcols,pver)
- real(r8) :: csrfl(state%psetcols,pver) !cloudsat reflectivity
- real(r8) :: acsrfl(state%psetcols,pver) !cloudsat average
- real(r8) :: fcsrfl(state%psetcols,pver)
- real(r8) :: rercld(state%psetcols,pver) ! effective radius calculation for rain + cloud
- real(r8) :: ncai(state%psetcols,pver) ! output number conc of ice nuclei available (1/m3)
- real(r8) :: ncal(state%psetcols,pver) ! output number conc of CCN (1/m3)
- real(r8) :: qrout2(state%psetcols,pver)
- real(r8) :: qsout2(state%psetcols,pver)
- real(r8) :: nrout2(state%psetcols,pver)
- real(r8) :: nsout2(state%psetcols,pver)
- real(r8) :: drout2(state%psetcols,pver) ! mean rain particle diameter (m)
- real(r8) :: dsout2(state%psetcols,pver) ! mean snow particle diameter (m)
- real(r8) :: freqs(state%psetcols,pver)
- real(r8) :: freqr(state%psetcols,pver)
- real(r8) :: nfice(state%psetcols,pver)
-
- real(r8) :: mnuccdohet(state%psetcols,pver)
-
- ! physics buffer fields for COSP simulator
- real(r8), pointer :: mgflxprc(:,:) ! MG grid-box mean flux_large_scale_cloud_rain+snow at interfaces (kg/m2/s)
- real(r8), pointer :: mgflxsnw(:,:) ! MG grid-box mean flux_large_scale_cloud_snow at interfaces (kg/m2/s)
- real(r8), pointer :: mgmrprc(:,:) ! MG grid-box mean mixingratio_large_scale_cloud_rain+snow at interfaces (kg/kg)
- real(r8), pointer :: mgmrsnw(:,:) ! MG grid-box mean mixingratio_large_scale_cloud_snow at interfaces (kg/kg)
- real(r8), pointer :: mgreffrain_grid(:,:) ! MG diagnostic rain effective radius (um)
- real(r8), pointer :: mgreffsnow_grid(:,:) ! MG diagnostic snow effective radius (um)
- real(r8), pointer :: cvreffliq(:,:) ! convective cloud liquid effective radius (um)
- real(r8), pointer :: cvreffice(:,:) ! convective cloud ice effective radius (um)
-
- ! physics buffer fields used with CARMA
- real(r8), pointer, dimension(:,:) :: tnd_qsnow ! external tendency on snow mass (kg/kg/s)
- real(r8), pointer, dimension(:,:) :: tnd_nsnow ! external tendency on snow number(#/kg/s)
- real(r8), pointer, dimension(:,:) :: re_ice ! ice effective radius (m)
-
- real(r8), pointer :: rate1ord_cw2pr_st(:,:) ! 1st order rate for direct conversion of
- ! strat. cloud water to precip (1/s) ! rce 2010/05/01
- real(r8), pointer :: wsedl(:,:) ! Sedimentation velocity of liquid stratus cloud droplet [ m/s ]
-
-
- real(r8), pointer :: CC_T(:,:) ! Grid-mean microphysical tendency
- real(r8), pointer :: CC_qv(:,:) ! Grid-mean microphysical tendency
- real(r8), pointer :: CC_ql(:,:) ! Grid-mean microphysical tendency
- real(r8), pointer :: CC_qi(:,:) ! Grid-mean microphysical tendency
- real(r8), pointer :: CC_nl(:,:) ! Grid-mean microphysical tendency
- real(r8), pointer :: CC_ni(:,:) ! Grid-mean microphysical tendency
- real(r8), pointer :: CC_qlst(:,:) ! In-liquid stratus microphysical tendency
-
- real(r8), pointer :: qme(:,:)
-
- ! A local copy of state is used for diagnostic calculations
- type(physics_state) :: state_loc
- type(physics_ptend) :: ptend_loc
-
- real(r8) :: icecldf(state%psetcols,pver) ! Ice cloud fraction
- real(r8) :: liqcldf(state%psetcols,pver) ! Liquid cloud fraction (combined into cloud)
-
- real(r8), pointer :: rel(:,:) ! Liquid effective drop radius (microns)
- real(r8), pointer :: rei(:,:) ! Ice effective drop size (microns)
- real(r8) :: rel_fn(state%psetcols,pver) ! Ice effective drop size at fixed number (indirect effect) (microns)
-
- ! in-cloud water quantities adjusted for convective water
- real(r8) :: allcld_ice(state%psetcols,pver) ! All-cloud cloud ice
- real(r8) :: allcld_liq(state%psetcols,pver) ! All-cloud liquid
-
- real(r8), pointer :: cmeliq(:,:)
-
- real(r8), pointer :: cld(:,:) ! Total cloud fraction
- real(r8), pointer :: concld(:,:) ! Convective cloud fraction
- real(r8), pointer :: iciwpst(:,:) ! Stratiform in-cloud ice water path for radiation
- real(r8), pointer :: iclwpst(:,:) ! Stratiform in-cloud liquid water path for radiation
- real(r8), pointer :: cldfsnow(:,:) ! Cloud fraction for liquid+snow
- real(r8), pointer :: icswp(:,:) ! In-cloud snow water path
-
- real(r8) :: icimrst(state%psetcols,pver) ! In stratus ice mixing ratio
- real(r8) :: icwmrst(state%psetcols,pver) ! In stratus water mixing ratio
- real(r8) :: icinc(state%psetcols,pver) ! In cloud ice number conc
- real(r8) :: icwnc(state%psetcols,pver) ! In cloud water number conc
-
- real(r8) :: iclwpi(state%psetcols) ! Vertically-integrated in-cloud Liquid WP before microphysics
- real(r8) :: iciwpi(state%psetcols) ! Vertically-integrated in-cloud Ice WP before microphysics
-
- ! Averaging arrays for effective radius and number....
- real(r8) :: efiout_grid(pcols,pver)
- real(r8) :: efcout_grid(pcols,pver)
- real(r8) :: ncout_grid(pcols,pver)
- real(r8) :: niout_grid(pcols,pver)
- real(r8) :: freqi_grid(pcols,pver)
- real(r8) :: freql_grid(pcols,pver)
-
- real(r8) :: cdnumc_grid(pcols) ! Vertically-integrated droplet concentration
- real(r8) :: icecldf_grid_out(pcols,pver) ! Ice cloud fraction
- real(r8) :: liqcldf_grid_out(pcols,pver) ! Liquid cloud fraction (combined into cloud)
- real(r8) :: icimrst_grid_out(pcols,pver) ! In stratus ice mixing ratio
- real(r8) :: icwmrst_grid_out(pcols,pver) ! In stratus water mixing ratio
-
- ! Average cloud top radius & number
- real(r8) :: ctrel_grid(pcols)
- real(r8) :: ctrei_grid(pcols)
- real(r8) :: ctnl_grid(pcols)
- real(r8) :: ctni_grid(pcols)
- real(r8) :: fcti_grid(pcols)
- real(r8) :: fctl_grid(pcols)
-
- real(r8) :: ftem_grid(pcols,pver)
-
- ! Variables for precip efficiency calculation
- real(r8) :: minlwp ! LWP threshold
-
- real(r8), pointer, dimension(:) :: acprecl_grid ! accumulated precip across timesteps
- real(r8), pointer, dimension(:) :: acgcme_grid ! accumulated condensation across timesteps
- integer, pointer, dimension(:) :: acnum_grid ! counter for # timesteps accumulated
-
- ! Variables for liquid water path and column condensation
- real(r8) :: tgliqwp_grid(pcols) ! column liquid
- real(r8) :: tgcmeliq_grid(pcols) ! column condensation rate (units)
-
- real(r8) :: pe_grid(pcols) ! precip efficiency for output
- real(r8) :: pefrac_grid(pcols) ! fraction of time precip efficiency is written out
- real(r8) :: tpr_grid(pcols) ! average accumulated precipitation rate in pe calculation
-
- ! variables for autoconversion and accretion vertical averages
- real(r8) :: vprco_grid(pcols) ! vertical average autoconversion
- real(r8) :: vprao_grid(pcols) ! vertical average accretion
- real(r8) :: racau_grid(pcols) ! ratio of vertical averages
- integer :: cnt_grid(pcols) ! counters
- logical :: lq(pcnst)
-
- real(r8) :: qc(state%psetcols,pver) ! cloud water mixing ratio (kg/kg)
- real(r8) :: qi(state%psetcols,pver) ! cloud ice mixing ratio (kg/kg)
- real(r8) :: nc(state%psetcols,pver) ! cloud water number conc (1/kg)
- real(r8) :: ni(state%psetcols,pver) ! cloud ice number conc (1/kg)
-
- real(r8) :: icimrst_grid(pcols,pver) ! stratus ice mixing ratio - on grid
- real(r8) :: icwmrst_grid(pcols,pver) ! stratus water mixing ratio - on grid
-
- real(r8),pointer :: lambdac_grid(:,:)
- real(r8),pointer :: mu_grid(:,:)
- real(r8),pointer :: rel_grid(:,:)
- real(r8),pointer :: rei_grid(:,:)
- real(r8),pointer :: dei_grid(:,:)
- real(r8),pointer :: des_grid(:,:)
- real(r8),pointer :: iclwpst_grid(:,:)
-
- real(r8) :: rho_grid(pcols,pver)
- real(r8) :: liqcldf_grid(pcols,pver)
- real(r8) :: qsout_grid(pcols,pver)
- real(r8) :: ncic_grid(pcols,pver)
- real(r8) :: niic_grid(pcols,pver)
- real(r8) :: rel_fn_grid(pcols,pver) ! Ice effective drop size at fixed number (indirect effect) (microns) - on grid
- real(r8) :: qrout_grid(pcols,pver)
- real(r8) :: drout2_grid(pcols,pver)
- real(r8) :: dsout2_grid(pcols,pver)
- real(r8) :: nsout_grid(pcols,pver)
- real(r8) :: nrout_grid(pcols,pver)
- real(r8) :: reff_rain_grid(pcols,pver)
- real(r8) :: reff_snow_grid(pcols,pver)
- real(r8) :: cld_grid(pcols,pver)
- real(r8) :: pdel_grid(pcols,pver)
- real(r8) :: prco_grid(pcols,pver)
- real(r8) :: prao_grid(pcols,pver)
- real(r8) :: q_ixnumliq_grid(pcols,pver)
- real(r8) :: icecldf_grid(pcols,pver)
- real(r8) :: icwnc_grid(pcols,pver)
- real(r8) :: icinc_grid(pcols,pver)
- real(r8) :: qcreso_grid(pcols,pver)
- real(r8) :: melto_grid(pcols,pver)
- real(r8) :: mnuccco_grid(pcols,pver)
- real(r8) :: mnuccto_grid(pcols,pver)
- real(r8) :: bergo_grid(pcols,pver)
- real(r8) :: homoo_grid(pcols,pver)
- real(r8) :: msacwio_grid(pcols,pver)
- real(r8) :: psacwso_grid(pcols,pver)
- real(r8) :: bergso_grid(pcols,pver)
- real(r8) :: cmeiout_grid(pcols,pver)
- real(r8) :: qireso_grid(pcols,pver)
- real(r8) :: prcio_grid(pcols,pver)
- real(r8) :: praio_grid(pcols,pver)
-
- real(r8),pointer :: cmeliq_grid(:,:)
-
- real(r8),pointer :: prec_str_grid(:)
- real(r8),pointer :: snow_str_grid(:)
- real(r8),pointer :: prec_pcw_grid(:)
- real(r8),pointer :: snow_pcw_grid(:)
- real(r8),pointer :: prec_sed_grid(:)
- real(r8),pointer :: snow_sed_grid(:)
- real(r8),pointer :: cldo_grid(:,:)
- real(r8),pointer :: nevapr_grid(:,:)
- real(r8),pointer :: prain_grid(:,:)
- real(r8),pointer :: mgflxprc_grid(:,:)
- real(r8),pointer :: mgflxsnw_grid(:,:)
- real(r8),pointer :: mgmrprc_grid(:,:)
- real(r8),pointer :: mgmrsnw_grid(:,:)
- real(r8),pointer :: cvreffliq_grid(:,:)
- real(r8),pointer :: cvreffice_grid(:,:)
- real(r8),pointer :: rate1ord_cw2pr_st_grid(:,:)
- real(r8),pointer :: wsedl_grid(:,:)
- real(r8),pointer :: CC_t_grid(:,:)
- real(r8),pointer :: CC_qv_grid(:,:)
- real(r8),pointer :: CC_ql_grid(:,:)
- real(r8),pointer :: CC_qi_grid(:,:)
- real(r8),pointer :: CC_nl_grid(:,:)
- real(r8),pointer :: CC_ni_grid(:,:)
- real(r8),pointer :: CC_qlst_grid(:,:)
- real(r8),pointer :: qme_grid(:,:)
- real(r8),pointer :: iciwpst_grid(:,:)
- real(r8),pointer :: icswp_grid(:,:)
- real(r8),pointer :: ast_grid(:,:)
- real(r8),pointer :: cldfsnow_grid(:,:)
-
- real(r8),pointer :: qrout_grid_ptr(:,:)
- real(r8),pointer :: qsout_grid_ptr(:,:)
- real(r8),pointer :: nrout_grid_ptr(:,:)
- real(r8),pointer :: nsout_grid_ptr(:,:)
-
-
- integer :: nlev ! number of levels where cloud physics is done
- integer :: mgncol ! size of mgcols
- integer :: col_type ! Flag to store whether accessing grid or sub-columns in pbuf_get_field
- integer, allocatable :: mgcols(:) ! Columns with microphysics performed
-
- logical :: use_subcol_microp
-
- character(128) :: errstring ! return status (non-blank for error return)
-
- ! For rrtmg optics specified distribution.
- real(r8), parameter :: dcon = 25.e-6_r8 ! Convective size distribution effective radius (meters)
- real(r8), parameter :: mucon = 5.3_r8 ! Convective size distribution shape parameter
- real(r8), parameter :: deicon = 50._r8 ! Convective ice effective diameter (meters)
-
- !-------------------------------------------------------------------------------
-
- ! Find the number of levels used in the microphysics.
- nlev = pver - top_lev + 1
-
- lchnk = state%lchnk
- ncol = state%ncol
- psetcols = state%psetcols
- ngrdcol = state%ngrdcol
-
- itim_old = pbuf_old_tim_idx()
-
- call phys_getopts(use_subcol_microp_out = use_subcol_microp)
-
- ! Set the col_type flag to grid or subcolumn dependent on the value of use_subcol_microp
- call pbuf_col_type_index(use_subcol_microp, col_type=col_type)
-
- !-----------------------
- ! These physics buffer fields are read only and not set in this parameterization
- ! If these fields do not have subcolumn data, copy the grid to the subcolumn if subcolumns is turned on
- ! If subcolumns is not turned on, then these fields will be grid data
-
- call pbuf_get_field(pbuf, naai_idx, naai, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, naai_hom_idx, naai_hom, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, npccn_idx, npccn, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, rndst_idx, rndst, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, nacon_idx, nacon, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, tnd_qsnow_idx, tnd_qsnow, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, tnd_nsnow_idx, tnd_nsnow, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, re_ice_idx, re_ice, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, relvar_idx, relvar, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, accre_enhan_idx, accre_enhan, col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, cmeliq_idx, cmeliq, col_type=col_type, copy_if_needed=use_subcol_microp)
-
- call pbuf_get_field(pbuf, cld_idx, cld, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), &
- col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, concld_idx, concld, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), &
- col_type=col_type, copy_if_needed=use_subcol_microp)
- call pbuf_get_field(pbuf, ast_idx, ast, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), &
- col_type=col_type, copy_if_needed=use_subcol_microp)
-
- !-----------------------
- ! These physics buffer fields are calculated and set in this parameterization
- ! If subcolumns is turned on, then these fields will be calculated on a subcolumn grid, otherwise they will be a normal grid
-
- call pbuf_get_field(pbuf, prec_str_idx, prec_str, col_type=col_type)
- call pbuf_get_field(pbuf, snow_str_idx, snow_str, col_type=col_type)
- call pbuf_get_field(pbuf, prec_pcw_idx, prec_pcw, col_type=col_type)
- call pbuf_get_field(pbuf, snow_pcw_idx, snow_pcw, col_type=col_type)
- call pbuf_get_field(pbuf, prec_sed_idx, prec_sed, col_type=col_type)
- call pbuf_get_field(pbuf, snow_sed_idx, snow_sed, col_type=col_type)
- call pbuf_get_field(pbuf, nevapr_idx, nevapr, col_type=col_type)
- call pbuf_get_field(pbuf, prain_idx, prain, col_type=col_type)
- call pbuf_get_field(pbuf, dei_idx, dei, col_type=col_type)
- call pbuf_get_field(pbuf, mu_idx, mu, col_type=col_type)
- call pbuf_get_field(pbuf, lambdac_idx, lambdac, col_type=col_type)
- call pbuf_get_field(pbuf, des_idx, des, col_type=col_type)
- call pbuf_get_field(pbuf, ls_flxprc_idx, mgflxprc, col_type=col_type)
- call pbuf_get_field(pbuf, ls_flxsnw_idx, mgflxsnw, col_type=col_type)
- call pbuf_get_field(pbuf, ls_mrprc_idx, mgmrprc, col_type=col_type)
- call pbuf_get_field(pbuf, ls_mrsnw_idx, mgmrsnw, col_type=col_type)
- call pbuf_get_field(pbuf, cv_reffliq_idx, cvreffliq, col_type=col_type)
- call pbuf_get_field(pbuf, cv_reffice_idx, cvreffice, col_type=col_type)
- call pbuf_get_field(pbuf, iciwpst_idx, iciwpst, col_type=col_type)
- call pbuf_get_field(pbuf, iclwpst_idx, iclwpst, col_type=col_type)
- call pbuf_get_field(pbuf, icswp_idx, icswp, col_type=col_type)
- call pbuf_get_field(pbuf, rel_idx, rel, col_type=col_type)
- call pbuf_get_field(pbuf, rei_idx, rei, col_type=col_type)
- call pbuf_get_field(pbuf, wsedl_idx, wsedl, col_type=col_type)
- call pbuf_get_field(pbuf, qme_idx, qme, col_type=col_type)
-
- call pbuf_get_field(pbuf, cldo_idx, cldo, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
- call pbuf_get_field(pbuf, cldfsnow_idx, cldfsnow, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
- call pbuf_get_field(pbuf, cc_t_idx, CC_t, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type )
- call pbuf_get_field(pbuf, cc_qv_idx, CC_qv, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type )
- call pbuf_get_field(pbuf, cc_ql_idx, CC_ql, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type )
- call pbuf_get_field(pbuf, cc_qi_idx, CC_qi, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type )
- call pbuf_get_field(pbuf, cc_nl_idx, CC_nl, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type )
- call pbuf_get_field(pbuf, cc_ni_idx, CC_ni, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type )
- call pbuf_get_field(pbuf, cc_qlst_idx, CC_qlst, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type )
-
- if (rate1_cw2pr_st_idx > 0) then
- call pbuf_get_field(pbuf, rate1_cw2pr_st_idx, rate1ord_cw2pr_st, col_type=col_type)
- end if
-
- if (qrain_idx > 0) call pbuf_get_field(pbuf, qrain_idx, qrout_grid_ptr)
- if (qsnow_idx > 0) call pbuf_get_field(pbuf, qsnow_idx, qsout_grid_ptr)
- if (nrain_idx > 0) call pbuf_get_field(pbuf, nrain_idx, nrout_grid_ptr)
- if (nsnow_idx > 0) call pbuf_get_field(pbuf, nsnow_idx, nsout_grid_ptr)
-
- !-----------------------
- ! If subcolumns is turned on, all calculated fields which are on subcolumns
- ! need to be retrieved on the grid as well for storing averaged values
-
- if (use_subcol_microp) then
- call pbuf_get_field(pbuf, prec_str_idx, prec_str_grid)
- call pbuf_get_field(pbuf, snow_str_idx, snow_str_grid)
- call pbuf_get_field(pbuf, prec_pcw_idx, prec_pcw_grid)
- call pbuf_get_field(pbuf, snow_pcw_idx, snow_pcw_grid)
- call pbuf_get_field(pbuf, prec_sed_idx, prec_sed_grid)
- call pbuf_get_field(pbuf, snow_sed_idx, snow_sed_grid)
- call pbuf_get_field(pbuf, nevapr_idx, nevapr_grid)
- call pbuf_get_field(pbuf, prain_idx, prain_grid)
- call pbuf_get_field(pbuf, dei_idx, dei_grid)
- call pbuf_get_field(pbuf, mu_idx, mu_grid)
- call pbuf_get_field(pbuf, lambdac_idx, lambdac_grid)
- call pbuf_get_field(pbuf, des_idx, des_grid)
- call pbuf_get_field(pbuf, ls_flxprc_idx, mgflxprc_grid)
- call pbuf_get_field(pbuf, ls_flxsnw_idx, mgflxsnw_grid)
- call pbuf_get_field(pbuf, ls_mrprc_idx, mgmrprc_grid)
- call pbuf_get_field(pbuf, ls_mrsnw_idx, mgmrsnw_grid)
- call pbuf_get_field(pbuf, cv_reffliq_idx, cvreffliq_grid)
- call pbuf_get_field(pbuf, cv_reffice_idx, cvreffice_grid)
- call pbuf_get_field(pbuf, iciwpst_idx, iciwpst_grid)
- call pbuf_get_field(pbuf, iclwpst_idx, iclwpst_grid)
- call pbuf_get_field(pbuf, icswp_idx, icswp_grid)
- call pbuf_get_field(pbuf, rel_idx, rel_grid)
- call pbuf_get_field(pbuf, rei_idx, rei_grid)
- call pbuf_get_field(pbuf, wsedl_idx, wsedl_grid)
- call pbuf_get_field(pbuf, qme_idx, qme_grid)
-
- call pbuf_get_field(pbuf, cldo_idx, cldo_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cldfsnow_idx, cldfsnow_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cc_t_idx, CC_t_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cc_qv_idx, CC_qv_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cc_ql_idx, CC_ql_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cc_qi_idx, CC_qi_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cc_nl_idx, CC_nl_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cc_ni_idx, CC_ni_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
- call pbuf_get_field(pbuf, cc_qlst_idx, CC_qlst_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
-
- if (rate1_cw2pr_st_idx > 0) then
- call pbuf_get_field(pbuf, rate1_cw2pr_st_idx, rate1ord_cw2pr_st_grid)
- end if
-
- end if
-
- !-----------------------
- ! These are only on the grid regardless of whether subcolumns are turned on or not
- call pbuf_get_field(pbuf, ls_reffrain_idx, mgreffrain_grid)
- call pbuf_get_field(pbuf, ls_reffsnow_idx, mgreffsnow_grid)
- call pbuf_get_field(pbuf, acpr_idx, acprecl_grid)
- call pbuf_get_field(pbuf, acgcme_idx, acgcme_grid)
- call pbuf_get_field(pbuf, acnum_idx, acnum_grid)
- call pbuf_get_field(pbuf, cmeliq_idx, cmeliq_grid)
- call pbuf_get_field(pbuf, ast_idx, ast_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
-
-
- !-------------------------------------------------------------------------------------
- ! Microphysics assumes 'liquid stratus frac = ice stratus frac
- ! = max( liquid stratus frac, ice stratus frac )'.
- alst_mic => ast
- aist_mic => ast
-
- ! Output initial in-cloud LWP (before microphysics)
-
- iclwpi = 0._r8
- iciwpi = 0._r8
-
- do i = 1, ncol
- do k = top_lev, pver
- iclwpi(i) = iclwpi(i) + &
- min(state%q(i,k,ixcldliq) / max(mincld,ast(i,k)),0.005_r8) &
- * state%pdel(i,k) / gravit
- iciwpi(i) = iciwpi(i) + &
- min(state%q(i,k,ixcldice) / max(mincld,ast(i,k)),0.005_r8) &
- * state%pdel(i,k) / gravit
- end do
- end do
-
- cldo(:ncol,top_lev:pver)=ast(:ncol,top_lev:pver)
-
- ! Initialize local state from input.
- call physics_state_copy(state, state_loc)
-
- ! Initialize ptend for output.
- lq = .false.
- lq(1) = .true.
- lq(ixcldliq) = .true.
- lq(ixcldice) = .true.
- lq(ixnumliq) = .true.
- lq(ixnumice) = .true.
-
- ! the name 'cldwat' triggers special tests on cldliq
- ! and cldice in physics_update
- call physics_ptend_init(ptend, psetcols, "cldwat", ls=.true., lq=lq)
-
- select case (micro_mg_version)
- case (1)
- select case (micro_mg_sub_version)
- case (0)
-
- qc = state_loc%q(:,:,ixcldliq)
- qi = state_loc%q(:,:,ixcldice)
- nc = state_loc%q(:,:,ixnumliq)
- ni = state_loc%q(:,:,ixnumice)
-
- call micro_mg_tend1_0( &
- microp_uniform, psetcols, pver, ncol, top_lev, dtime, &
- state_loc%t, state_loc%q(:,:,1), qc, qi, nc, &
- ni, state_loc%pmid, state_loc%pdel, ast, alst_mic,&
- relvar, accre_enhan, &
- aist_mic, rate1cld, naai, npccn, &
- rndst, nacon, tlat, qvlat, qcten, &
- qiten, ncten, niten, rel, rel_fn, &
- rei, prect, preci, nevapr, evapsnow, &
- prain, prodsnow, cmeice, dei, mu, &
- lambdac, qsout, des, rflx, sflx, &
- qrout, reff_rain, reff_snow, qcsevap, qisevap, &
- qvres, cmeiout, vtrmc, vtrmi, qcsedten, &
- qisedten, prao, prco, mnuccco, mnuccto, &
- msacwio, psacwso, bergso, bergo, melto, &
- homoo, qcreso, prcio, praio, qireso, &
- mnuccro, pracso, meltsdt, frzrdt, mnuccdo, &
- nrout, nsout, refl, arefl, areflz, &
- frefl, csrfl, acsrfl, fcsrfl, rercld, &
- ncai, ncal, qrout2, qsout2, nrout2, &
- nsout2, drout2, dsout2, freqs, freqr, &
- nfice, do_cldice, tnd_qsnow, &
- tnd_nsnow, re_ice, errstring)
-
-
- case (5)
-
- call micro_mg_get_cols1_5(ncol, nlev, top_lev, state%q(:,:,ixcldliq), &
- state%q(:,:,ixcldice), mgncol, mgcols)
-
- call micro_mg_tend1_5( &
- mgncol, mgcols, nlev, top_lev, dtime, &
- state_loc%t, state_loc%q(:,:,1), &
- state_loc%q(:,:,ixcldliq), state_loc%q(:,:,ixcldice), &
- state_loc%q(:,:,ixnumliq), state_loc%q(:,:,ixnumice), &
- relvar, accre_enhan, &
- state_loc%pmid, state_loc%pdel, state_loc%pint, &
- ast, alst_mic, aist_mic, &
- rate1cld, naai, npccn, rndst, nacon, &
- tlat, qvlat, qcten, qiten, ncten, niten, &
- rel, rel_fn, rei, prect, preci, &
- nevapr, evapsnow, prain, prodsnow, cmeice, dei, &
- mu, lambdac, qsout, des, rflx, sflx, &
- qrout, reff_rain, reff_snow, &
- qcsevap, qisevap, qvres, cmeiout, vtrmc, vtrmi, &
- qcsedten, qisedten, prao, prco, mnuccco, mnuccto, &
- msacwio, psacwso, bergso, bergo, melto, homoo, &
- qcreso, prcio, praio, qireso, &
- mnuccro, pracso, meltsdt, frzrdt, mnuccdo, &
- nrout, nsout, refl, arefl, areflz, frefl, &
- csrfl, acsrfl, fcsrfl, rercld, &
- ncai, ncal, qrout2, qsout2, nrout2, nsout2, &
- drout2, dsout2, freqs, freqr, nfice, &
- tnd_qsnow, tnd_nsnow, re_ice, &
- errstring)
-
- call handle_errmsg(errstring, subname="micro_mg_tend1_5")
- end select
- end select
-
- call handle_errmsg(errstring, subname="micro_mg_tend")
-
- call physics_ptend_init(ptend_loc, psetcols, "micro_mg", ls=.true., lq=lq)
-
- ! Set local tendency.
- ptend_loc%s(:ncol,top_lev:pver) = tlat(:ncol,top_lev:pver)
- ptend_loc%q(:ncol,top_lev:pver,1) = qvlat(:ncol,top_lev:pver)
- ptend_loc%q(:ncol,top_lev:pver,ixcldliq) = qcten(:ncol,top_lev:pver)
- ptend_loc%q(:ncol,top_lev:pver,ixcldice) = qiten(:ncol,top_lev:pver)
- ptend_loc%q(:ncol,top_lev:pver,ixnumliq) = ncten(:ncol,top_lev:pver)
- ptend_loc%q(:ncol,top_lev:pver,ixnumice) = niten(:ncol,top_lev:pver)
-
- ! Sum into overall ptend
- call physics_ptend_sum(ptend_loc, ptend, ncol)
-
- ! Update local state
- call physics_update(state_loc, ptend_loc, dtime)
-
- ! Check to make sure that the microphysics code is respecting the flags that control
- ! whether MG should be prognosing cloud ice and cloud liquid or not.
- if (.not. do_cldice) then
- if (any(ptend%q(:ncol,top_lev:pver,ixcldice) /= 0.0_r8)) &
- call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud ice,"// &
- " but micro_mg_tend has ice mass tendencies.")
- if (any(ptend%q(:ncol,top_lev:pver,ixnumice) /= 0.0_r8)) &
- call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud ice,"// &
- " but micro_mg_tend has ice number tendencies.")
- end if
- if (.not. do_cldliq) then
- if (any(ptend%q(:ncol,top_lev:pver,ixcldliq) /= 0.0_r8)) &
- call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud liquid,"// &
- " but micro_mg_tend has liquid mass tendencies.")
- if (any(ptend%q(:ncol,top_lev:pver,ixnumliq) /= 0.0_r8)) &
- call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud liquid,"// &
- " but micro_mg_tend has liquid number tendencies.")
- end if
-
-
- mnuccdohet = 0._r8
- do k=top_lev,pver
- do i=1,ncol
- if (naai(i,k) > 0._r8) then
- mnuccdohet(i,k) = mnuccdo(i,k) - (naai_hom(i,k)/naai(i,k))*mnuccdo(i,k)
- end if
- end do
- end do
-
- mgflxprc(:ncol,top_lev:pverp) = rflx(:ncol,top_lev:pverp) + sflx(:ncol,top_lev:pverp)
- mgflxsnw(:ncol,top_lev:pverp) = sflx(:ncol,top_lev:pverp)
-
- mgmrprc(:ncol,top_lev:pver) = qrout(:ncol,top_lev:pver) + qsout(:ncol,top_lev:pver)
- mgmrsnw(:ncol,top_lev:pver) = qsout(:ncol,top_lev:pver)
-
- !! calculate effective radius of convective liquid and ice using dcon and deicon (not used by code, not useful for COSP)
- !! hard-coded as average of hard-coded values used for deep/shallow convective detrainment (near line 1502/1505)
- cvreffliq(:ncol,top_lev:pver) = 9.0_r8
- cvreffice(:ncol,top_lev:pver) = 37.0_r8
-
-
- ! Reassign rate1 if modal aerosols
- if (rate1_cw2pr_st_idx > 0) then
- rate1ord_cw2pr_st(:ncol,top_lev:pver) = rate1cld(:ncol,top_lev:pver)
- end if
-
- ! Sedimentation velocity for liquid stratus cloud droplet
- wsedl(:ncol,top_lev:pver) = vtrmc(:ncol,top_lev:pver)
-
- ! Microphysical tendencies for use in the macrophysics at the next time step
- CC_T(:ncol,top_lev:pver) = tlat(:ncol,top_lev:pver)/cpair
- CC_qv(:ncol,top_lev:pver) = qvlat(:ncol,top_lev:pver)
- CC_ql(:ncol,top_lev:pver) = qcten(:ncol,top_lev:pver)
- CC_qi(:ncol,top_lev:pver) = qiten(:ncol,top_lev:pver)
- CC_nl(:ncol,top_lev:pver) = ncten(:ncol,top_lev:pver)
- CC_ni(:ncol,top_lev:pver) = niten(:ncol,top_lev:pver)
- CC_qlst(:ncol,top_lev:pver) = qcten(:ncol,top_lev:pver)/max(0.01_r8,alst_mic(:ncol,top_lev:pver))
-
- ! Net micro_mg_cam condensation rate
- qme(:ncol,top_lev:pver) = cmeliq(:ncol,top_lev:pver) + cmeiout(:ncol,top_lev:pver)
-
- ! For precip, accumulate only total precip in prec_pcw and snow_pcw variables.
- ! Other precip output variables are set to 0
- prec_pcw(:ncol) = prect(:ncol)
- snow_pcw(:ncol) = preci(:ncol)
- prec_sed(:ncol) = 0._r8
- snow_sed(:ncol) = 0._r8
- prec_str(:ncol) = prec_pcw(:ncol) + prec_sed(:ncol)
- snow_str(:ncol) = snow_pcw(:ncol) + snow_sed(:ncol)
-
- icecldf(:ncol,top_lev:pver) = ast(:ncol,top_lev:pver)
- liqcldf(:ncol,top_lev:pver) = ast(:ncol,top_lev:pver)
-
-
- ! ------------------------------------------------------------ !
- ! Compute in cloud ice and liquid mixing ratios !
- ! Note that 'iclwp, iciwp' are used for radiation computation. !
- ! ------------------------------------------------------------ !
-
-
- icinc = 0._r8
- icwnc = 0._r8
- iciwpst = 0._r8
- iclwpst = 0._r8
- icswp = 0._r8
- cldfsnow = 0._r8
-
- do k = top_lev, pver
- do i = 1, ncol
- ! Limits for in-cloud mixing ratios consistent with MG microphysics
- ! in-cloud mixing ratio maximum limit of 0.005 kg/kg
- icimrst(i,k) = min( state_loc%q(i,k,ixcldice) / max(mincld,icecldf(i,k)),0.005_r8 )
- icwmrst(i,k) = min( state_loc%q(i,k,ixcldliq) / max(mincld,liqcldf(i,k)),0.005_r8 )
- icinc(i,k) = state_loc%q(i,k,ixnumice) / max(mincld,icecldf(i,k)) * &
- state_loc%pmid(i,k) / (287.15_r8*state_loc%t(i,k))
- icwnc(i,k) = state_loc%q(i,k,ixnumliq) / max(mincld,liqcldf(i,k)) * &
- state_loc%pmid(i,k) / (287.15_r8*state_loc%t(i,k))
- ! Calculate micro_mg_cam cloud water paths in each layer
- ! Note: uses stratiform cloud fraction!
- iciwpst(i,k) = min(state_loc%q(i,k,ixcldice)/max(mincld,ast(i,k)),0.005_r8) * state_loc%pdel(i,k) / gravit
- iclwpst(i,k) = min(state_loc%q(i,k,ixcldliq)/max(mincld,ast(i,k)),0.005_r8) * state_loc%pdel(i,k) / gravit
-
- ! ------------------------------ !
- ! Adjust cloud fraction for snow !
- ! ------------------------------ !
- cldfsnow(i,k) = cld(i,k)
- ! If cloud and only ice ( no convective cloud or ice ), then set to 0.
- if( ( cldfsnow(i,k) .gt. 1.e-4_r8 ) .and. &
- ( concld(i,k) .lt. 1.e-4_r8 ) .and. &
- ( state_loc%q(i,k,ixcldliq) .lt. 1.e-10_r8 ) ) then
- cldfsnow(i,k) = 0._r8
- end if
- ! If no cloud and snow, then set to 0.25
- if( ( cldfsnow(i,k) .lt. 1.e-4_r8 ) .and. ( qsout(i,k) .gt. 1.e-6_r8 ) ) then
- cldfsnow(i,k) = 0.25_r8
- end if
- ! Calculate in-cloud snow water path
- icswp(i,k) = qsout(i,k) / max( mincld, cldfsnow(i,k) ) * state_loc%pdel(i,k) / gravit
- end do
- end do
-
-
- ! ------------------------------------------------------ !
- ! ------------------------------------------------------ !
- ! All code from here to the end is on grid columns only !
- ! ------------------------------------------------------ !
- ! ------------------------------------------------------ !
-
- ! Average the fields which are needed later in this paramterization to be on the grid
- if (use_subcol_microp) then
- call subcol_field_avg(lambdac, ngrdcol, lchnk, lambdac_grid)
- call subcol_field_avg(mu, ngrdcol, lchnk, mu_grid)
- call subcol_field_avg(rel, ngrdcol, lchnk, rel_grid)
- call subcol_field_avg(rei, ngrdcol, lchnk, rei_grid)
- call subcol_field_avg(dei, ngrdcol, lchnk, dei_grid)
- call subcol_field_avg(prec_str, ngrdcol, lchnk, prec_str_grid)
- call subcol_field_avg(iclwpst, ngrdcol, lchnk, iclwpst_grid)
- call subcol_field_avg(cvreffliq, ngrdcol, lchnk, cvreffliq_grid)
- call subcol_field_avg(cvreffice, ngrdcol, lchnk, cvreffice_grid)
- call subcol_field_avg(mgflxprc, ngrdcol, lchnk, mgflxprc_grid)
- call subcol_field_avg(mgflxsnw, ngrdcol, lchnk, mgflxsnw_grid)
- call subcol_field_avg(qme, ngrdcol, lchnk, qme_grid)
- call subcol_field_avg(nevapr, ngrdcol, lchnk, nevapr_grid)
- call subcol_field_avg(prain, ngrdcol, lchnk, prain_grid)
-
- ! Average fields which are not in pbuf
- call subcol_field_avg(qrout, ngrdcol, lchnk, qrout_grid)
- call subcol_field_avg(qsout, ngrdcol, lchnk, qsout_grid)
- call subcol_field_avg(nsout, ngrdcol, lchnk, nsout_grid)
- call subcol_field_avg(nrout, ngrdcol, lchnk, nrout_grid)
- call subcol_field_avg(cld, ngrdcol, lchnk, cld_grid)
- call subcol_field_avg(qcreso, ngrdcol, lchnk, qcreso_grid)
- call subcol_field_avg(melto, ngrdcol, lchnk, melto_grid)
- call subcol_field_avg(mnuccco, ngrdcol, lchnk, mnuccco_grid)
- call subcol_field_avg(mnuccto, ngrdcol, lchnk, mnuccto_grid)
- call subcol_field_avg(bergo, ngrdcol, lchnk, bergo_grid)
- call subcol_field_avg(homoo, ngrdcol, lchnk, homoo_grid)
- call subcol_field_avg(msacwio, ngrdcol, lchnk, msacwio_grid)
- call subcol_field_avg(psacwso, ngrdcol, lchnk, psacwso_grid)
- call subcol_field_avg(bergso, ngrdcol, lchnk, bergso_grid)
- call subcol_field_avg(cmeiout, ngrdcol, lchnk, cmeiout_grid)
- call subcol_field_avg(qireso, ngrdcol, lchnk, qireso_grid)
- call subcol_field_avg(prcio, ngrdcol, lchnk, prcio_grid)
- call subcol_field_avg(praio, ngrdcol, lchnk, praio_grid)
- call subcol_field_avg(icwmrst, ngrdcol, lchnk, icwmrst_grid)
- call subcol_field_avg(icimrst, ngrdcol, lchnk, icimrst_grid)
- call subcol_field_avg(liqcldf, ngrdcol, lchnk, liqcldf_grid)
- call subcol_field_avg(icecldf, ngrdcol, lchnk, icecldf_grid)
- call subcol_field_avg(icwnc, ngrdcol, lchnk, icwnc_grid)
- call subcol_field_avg(icinc, ngrdcol, lchnk, icinc_grid)
- call subcol_field_avg(state_loc%pdel, ngrdcol, lchnk, pdel_grid)
- call subcol_field_avg(state_loc%q(:,:,ixnumliq), ngrdcol, lchnk, q_ixnumliq_grid)
- call subcol_field_avg(prao, ngrdcol, lchnk, prao_grid)
- call subcol_field_avg(prco, ngrdcol, lchnk, prco_grid)
-
- else ! fields already on grids, so just assign
- lambdac_grid => lambdac
- mu_grid => mu
- rel_grid => rel
- rei_grid => rei
- dei_grid => dei
- prec_str_grid => prec_str
- iclwpst_grid => iclwpst
- cvreffliq_grid => cvreffliq
- cvreffice_grid => cvreffice
- mgflxprc_grid => mgflxprc
- mgflxsnw_grid => mgflxsnw
- qme_grid => qme
- nevapr_grid => nevapr
- prain_grid => prain
-
- ! This pbuf field needs to be assigned. There is no corresponding subcol_field_avg
- ! as it is reset before it is used and would be a needless calculation
- des_grid => des
-
- qrout_grid = qrout
- qsout_grid = qsout
- nsout_grid = nsout
- nrout_grid = nrout
- cld_grid = cld
- qcreso_grid = qcreso
- melto_grid = melto
- mnuccco_grid = mnuccco
- mnuccto_grid = mnuccto
- bergo_grid = bergo
- homoo_grid = homoo
- msacwio_grid = msacwio
- psacwso_grid = psacwso
- bergso_grid = bergso
- cmeiout_grid = cmeiout
- qireso_grid = qireso
- prcio_grid = prcio
- praio_grid = praio
- icwmrst_grid = icwmrst
- icimrst_grid = icimrst
- liqcldf_grid = liqcldf
- icecldf_grid = icecldf
- icwnc_grid = icwnc
- icinc_grid = icinc
- pdel_grid = state_loc%pdel
- q_ixnumliq_grid = state_loc%q(:,:,ixnumliq)
- prao_grid = prao
- prco_grid = prco
-
- end if
-
- ! If on subcolumns, average the rest of the pbuf fields which were modified on subcolumns but are not used further in
- ! this parameterization (no need to assign in the non-subcolumn case -- the else step)
- if (use_subcol_microp) then
- call subcol_field_avg(snow_str, ngrdcol, lchnk, snow_str_grid)
- call subcol_field_avg(prec_pcw, ngrdcol, lchnk, prec_pcw_grid)
- call subcol_field_avg(snow_pcw, ngrdcol, lchnk, snow_pcw_grid)
- call subcol_field_avg(prec_sed, ngrdcol, lchnk, prec_sed_grid)
- call subcol_field_avg(snow_sed, ngrdcol, lchnk, snow_sed_grid)
- call subcol_field_avg(cldo, ngrdcol, lchnk, cldo_grid)
- call subcol_field_avg(mgmrprc, ngrdcol, lchnk, mgmrprc_grid)
- call subcol_field_avg(mgmrsnw, ngrdcol, lchnk, mgmrsnw_grid)
- call subcol_field_avg(wsedl, ngrdcol, lchnk, wsedl_grid)
- call subcol_field_avg(cc_t, ngrdcol, lchnk, cc_t_grid)
- call subcol_field_avg(cc_qv, ngrdcol, lchnk, cc_qv_grid)
- call subcol_field_avg(cc_ql, ngrdcol, lchnk, cc_ql_grid)
- call subcol_field_avg(cc_qi, ngrdcol, lchnk, cc_qi_grid)
- call subcol_field_avg(cc_nl, ngrdcol, lchnk, cc_nl_grid)
- call subcol_field_avg(cc_ni, ngrdcol, lchnk, cc_ni_grid)
- call subcol_field_avg(cc_qlst, ngrdcol, lchnk, cc_qlst_grid)
- call subcol_field_avg(iciwpst, ngrdcol, lchnk, iciwpst_grid)
- call subcol_field_avg(icswp, ngrdcol, lchnk, icswp_grid)
- call subcol_field_avg(cldfsnow, ngrdcol, lchnk, cldfsnow_grid)
-
- if (rate1_cw2pr_st_idx > 0) then
- call subcol_field_avg(rate1ord_cw2pr_st, ngrdcol, lchnk, rate1ord_cw2pr_st_grid)
- end if
-
- end if
-
- ! ------------------------------------- !
- ! Size distribution calculation !
- ! ------------------------------------- !
-
-
- ! Calculate rho (on subcolumns if turned on) for size distribution parameter calculations and average it if needed
- rho(:ncol,top_lev:) = state%pmid(:ncol,top_lev:) / &
- (rair*state%t(:ncol,top_lev:))
- if (use_subcol_microp) then
- call subcol_field_avg(rho, ngrdcol, lchnk, rho_grid)
- else
- rho_grid = rho
- end if
-
- ! Effective radius for cloud liquid, fixed number.
- mu_grid = 0._r8
- lambdac_grid = 0._r8
- rel_fn_grid = 10._r8
- ncic_grid = 1.e8_r8
-
- call size_dist_param_liq(mg_liq_props, icwmrst_grid(:ngrdcol,top_lev:), &
- ncic_grid(:ngrdcol,top_lev:), rho_grid(:ngrdcol,top_lev:), &
- mu_grid(:ngrdcol,top_lev:), lambdac_grid(:ngrdcol,top_lev:))
-
- where (icwmrst_grid(:ngrdcol,top_lev:) > qsmall)
- rel_fn_grid(:ngrdcol,top_lev:) = &
- (mu_grid(:ngrdcol,top_lev:) + 3._r8)/ &
- lambdac_grid(:ngrdcol,top_lev:)/2._r8 * 1.e6_r8
- end where
-
- ! Effective radius for cloud liquid, and size parameters mu_grid and lambdac_grid.
- mu_grid = 0._r8
- lambdac_grid = 0._r8
- rel_grid = 10._r8
-
- ! Calculate ncic (on subcolumns if turned on) and average it if needed
- ncic(:ncol,top_lev:) = state_loc%q(:ncol,top_lev:,ixnumliq) / &
- max(mincld,liqcldf(:ncol,top_lev:))
- if (use_subcol_microp) then
- call subcol_field_avg(ncic, ngrdcol, lchnk, ncic_grid)
- else
- ncic_grid=ncic
- endif
-
- call size_dist_param_liq(mg_liq_props, icwmrst_grid(:ngrdcol,top_lev:), &
- ncic_grid(:ngrdcol,top_lev:), rho_grid(:ngrdcol,top_lev:), &
- mu_grid(:ngrdcol,top_lev:), lambdac_grid(:ngrdcol,top_lev:))
-
- where (icwmrst_grid(:ngrdcol,top_lev:) >= qsmall)
- rel_grid(:ngrdcol,top_lev:) = &
- (mu_grid(:ngrdcol,top_lev:) + 3._r8) / &
- lambdac_grid(:ngrdcol,top_lev:)/2._r8 * 1.e6_r8
- elsewhere
- ! Deal with the fact that size_dist_param_liq sets mu_grid to -100 wherever
- ! there is no cloud.
- mu_grid(:ngrdcol,top_lev:) = 0._r8
- end where
-
- ! Rain/Snow effective diameter.
- ! Note -- These five fields are calculated in micro_mg_tend but are overwritten here
- drout2_grid = 0._r8
- reff_rain_grid = 0._r8
- des_grid = 0._r8
- dsout2_grid = 0._r8
- reff_snow_grid = 0._r8
-
- where (qrout_grid(:ngrdcol,top_lev:) >= 1.e-7_r8)
-
- drout2_grid(:ngrdcol,top_lev:) = avg_diameter(qrout_grid(:ngrdcol,top_lev:), &
- nrout_grid(:ngrdcol,top_lev:) * rho_grid(:ngrdcol,top_lev:), &
- rho_grid(:ngrdcol,top_lev:), rhow)
-
- reff_rain_grid(:ngrdcol,top_lev:) = drout2_grid(:ngrdcol,top_lev:) * &
- 1.5_r8 * 1.e6_r8
-
- end where
-
- where (qsout_grid(:ngrdcol,top_lev:) >= 1.e-7_r8)
-
- dsout2_grid(:ngrdcol,top_lev:) = avg_diameter( qsout_grid(:ngrdcol,top_lev:), &
- nsout_grid(:ngrdcol,top_lev:) * rho_grid(:ngrdcol,top_lev:), &
- rho_grid(:ngrdcol,top_lev:), rhosn)
-
- des_grid(:ngrdcol,top_lev:) = dsout2_grid(:ngrdcol,top_lev:) * 3._r8 * rhosn/rhows
-
- reff_snow_grid(:ngrdcol,top_lev:) = dsout2_grid(:ngrdcol,top_lev:) * &
- 1.5_r8 * 1.e6_r8
-
- end where
-
- ! Effective radius and diameter for cloud ice.
- ! These must always be on the grid
- rei_grid = 25._r8
-
- ! Calculate niic (on subcolumns if turned on) and average it if needed
- niic(:ncol,top_lev:) = state_loc%q(:ncol,top_lev:,ixnumice) / &
- max(mincld,icecldf(:ncol,top_lev:))
- if (use_subcol_microp) then
- call subcol_field_avg(niic, ngrdcol, lchnk, niic_grid)
- else
- niic_grid = niic
- end if
-
- call size_dist_param_basic(mg_ice_props, icimrst_grid(:ngrdcol,top_lev:), &
- niic_grid(:ngrdcol,top_lev:), rei_grid(:ngrdcol,top_lev:))
-
- where (icimrst_grid(:ngrdcol,top_lev:) >= qsmall)
- rei_grid(:ngrdcol,top_lev:) = 1.5_r8/rei_grid(:ngrdcol,top_lev:) &
- * 1.e6_r8
- elsewhere
- rei_grid(:ngrdcol,top_lev:) = 25._r8
- end where
-
- dei_grid = rei_grid * rhoi/rhows * 2._r8
-
-
- ! Limiters for low cloud fraction.
- do k = top_lev, pver
- do i = 1, ngrdcol
- ! Convert snow effective diameter to microns
- des_grid(i,k) = des_grid(i,k) * 1.e6_r8
- if ( ast_grid(i,k) < 1.e-4_r8 ) then
- mu_grid(i,k) = mucon
- lambdac_grid(i,k) = (mucon + 1._r8)/dcon
- dei_grid(i,k) = deicon
- end if
- end do
- end do
-
- mgreffrain_grid(:ngrdcol,top_lev:pver) = reff_rain_grid(:ngrdcol,top_lev:pver)
- mgreffsnow_grid(:ngrdcol,top_lev:pver) = reff_snow_grid(:ngrdcol,top_lev:pver)
-
-
- ! ------------------------------------- !
- ! Precipitation efficiency Calculation !
- ! ------------------------------------- !
-
-
- !-----------------------------------------------------------------------
- ! Liquid water path
-
- ! Compute liquid water paths, and column condensation
- tgliqwp_grid(:ngrdcol) = 0._r8
- tgcmeliq_grid(:ngrdcol) = 0._r8
-
- do k = top_lev, pver
- do i = 1, ngrdcol
- tgliqwp_grid(i) = tgliqwp_grid(i) + iclwpst_grid(i,k)*cld_grid(i,k)
-
- if (cmeliq_grid(i,k) > 1.e-12_r8) then
- !convert cmeliq to right units: kgh2o/kgair/s * kgair/m2 / kgh2o/m3 = m/s
- tgcmeliq_grid(i) = tgcmeliq_grid(i) + cmeliq_grid(i,k) * (pdel_grid(i,k) / gravit) / rhoh2o
- end if
- end do
- end do
-
- ! note: 1e-6 kgho2/kgair/s * 1000. pa / (9.81 m/s2) / 1000 kgh2o/m3 = 1e-7 m/s
- ! this is 1ppmv of h2o in 10hpa
- ! alternatively: 0.1 mm/day * 1.e-4 m/mm * 1/86400 day/s = 1.e-9
-
- !-----------------------------------------------------------------------
- ! precipitation efficiency calculation (accumulate cme and precip)
-
- minlwp = 0.01_r8 !minimum lwp threshold (kg/m3)
-
- ! zero out precip efficiency and total averaged precip
- pe_grid(:ngrdcol) = 0._r8
- tpr_grid(:ngrdcol) = 0._r8
- pefrac_grid(:ngrdcol) = 0._r8
-
- ! accumulate precip and condensation
- do i = 1, ngrdcol
-
- acgcme_grid(i) = acgcme_grid(i) + tgcmeliq_grid(i)
- acprecl_grid(i) = acprecl_grid(i) + prec_str_grid(i)
- acnum_grid(i) = acnum_grid(i) + 1
-
- ! if LWP is zero, then 'end of cloud': calculate precip efficiency
- if (tgliqwp_grid(i) < minlwp) then
- if (acprecl_grid(i) > 5.e-8_r8) then
- tpr_grid(i) = max(acprecl_grid(i)/acnum_grid(i), 1.e-15_r8)
- if (acgcme_grid(i) > 1.e-10_r8) then
- pe_grid(i) = min(max(acprecl_grid(i)/acgcme_grid(i), 1.e-15_r8), 1.e5_r8)
- pefrac_grid(i) = 1._r8
- end if
- end if
-
- ! reset counters
- ! if (pe_grid(i) /= 0._r8 .and. (pe_grid(i) < 1.e-8_r8 .or. pe_grid(i) > 1.e3_r8)) then
- ! write (iulog,*) 'PE_grid:ANOMALY pe_grid, acprecl_grid, acgcme_grid, tpr_grid, acnum_grid ',pe_grid(i),&
- ! acprecl_grid(i), acgcme_grid(i), tpr_grid(i), acnum_grid(i)
- ! endif
-
- acprecl_grid(i) = 0._r8
- acgcme_grid(i) = 0._r8
- acnum_grid(i) = 0
- end if ! end LWP zero conditional
-
- ! if never find any rain....(after 10^3 timesteps...)
- if (acnum_grid(i) > 1000) then
- acnum_grid(i) = 0
- acprecl_grid(i) = 0._r8
- acgcme_grid(i) = 0._r8
- end if
-
- end do
-
- !-----------------------------------------------------------------------
- ! vertical average of non-zero accretion, autoconversion and ratio.
- ! vars: vprco_grid(i),vprao_grid(i),racau_grid(i),cnt_grid
-
- vprao_grid = 0._r8
- cnt_grid = 0
- do k = top_lev, pver
- vprao_grid(:ngrdcol) = vprao_grid(:ngrdcol) + prao_grid(:ngrdcol,k)
- where (prao_grid(:ngrdcol,k) /= 0._r8) cnt_grid(:ngrdcol) = cnt_grid(:ngrdcol) + 1
- end do
-
- where (cnt_grid > 0) vprao_grid = vprao_grid/cnt_grid
-
- vprco_grid = 0._r8
- cnt_grid = 0
- do k = top_lev, pver
- vprco_grid(:ngrdcol) = vprco_grid(:ngrdcol) + prco_grid(:ngrdcol,k)
- where (prco_grid(:ngrdcol,k) /= 0._r8) cnt_grid(:ngrdcol) = cnt_grid(:ngrdcol) + 1
- end do
-
- where (cnt_grid > 0)
- vprco_grid = vprco_grid/cnt_grid
- racau_grid = vprao_grid/vprco_grid
- elsewhere
- racau_grid = 0._r8
- end where
-
- racau_grid = min(racau_grid, 1.e10_r8)
-
- ! --------------------- !
- ! History Output Fields !
- ! --------------------- !
-
- ! Column droplet concentration
- cdnumc_grid(:ngrdcol) = sum(q_ixnumliq_grid(:ngrdcol,top_lev:pver) * &
- pdel_grid(:ngrdcol,top_lev:pver)/gravit, dim=2)
-
- ! Averaging for new output fields
- efcout_grid = 0._r8
- efiout_grid = 0._r8
- ncout_grid = 0._r8
- niout_grid = 0._r8
- freql_grid = 0._r8
- freqi_grid = 0._r8
- liqcldf_grid_out = 0._r8
- icecldf_grid_out = 0._r8
- icwmrst_grid_out = 0._r8
- icimrst_grid_out = 0._r8
-
- do k = top_lev, pver
- do i = 1, ngrdcol
- if ( liqcldf_grid(i,k) > 0.01_r8 .and. icwmrst_grid(i,k) > 5.e-5_r8 ) then
- efcout_grid(i,k) = rel_grid(i,k) * liqcldf_grid(i,k)
- ncout_grid(i,k) = icwnc_grid(i,k) * liqcldf_grid(i,k)
- freql_grid(i,k) = liqcldf_grid(i,k)
- liqcldf_grid_out(i,k) = liqcldf_grid(i,k)
- icwmrst_grid_out(i,k) = icwmrst_grid(i,k)
- end if
- if ( icecldf_grid(i,k) > 0.01_r8 .and. icimrst_grid(i,k) > 1.e-6_r8 ) then
- efiout_grid(i,k) = rei_grid(i,k) * icecldf_grid(i,k)
- niout_grid(i,k) = icinc_grid(i,k) * icecldf_grid(i,k)
- freqi_grid(i,k) = icecldf_grid(i,k)
- icecldf_grid_out(i,k) = icecldf_grid(i,k)
- icimrst_grid_out(i,k) = icimrst_grid(i,k)
- end if
- end do
- end do
-
- ! Cloud top effective radius and number.
- fcti_grid = 0._r8
- fctl_grid = 0._r8
- ctrel_grid = 0._r8
- ctrei_grid = 0._r8
- ctnl_grid = 0._r8
- ctni_grid = 0._r8
- do i = 1, ngrdcol
- do k = top_lev, pver
- if ( liqcldf_grid(i,k) > 0.01_r8 .and. icwmrst_grid(i,k) > 1.e-7_r8 ) then
- ctrel_grid(i) = rel_grid(i,k) * liqcldf_grid(i,k)
- ctnl_grid(i) = icwnc_grid(i,k) * liqcldf_grid(i,k)
- fctl_grid(i) = liqcldf_grid(i,k)
- exit
- end if
- if ( icecldf_grid(i,k) > 0.01_r8 .and. icimrst_grid(i,k) > 1.e-7_r8 ) then
- ctrei_grid(i) = rei_grid(i,k) * icecldf_grid(i,k)
- ctni_grid(i) = icinc_grid(i,k) * icecldf_grid(i,k)
- fcti_grid(i) = icecldf_grid(i,k)
- exit
- end if
- end do
- end do
-
-
- ! Assign the values to the pbuf pointers if they exist in pbuf
- if (qrain_idx > 0) qrout_grid_ptr = qrout_grid
- if (qsnow_idx > 0) qsout_grid_ptr = qsout_grid
- if (nrain_idx > 0) nrout_grid_ptr = nrout_grid
- if (nsnow_idx > 0) nsout_grid_ptr = nsout_grid
-
- ! --------------------------------------------- !
- ! General outfield calls for microphysics !
- ! --------------------------------------------- !
-
- ! Output a handle of variables which are calculated on the fly
- ftem_grid = 0._r8
-
- ftem_grid(:ngrdcol,top_lev:pver) = qcreso_grid(:ngrdcol,top_lev:pver)
- call outfld( 'MPDW2V', ftem_grid, pcols, lchnk)
-
- ftem_grid(:ngrdcol,top_lev:pver) = melto_grid(:ngrdcol,top_lev:pver) - mnuccco_grid(:ngrdcol,top_lev:pver)&
+ use micro_mg_utils, only: size_dist_param_basic, size_dist_param_liq, &
+ mg_liq_props, mg_ice_props, avg_diameter, rhoi, rhosn, rhow, rhows, &
+ qsmall, mincld
+
+ use micro_mg_data, only: MGPacker, MGPostProc, accum_null, accum_mean
+
+ use micro_mg1_0, only: micro_mg_tend1_0 => micro_mg_tend, &
+ micro_mg_get_cols1_0 => micro_mg_get_cols
+ use micro_mg1_5, only: micro_mg_tend1_5 => micro_mg_tend, &
+ micro_mg_get_cols1_5 => micro_mg_get_cols
+ use micro_mg2_0, only: micro_mg_tend2_0 => micro_mg_tend, &
+ micro_mg_get_cols2_0 => micro_mg_get_cols
+
+ use physics_buffer, only: pbuf_col_type_index
+ use subcol, only: subcol_field_avg
+
+ type(physics_state), intent(in) :: state
+ type(physics_ptend), intent(out) :: ptend
+ real(r8), intent(in) :: dtime
+ type(physics_buffer_desc), pointer :: pbuf(:)
+
+ ! Local variables
+ integer :: lchnk, ncol, psetcols, ngrdcol
+
+ integer :: i, k, itim_old, it
+
+ real(r8), pointer :: naai(:,:) ! ice nucleation number
+ real(r8), pointer :: naai_hom(:,:) ! ice nucleation number (homogeneous)
+ real(r8), pointer :: npccn(:,:) ! liquid activation number tendency
+ real(r8), pointer :: rndst(:,:,:)
+ real(r8), pointer :: nacon(:,:,:)
+ real(r8), pointer :: am_evp_st_grid(:,:) ! Evaporation area of stratiform precipitation. 0<= am_evp_st <=1.
+ real(r8), pointer :: evprain_st_grid(:,:) ! Evaporation rate of stratiform rain [kg/kg/s]
+ real(r8), pointer :: evpsnow_st_grid(:,:) ! Evaporation rate of stratiform snow [kg/kg/s]
+
+ real(r8), pointer :: prec_str(:) ! [Total] Sfc flux of precip from stratiform [ m/s ]
+ real(r8), pointer :: snow_str(:) ! [Total] Sfc flux of snow from stratiform [ m/s ]
+ real(r8), pointer :: prec_sed(:) ! Surface flux of total cloud water from sedimentation
+ real(r8), pointer :: snow_sed(:) ! Surface flux of cloud ice from sedimentation
+ real(r8), pointer :: prec_pcw(:) ! Sfc flux of precip from microphysics [ m/s ]
+ real(r8), pointer :: snow_pcw(:) ! Sfc flux of snow from microphysics [ m/s ]
+
+ real(r8), pointer :: ast(:,:) ! Relative humidity cloud fraction
+ real(r8), pointer :: alst_mic(:,:)
+ real(r8), pointer :: aist_mic(:,:)
+ real(r8), pointer :: cldo(:,:) ! Old cloud fraction
+ real(r8), pointer :: nevapr(:,:) ! Evaporation of total precipitation (rain + snow)
+ real(r8), pointer :: prer_evap(:,:) ! precipitation evaporation rate
+ real(r8), pointer :: relvar(:,:) ! relative variance of cloud water
+ real(r8), pointer :: accre_enhan(:,:) ! optional accretion enhancement for experimentation
+ real(r8), pointer :: prain(:,:) ! Total precipitation (rain + snow)
+ real(r8), pointer :: dei(:,:) ! Ice effective diameter (meters) (AG: microns?)
+ real(r8), pointer :: mu(:,:) ! Size distribution shape parameter for radiation
+ real(r8), pointer :: lambdac(:,:) ! Size distribution slope parameter for radiation
+ real(r8), pointer :: des(:,:) ! Snow effective diameter (m)
+
+ real(r8) :: rho(state%psetcols,pver)
+ real(r8) :: cldmax(state%psetcols,pver)
+
+ real(r8), target :: rate1cld(state%psetcols,pver) ! array to hold rate1ord_cw2pr_st from microphysics
+
+ real(r8), target :: tlat(state%psetcols,pver)
+ real(r8), target :: qvlat(state%psetcols,pver)
+ real(r8), target :: qcten(state%psetcols,pver)
+ real(r8), target :: qiten(state%psetcols,pver)
+ real(r8), target :: ncten(state%psetcols,pver)
+ real(r8), target :: niten(state%psetcols,pver)
+
+ real(r8), target :: qrten(state%psetcols,pver)
+ real(r8), target :: qsten(state%psetcols,pver)
+ real(r8), target :: nrten(state%psetcols,pver)
+ real(r8), target :: nsten(state%psetcols,pver)
+
+ real(r8), target :: prect(state%psetcols)
+ real(r8), target :: preci(state%psetcols)
+ real(r8), target :: am_evp_st(state%psetcols,pver) ! Area over which precip evaporates
+ real(r8), target :: evapsnow(state%psetcols,pver) ! Local evaporation of snow
+ real(r8), target :: prodsnow(state%psetcols,pver) ! Local production of snow
+ real(r8), target :: cmeice(state%psetcols,pver) ! Rate of cond-evap of ice within the cloud
+ real(r8), target :: qsout(state%psetcols,pver) ! Snow mixing ratio
+ real(r8), target :: rflx(state%psetcols,pverp) ! grid-box average rain flux (kg m^-2 s^-1)
+ real(r8), target :: sflx(state%psetcols,pverp) ! grid-box average snow flux (kg m^-2 s^-1)
+ real(r8), target :: qrout(state%psetcols,pver) ! Rain mixing ratio
+ real(r8), target :: qcsevap(state%psetcols,pver) ! Evaporation of falling cloud water
+ real(r8), target :: qisevap(state%psetcols,pver) ! Sublimation of falling cloud ice
+ real(r8), target :: qvres(state%psetcols,pver) ! Residual condensation term to remove excess saturation
+ real(r8), target :: cmeiout(state%psetcols,pver) ! Deposition/sublimation rate of cloud ice
+ real(r8), target :: vtrmc(state%psetcols,pver) ! Mass-weighted cloud water fallspeed
+ real(r8), target :: vtrmi(state%psetcols,pver) ! Mass-weighted cloud ice fallspeed
+ real(r8), target :: umr(state%psetcols,pver) ! Mass-weighted rain fallspeed
+ real(r8), target :: ums(state%psetcols,pver) ! Mass-weighted snow fallspeed
+ real(r8), target :: qcsedten(state%psetcols,pver) ! Cloud water mixing ratio tendency from sedimentation
+ real(r8), target :: qisedten(state%psetcols,pver) ! Cloud ice mixing ratio tendency from sedimentation
+ real(r8), target :: qrsedten(state%psetcols,pver) ! Rain mixing ratio tendency from sedimentation
+ real(r8), target :: qssedten(state%psetcols,pver) ! Snow mixing ratio tendency from sedimentation
+
+ real(r8), target :: prao(state%psetcols,pver)
+ real(r8), target :: prco(state%psetcols,pver)
+ real(r8), target :: mnuccco(state%psetcols,pver)
+ real(r8), target :: mnuccto(state%psetcols,pver)
+ real(r8), target :: msacwio(state%psetcols,pver)
+ real(r8), target :: psacwso(state%psetcols,pver)
+ real(r8), target :: bergso(state%psetcols,pver)
+ real(r8), target :: bergo(state%psetcols,pver)
+ real(r8), target :: melto(state%psetcols,pver)
+ real(r8), target :: homoo(state%psetcols,pver)
+ real(r8), target :: qcreso(state%psetcols,pver)
+ real(r8), target :: prcio(state%psetcols,pver)
+ real(r8), target :: praio(state%psetcols,pver)
+ real(r8), target :: qireso(state%psetcols,pver)
+ real(r8), target :: mnuccro(state%psetcols,pver)
+ real(r8), target :: pracso (state%psetcols,pver)
+ real(r8), target :: meltsdt(state%psetcols,pver)
+ real(r8), target :: frzrdt (state%psetcols,pver)
+ real(r8), target :: mnuccdo(state%psetcols,pver)
+ real(r8), target :: nrout(state%psetcols,pver)
+ real(r8), target :: nsout(state%psetcols,pver)
+ real(r8), target :: refl(state%psetcols,pver) ! analytic radar reflectivity
+ real(r8), target :: arefl(state%psetcols,pver) ! average reflectivity will zero points outside valid range
+ real(r8), target :: areflz(state%psetcols,pver) ! average reflectivity in z.
+ real(r8), target :: frefl(state%psetcols,pver)
+ real(r8), target :: csrfl(state%psetcols,pver) ! cloudsat reflectivity
+ real(r8), target :: acsrfl(state%psetcols,pver) ! cloudsat average
+ real(r8), target :: fcsrfl(state%psetcols,pver)
+ real(r8), target :: rercld(state%psetcols,pver) ! effective radius calculation for rain + cloud
+ real(r8), target :: ncai(state%psetcols,pver) ! output number conc of ice nuclei available (1/m3)
+ real(r8), target :: ncal(state%psetcols,pver) ! output number conc of CCN (1/m3)
+ real(r8), target :: qrout2(state%psetcols,pver)
+ real(r8), target :: qsout2(state%psetcols,pver)
+ real(r8), target :: nrout2(state%psetcols,pver)
+ real(r8), target :: nsout2(state%psetcols,pver)
+ real(r8), target :: freqs(state%psetcols,pver)
+ real(r8), target :: freqr(state%psetcols,pver)
+ real(r8), target :: nfice(state%psetcols,pver)
+ real(r8), target :: qcrat(state%psetcols,pver) ! qc limiter ratio (1=no limit)
+
+ ! Object that packs columns with clouds/precip.
+ type(MGPacker) :: packer
+
+ ! Packed versions of inputs.
+ real(r8), allocatable :: packed_t(:,:)
+ real(r8), allocatable :: packed_q(:,:)
+ real(r8), allocatable :: packed_qc(:,:)
+ real(r8), allocatable :: packed_nc(:,:)
+ real(r8), allocatable :: packed_qi(:,:)
+ real(r8), allocatable :: packed_ni(:,:)
+ real(r8), allocatable :: packed_qr(:,:)
+ real(r8), allocatable :: packed_nr(:,:)
+ real(r8), allocatable :: packed_qs(:,:)
+ real(r8), allocatable :: packed_ns(:,:)
+
+ real(r8), allocatable :: packed_relvar(:,:)
+ real(r8), allocatable :: packed_accre_enhan(:,:)
+
+ real(r8), allocatable :: packed_p(:,:)
+ real(r8), allocatable :: packed_pdel(:,:)
+
+ ! This is only needed for MG1.5, and can be removed when support for
+ ! that version is dropped.
+ real(r8), allocatable :: packed_pint(:,:)
+
+ real(r8), allocatable :: packed_cldn(:,:)
+ real(r8), allocatable :: packed_liqcldf(:,:)
+ real(r8), allocatable :: packed_icecldf(:,:)
+
+ real(r8), allocatable :: packed_naai(:,:)
+ real(r8), allocatable :: packed_npccn(:,:)
+
+ real(r8), allocatable :: packed_rndst(:,:,:)
+ real(r8), allocatable :: packed_nacon(:,:,:)
+
+ ! Optional outputs.
+ real(r8), pointer :: packed_tnd_qsnow(:,:)
+ real(r8), pointer :: packed_tnd_nsnow(:,:)
+ real(r8), pointer :: packed_re_ice(:,:)
+
+ real(r8), pointer :: packed_frzimm(:,:)
+ real(r8), pointer :: packed_frzcnt(:,:)
+ real(r8), pointer :: packed_frzdep(:,:)
+
+ ! Output field post-processing.
+ type(MGPostProc) :: post_proc
+
+ ! Packed versions of outputs.
+ real(r8), allocatable, target :: packed_rate1ord_cw2pr_st(:,:)
+ real(r8), allocatable, target :: packed_tlat(:,:)
+ real(r8), allocatable, target :: packed_qvlat(:,:)
+ real(r8), allocatable, target :: packed_qctend(:,:)
+ real(r8), allocatable, target :: packed_qitend(:,:)
+ real(r8), allocatable, target :: packed_nctend(:,:)
+ real(r8), allocatable, target :: packed_nitend(:,:)
+
+ real(r8), allocatable, target :: packed_qrtend(:,:)
+ real(r8), allocatable, target :: packed_qstend(:,:)
+ real(r8), allocatable, target :: packed_nrtend(:,:)
+ real(r8), allocatable, target :: packed_nstend(:,:)
+
+ real(r8), allocatable, target :: packed_prect(:)
+ real(r8), allocatable, target :: packed_preci(:)
+ real(r8), allocatable, target :: packed_nevapr(:,:)
+ real(r8), allocatable, target :: packed_am_evp_st(:,:)
+ real(r8), allocatable, target :: packed_evapsnow(:,:)
+ real(r8), allocatable, target :: packed_prain(:,:)
+ real(r8), allocatable, target :: packed_prodsnow(:,:)
+ real(r8), allocatable, target :: packed_cmeout(:,:)
+ real(r8), allocatable, target :: packed_qsout(:,:)
+ real(r8), allocatable, target :: packed_rflx(:,:)
+ real(r8), allocatable, target :: packed_sflx(:,:)
+ real(r8), allocatable, target :: packed_qrout(:,:)
+ real(r8), allocatable, target :: packed_qcsevap(:,:)
+ real(r8), allocatable, target :: packed_qisevap(:,:)
+ real(r8), allocatable, target :: packed_qvres(:,:)
+ real(r8), allocatable, target :: packed_cmei(:,:)
+ real(r8), allocatable, target :: packed_vtrmc(:,:)
+ real(r8), allocatable, target :: packed_vtrmi(:,:)
+ real(r8), allocatable, target :: packed_qcsedten(:,:)
+ real(r8), allocatable, target :: packed_qisedten(:,:)
+ real(r8), allocatable, target :: packed_qrsedten(:,:)
+ real(r8), allocatable, target :: packed_qssedten(:,:)
+ real(r8), allocatable, target :: packed_umr(:,:)
+ real(r8), allocatable, target :: packed_ums(:,:)
+ real(r8), allocatable, target :: packed_pra(:,:)
+ real(r8), allocatable, target :: packed_prc(:,:)
+ real(r8), allocatable, target :: packed_mnuccc(:,:)
+ real(r8), allocatable, target :: packed_mnucct(:,:)
+ real(r8), allocatable, target :: packed_msacwi(:,:)
+ real(r8), allocatable, target :: packed_psacws(:,:)
+ real(r8), allocatable, target :: packed_bergs(:,:)
+ real(r8), allocatable, target :: packed_berg(:,:)
+ real(r8), allocatable, target :: packed_melt(:,:)
+ real(r8), allocatable, target :: packed_homo(:,:)
+ real(r8), allocatable, target :: packed_qcres(:,:)
+ real(r8), allocatable, target :: packed_prci(:,:)
+ real(r8), allocatable, target :: packed_prai(:,:)
+ real(r8), allocatable, target :: packed_qires(:,:)
+ real(r8), allocatable, target :: packed_mnuccr(:,:)
+ real(r8), allocatable, target :: packed_pracs(:,:)
+ real(r8), allocatable, target :: packed_meltsdt(:,:)
+ real(r8), allocatable, target :: packed_frzrdt(:,:)
+ real(r8), allocatable, target :: packed_mnuccd(:,:)
+ real(r8), allocatable, target :: packed_nrout(:,:)
+ real(r8), allocatable, target :: packed_nsout(:,:)
+ real(r8), allocatable, target :: packed_refl(:,:)
+ real(r8), allocatable, target :: packed_arefl(:,:)
+ real(r8), allocatable, target :: packed_areflz(:,:)
+ real(r8), allocatable, target :: packed_frefl(:,:)
+ real(r8), allocatable, target :: packed_csrfl(:,:)
+ real(r8), allocatable, target :: packed_acsrfl(:,:)
+ real(r8), allocatable, target :: packed_fcsrfl(:,:)
+ real(r8), allocatable, target :: packed_rercld(:,:)
+ real(r8), allocatable, target :: packed_ncai(:,:)
+ real(r8), allocatable, target :: packed_ncal(:,:)
+ real(r8), allocatable, target :: packed_qrout2(:,:)
+ real(r8), allocatable, target :: packed_qsout2(:,:)
+ real(r8), allocatable, target :: packed_nrout2(:,:)
+ real(r8), allocatable, target :: packed_nsout2(:,:)
+ real(r8), allocatable, target :: packed_freqs(:,:)
+ real(r8), allocatable, target :: packed_freqr(:,:)
+ real(r8), allocatable, target :: packed_nfice(:,:)
+ real(r8), allocatable, target :: packed_prer_evap(:,:)
+ real(r8), allocatable, target :: packed_qcrat(:,:)
+
+ real(r8), allocatable, target :: packed_rel(:,:)
+ real(r8), allocatable, target :: packed_rei(:,:)
+ real(r8), allocatable, target :: packed_lambdac(:,:)
+ real(r8), allocatable, target :: packed_mu(:,:)
+ real(r8), allocatable, target :: packed_des(:,:)
+ real(r8), allocatable, target :: packed_dei(:,:)
+
+ ! Dummy arrays for cases where we throw away the MG version and
+ ! recalculate sizes on the CAM grid to avoid time/subcolumn averaging
+ ! issues.
+ real(r8), allocatable :: rel_fn_dum(:,:)
+ real(r8), allocatable :: dsout2_dum(:,:)
+ real(r8), allocatable :: drout_dum(:,:)
+ real(r8), allocatable :: reff_rain_dum(:,:)
+ real(r8), allocatable :: reff_snow_dum(:,:)
+
+ ! Heterogeneous-only version of mnuccdo.
+ real(r8) :: mnuccdohet(state%psetcols,pver)
+
+ ! physics buffer fields for COSP simulator
+ real(r8), pointer :: mgflxprc(:,:) ! MG grid-box mean flux_large_scale_cloud_rain+snow at interfaces (kg/m2/s)
+ real(r8), pointer :: mgflxsnw(:,:) ! MG grid-box mean flux_large_scale_cloud_snow at interfaces (kg/m2/s)
+ real(r8), pointer :: mgmrprc(:,:) ! MG grid-box mean mixingratio_large_scale_cloud_rain+snow at interfaces (kg/kg)
+ real(r8), pointer :: mgmrsnw(:,:) ! MG grid-box mean mixingratio_large_scale_cloud_snow at interfaces (kg/kg)
+ real(r8), pointer :: mgreffrain_grid(:,:) ! MG diagnostic rain effective radius (um)
+ real(r8), pointer :: mgreffsnow_grid(:,:) ! MG diagnostic snow effective radius (um)
+ real(r8), pointer :: cvreffliq(:,:) ! convective cloud liquid effective radius (um)
+ real(r8), pointer :: cvreffice(:,:) ! convective cloud ice effective radius (um)
+
+ ! physics buffer fields used with CARMA
+ real(r8), pointer, dimension(:,:) :: tnd_qsnow ! external tendency on snow mass (kg/kg/s)
+ real(r8), pointer, dimension(:,:) :: tnd_nsnow ! external tendency on snow number(#/kg/s)
+ real(r8), pointer, dimension(:,:) :: re_ice ! ice effective radius (m)
+
+ real(r8), pointer :: rate1ord_cw2pr_st(:,:) ! 1st order rate for direct conversion of
+ ! strat. cloud water to precip (1/s) ! rce 2010/05/01
+ real(r8), pointer :: wsedl(:,:) ! Sedimentation velocity of liquid stratus cloud droplet [ m/s ]
+
+
+ real(r8), pointer :: CC_T(:,:) ! Grid-mean microphysical tendency
+ real(r8), pointer :: CC_qv(:,:) ! Grid-mean microphysical tendency
+ real(r8), pointer :: CC_ql(:,:) ! Grid-mean microphysical tendency
+ real(r8), pointer :: CC_qi(:,:) ! Grid-mean microphysical tendency
+ real(r8), pointer :: CC_nl(:,:) ! Grid-mean microphysical tendency
+ real(r8), pointer :: CC_ni(:,:) ! Grid-mean microphysical tendency
+ real(r8), pointer :: CC_qlst(:,:) ! In-liquid stratus microphysical tendency
+
+ ! variables for heterogeneous freezing
+ real(r8), pointer :: frzimm(:,:)
+ real(r8), pointer :: frzcnt(:,:)
+ real(r8), pointer :: frzdep(:,:)
+
+ real(r8), pointer :: qme(:,:)
+
+ ! A local copy of state is used for diagnostic calculations
+ type(physics_state) :: state_loc
+ type(physics_ptend) :: ptend_loc
+
+ real(r8) :: icecldf(state%psetcols,pver) ! Ice cloud fraction
+ real(r8) :: liqcldf(state%psetcols,pver) ! Liquid cloud fraction (combined into cloud)
+
+ real(r8), pointer :: rel(:,:) ! Liquid effective drop radius (microns)
+ real(r8), pointer :: rei(:,:) ! Ice effective drop size (microns)
+
+ real(r8), pointer :: cmeliq(:,:)
+
+ real(r8), pointer :: cld(:,:) ! Total cloud fraction
+ real(r8), pointer :: concld(:,:) ! Convective cloud fraction
+ real(r8), pointer :: iciwpst(:,:) ! Stratiform in-cloud ice water path for radiation
+ real(r8), pointer :: iclwpst(:,:) ! Stratiform in-cloud liquid water path for radiation
+ real(r8), pointer :: cldfsnow(:,:) ! Cloud fraction for liquid+snow
+ real(r8), pointer :: icswp(:,:) ! In-cloud snow water path
+
+ real(r8) :: icimrst(state%psetcols,pver) ! In stratus ice mixing ratio
+ real(r8) :: icwmrst(state%psetcols,pver) ! In stratus water mixing ratio
+ real(r8) :: icinc(state%psetcols,pver) ! In cloud ice number conc
+ real(r8) :: icwnc(state%psetcols,pver) ! In cloud water number conc
+
+ real(r8) :: iclwpi(state%psetcols) ! Vertically-integrated in-cloud Liquid WP before microphysics
+ real(r8) :: iciwpi(state%psetcols) ! Vertically-integrated in-cloud Ice WP before microphysics
+
+ ! Averaging arrays for effective radius and number....
+ real(r8) :: efiout_grid(pcols,pver)
+ real(r8) :: efcout_grid(pcols,pver)
+ real(r8) :: ncout_grid(pcols,pver)
+ real(r8) :: niout_grid(pcols,pver)
+ real(r8) :: freqi_grid(pcols,pver)
+ real(r8) :: freql_grid(pcols,pver)
+
+ real(r8) :: cdnumc_grid(pcols) ! Vertically-integrated droplet concentration
+ real(r8) :: icimrst_grid_out(pcols,pver) ! In stratus ice mixing ratio
+ real(r8) :: icwmrst_grid_out(pcols,pver) ! In stratus water mixing ratio
+
+ ! Cloud fraction used for precipitation.
+ real(r8) :: cldmax_grid(pcols,pver)
+
+ ! Average cloud top radius & number
+ real(r8) :: ctrel_grid(pcols)
+ real(r8) :: ctrei_grid(pcols)
+ real(r8) :: ctnl_grid(pcols)
+ real(r8) :: ctni_grid(pcols)
+ real(r8) :: fcti_grid(pcols)
+ real(r8) :: fctl_grid(pcols)
+
+ real(r8) :: ftem_grid(pcols,pver)
+
+ ! Variables for precip efficiency calculation
+ real(r8) :: minlwp ! LWP threshold
+
+ real(r8), pointer, dimension(:) :: acprecl_grid ! accumulated precip across timesteps
+ real(r8), pointer, dimension(:) :: acgcme_grid ! accumulated condensation across timesteps
+ integer, pointer, dimension(:) :: acnum_grid ! counter for # timesteps accumulated
+
+ ! Variables for liquid water path and column condensation
+ real(r8) :: tgliqwp_grid(pcols) ! column liquid
+ real(r8) :: tgcmeliq_grid(pcols) ! column condensation rate (units)
+
+ real(r8) :: pe_grid(pcols) ! precip efficiency for output
+ real(r8) :: pefrac_grid(pcols) ! fraction of time precip efficiency is written out
+ real(r8) :: tpr_grid(pcols) ! average accumulated precipitation rate in pe calculation
+
+ ! variables for autoconversion and accretion vertical averages
+ real(r8) :: vprco_grid(pcols) ! vertical average autoconversion
+ real(r8) :: vprao_grid(pcols) ! vertical average accretion
+ real(r8) :: racau_grid(pcols) ! ratio of vertical averages
+ integer :: cnt_grid(pcols) ! counters
+
+ logical :: lq(pcnst)
+
+ real(r8) :: icimrst_grid(pcols,pver) ! stratus ice mixing ratio - on grid
+ real(r8) :: icwmrst_grid(pcols,pver) ! stratus water mixing ratio - on grid
+
+ real(r8), pointer :: lambdac_grid(:,:)
+ real(r8), pointer :: mu_grid(:,:)
+ real(r8), pointer :: rel_grid(:,:)
+ real(r8), pointer :: rei_grid(:,:)
+ real(r8), pointer :: dei_grid(:,:)
+ real(r8), pointer :: des_grid(:,:)
+ real(r8), pointer :: iclwpst_grid(:,:)
+
+ real(r8) :: rho_grid(pcols,pver)
+ real(r8) :: liqcldf_grid(pcols,pver)
+ real(r8) :: qsout_grid(pcols,pver)
+ real(r8) :: ncic_grid(pcols,pver)
+ real(r8) :: niic_grid(pcols,pver)
+ real(r8) :: rel_fn_grid(pcols,pver) ! Ice effective drop size at fixed number (indirect effect) (microns) - on grid
+ real(r8) :: qrout_grid(pcols,pver)
+ real(r8) :: drout2_grid(pcols,pver)
+ real(r8) :: dsout2_grid(pcols,pver)
+ real(r8) :: nsout_grid(pcols,pver)
+ real(r8) :: nrout_grid(pcols,pver)
+ real(r8) :: reff_rain_grid(pcols,pver)
+ real(r8) :: reff_snow_grid(pcols,pver)
+ real(r8) :: cld_grid(pcols,pver)
+ real(r8) :: pdel_grid(pcols,pver)
+ real(r8) :: prco_grid(pcols,pver)
+ real(r8) :: prao_grid(pcols,pver)
+ real(r8) :: icecldf_grid(pcols,pver)
+ real(r8) :: icwnc_grid(pcols,pver)
+ real(r8) :: icinc_grid(pcols,pver)
+ real(r8) :: qcreso_grid(pcols,pver)
+ real(r8) :: melto_grid(pcols,pver)
+ real(r8) :: mnuccco_grid(pcols,pver)
+ real(r8) :: mnuccto_grid(pcols,pver)
+ real(r8) :: bergo_grid(pcols,pver)
+ real(r8) :: homoo_grid(pcols,pver)
+ real(r8) :: msacwio_grid(pcols,pver)
+ real(r8) :: psacwso_grid(pcols,pver)
+ real(r8) :: bergso_grid(pcols,pver)
+ real(r8) :: cmeiout_grid(pcols,pver)
+ real(r8) :: qireso_grid(pcols,pver)
+ real(r8) :: prcio_grid(pcols,pver)
+ real(r8) :: praio_grid(pcols,pver)
+
+ real(r8) :: nc_grid(pcols,pver)
+ real(r8) :: ni_grid(pcols,pver)
+ real(r8) :: qr_grid(pcols,pver)
+ real(r8) :: nr_grid(pcols,pver)
+ real(r8) :: qs_grid(pcols,pver)
+ real(r8) :: ns_grid(pcols,pver)
+
+ real(r8), pointer :: cmeliq_grid(:,:)
+
+ real(r8), pointer :: prec_str_grid(:)
+ real(r8), pointer :: snow_str_grid(:)
+ real(r8), pointer :: prec_pcw_grid(:)
+ real(r8), pointer :: snow_pcw_grid(:)
+ real(r8), pointer :: prec_sed_grid(:)
+ real(r8), pointer :: snow_sed_grid(:)
+ real(r8), pointer :: cldo_grid(:,:)
+ real(r8), pointer :: nevapr_grid(:,:)
+ real(r8), pointer :: prain_grid(:,:)
+ real(r8), pointer :: mgflxprc_grid(:,:)
+ real(r8), pointer :: mgflxsnw_grid(:,:)
+ real(r8), pointer :: mgmrprc_grid(:,:)
+ real(r8), pointer :: mgmrsnw_grid(:,:)
+ real(r8), pointer :: cvreffliq_grid(:,:)
+ real(r8), pointer :: cvreffice_grid(:,:)
+ real(r8), pointer :: rate1ord_cw2pr_st_grid(:,:)
+ real(r8), pointer :: wsedl_grid(:,:)
+ real(r8), pointer :: CC_t_grid(:,:)
+ real(r8), pointer :: CC_qv_grid(:,:)
+ real(r8), pointer :: CC_ql_grid(:,:)
+ real(r8), pointer :: CC_qi_grid(:,:)
+ real(r8), pointer :: CC_nl_grid(:,:)
+ real(r8), pointer :: CC_ni_grid(:,:)
+ real(r8), pointer :: CC_qlst_grid(:,:)
+ real(r8), pointer :: qme_grid(:,:)
+ real(r8), pointer :: iciwpst_grid(:,:)
+ real(r8), pointer :: icswp_grid(:,:)
+ real(r8), pointer :: ast_grid(:,:)
+ real(r8), pointer :: cldfsnow_grid(:,:)
+
+ real(r8), pointer :: qrout_grid_ptr(:,:)
+ real(r8), pointer :: qsout_grid_ptr(:,:)
+ real(r8), pointer :: nrout_grid_ptr(:,:)
+ real(r8), pointer :: nsout_grid_ptr(:,:)
+
+ integer :: nlev ! number of levels where cloud physics is done
+ integer :: mgncol ! size of mgcols
+ integer, allocatable :: mgcols(:) ! Columns with microphysics performed
+
+ logical :: use_subcol_microp
+ integer :: col_type ! Flag to store whether accessing grid or sub-columns in pbuf_get_field
+
+ character(128) :: errstring ! return status (non-blank for error return)
+
+ ! For rrtmg optics. specified distribution.
+ real(r8), parameter :: dcon = 25.e-6_r8 ! Convective size distribution effective radius (meters)
+ real(r8), parameter :: mucon = 5.3_r8 ! Convective size distribution shape parameter
+ real(r8), parameter :: deicon = 50._r8 ! Convective ice effective diameter (meters)
+
+ real(r8), pointer :: pckdptr(:,:)
+
+ !-------------------------------------------------------------------------------
+
+ ! Find the number of levels used in the microphysics.
+ nlev = pver - top_lev + 1
+
+ lchnk = state%lchnk
+ ncol = state%ncol
+ psetcols = state%psetcols
+ ngrdcol = state%ngrdcol
+
+ itim_old = pbuf_old_tim_idx()
+
+ call phys_getopts(use_subcol_microp_out=use_subcol_microp)
+
+ ! Set the col_type flag to grid or subcolumn dependent on the value of use_subcol_microp
+ call pbuf_col_type_index(use_subcol_microp, col_type=col_type)
+
+ !-----------------------
+ ! These physics buffer fields are read only and not set in this parameterization
+ ! If these fields do not have subcolumn data, copy the grid to the subcolumn if subcolumns is turned on
+ ! If subcolumns is not turned on, then these fields will be grid data
+
+ call pbuf_get_field(pbuf, naai_idx, naai, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, naai_hom_idx, naai_hom, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, npccn_idx, npccn, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, rndst_idx, rndst, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, nacon_idx, nacon, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, relvar_idx, relvar, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, accre_enhan_idx, accre_enhan, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, cmeliq_idx, cmeliq, col_type=col_type, copy_if_needed=use_subcol_microp)
+
+ call pbuf_get_field(pbuf, cld_idx, cld, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), &
+ col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, concld_idx, concld, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), &
+ col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, ast_idx, ast, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), &
+ col_type=col_type, copy_if_needed=use_subcol_microp)
+
+ if (.not. do_cldice) then
+ call pbuf_get_field(pbuf, tnd_qsnow_idx, tnd_qsnow, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, tnd_nsnow_idx, tnd_nsnow, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, re_ice_idx, re_ice, col_type=col_type, copy_if_needed=use_subcol_microp)
+ end if
+
+ if (use_hetfrz_classnuc) then
+ call pbuf_get_field(pbuf, frzimm_idx, frzimm, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, frzcnt_idx, frzcnt, col_type=col_type, copy_if_needed=use_subcol_microp)
+ call pbuf_get_field(pbuf, frzdep_idx, frzdep, col_type=col_type, copy_if_needed=use_subcol_microp)
+ end if
+
+ !-----------------------
+ ! These physics buffer fields are calculated and set in this parameterization
+ ! If subcolumns is turned on, then these fields will be calculated on a subcolumn grid, otherwise they will be a normal grid
+
+ call pbuf_get_field(pbuf, prec_str_idx, prec_str, col_type=col_type)
+ call pbuf_get_field(pbuf, snow_str_idx, snow_str, col_type=col_type)
+ call pbuf_get_field(pbuf, prec_pcw_idx, prec_pcw, col_type=col_type)
+ call pbuf_get_field(pbuf, snow_pcw_idx, snow_pcw, col_type=col_type)
+ call pbuf_get_field(pbuf, prec_sed_idx, prec_sed, col_type=col_type)
+ call pbuf_get_field(pbuf, snow_sed_idx, snow_sed, col_type=col_type)
+ call pbuf_get_field(pbuf, nevapr_idx, nevapr, col_type=col_type)
+ call pbuf_get_field(pbuf, prer_evap_idx, prer_evap, col_type=col_type)
+ call pbuf_get_field(pbuf, prain_idx, prain, col_type=col_type)
+ call pbuf_get_field(pbuf, dei_idx, dei, col_type=col_type)
+ call pbuf_get_field(pbuf, mu_idx, mu, col_type=col_type)
+ call pbuf_get_field(pbuf, lambdac_idx, lambdac, col_type=col_type)
+ call pbuf_get_field(pbuf, des_idx, des, col_type=col_type)
+ call pbuf_get_field(pbuf, ls_flxprc_idx, mgflxprc, col_type=col_type)
+ call pbuf_get_field(pbuf, ls_flxsnw_idx, mgflxsnw, col_type=col_type)
+ call pbuf_get_field(pbuf, ls_mrprc_idx, mgmrprc, col_type=col_type)
+ call pbuf_get_field(pbuf, ls_mrsnw_idx, mgmrsnw, col_type=col_type)
+ call pbuf_get_field(pbuf, cv_reffliq_idx, cvreffliq, col_type=col_type)
+ call pbuf_get_field(pbuf, cv_reffice_idx, cvreffice, col_type=col_type)
+ call pbuf_get_field(pbuf, iciwpst_idx, iciwpst, col_type=col_type)
+ call pbuf_get_field(pbuf, iclwpst_idx, iclwpst, col_type=col_type)
+ call pbuf_get_field(pbuf, icswp_idx, icswp, col_type=col_type)
+ call pbuf_get_field(pbuf, rel_idx, rel, col_type=col_type)
+ call pbuf_get_field(pbuf, rei_idx, rei, col_type=col_type)
+ call pbuf_get_field(pbuf, wsedl_idx, wsedl, col_type=col_type)
+ call pbuf_get_field(pbuf, qme_idx, qme, col_type=col_type)
+
+ call pbuf_get_field(pbuf, cldo_idx, cldo, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cldfsnow_idx, cldfsnow, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cc_t_idx, CC_t, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cc_qv_idx, CC_qv, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cc_ql_idx, CC_ql, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cc_qi_idx, CC_qi, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cc_nl_idx, CC_nl, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cc_ni_idx, CC_ni, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+ call pbuf_get_field(pbuf, cc_qlst_idx, CC_qlst, start=(/1,1,itim_old/), kount=(/psetcols,pver,1/), col_type=col_type)
+
+ if (rate1_cw2pr_st_idx > 0) then
+ call pbuf_get_field(pbuf, rate1_cw2pr_st_idx, rate1ord_cw2pr_st, col_type=col_type)
+ end if
+
+ if (qrain_idx > 0) call pbuf_get_field(pbuf, qrain_idx, qrout_grid_ptr)
+ if (qsnow_idx > 0) call pbuf_get_field(pbuf, qsnow_idx, qsout_grid_ptr)
+ if (nrain_idx > 0) call pbuf_get_field(pbuf, nrain_idx, nrout_grid_ptr)
+ if (nsnow_idx > 0) call pbuf_get_field(pbuf, nsnow_idx, nsout_grid_ptr)
+
+ !-----------------------
+ ! If subcolumns is turned on, all calculated fields which are on subcolumns
+ ! need to be retrieved on the grid as well for storing averaged values
+
+ if (use_subcol_microp) then
+ call pbuf_get_field(pbuf, prec_str_idx, prec_str_grid)
+ call pbuf_get_field(pbuf, snow_str_idx, snow_str_grid)
+ call pbuf_get_field(pbuf, prec_pcw_idx, prec_pcw_grid)
+ call pbuf_get_field(pbuf, snow_pcw_idx, snow_pcw_grid)
+ call pbuf_get_field(pbuf, prec_sed_idx, prec_sed_grid)
+ call pbuf_get_field(pbuf, snow_sed_idx, snow_sed_grid)
+ call pbuf_get_field(pbuf, nevapr_idx, nevapr_grid)
+ call pbuf_get_field(pbuf, prain_idx, prain_grid)
+ call pbuf_get_field(pbuf, dei_idx, dei_grid)
+ call pbuf_get_field(pbuf, mu_idx, mu_grid)
+ call pbuf_get_field(pbuf, lambdac_idx, lambdac_grid)
+ call pbuf_get_field(pbuf, des_idx, des_grid)
+ call pbuf_get_field(pbuf, ls_flxprc_idx, mgflxprc_grid)
+ call pbuf_get_field(pbuf, ls_flxsnw_idx, mgflxsnw_grid)
+ call pbuf_get_field(pbuf, ls_mrprc_idx, mgmrprc_grid)
+ call pbuf_get_field(pbuf, ls_mrsnw_idx, mgmrsnw_grid)
+ call pbuf_get_field(pbuf, cv_reffliq_idx, cvreffliq_grid)
+ call pbuf_get_field(pbuf, cv_reffice_idx, cvreffice_grid)
+ call pbuf_get_field(pbuf, iciwpst_idx, iciwpst_grid)
+ call pbuf_get_field(pbuf, iclwpst_idx, iclwpst_grid)
+ call pbuf_get_field(pbuf, icswp_idx, icswp_grid)
+ call pbuf_get_field(pbuf, rel_idx, rel_grid)
+ call pbuf_get_field(pbuf, rei_idx, rei_grid)
+ call pbuf_get_field(pbuf, wsedl_idx, wsedl_grid)
+ call pbuf_get_field(pbuf, qme_idx, qme_grid)
+
+ call pbuf_get_field(pbuf, cldo_idx, cldo_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cldfsnow_idx, cldfsnow_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cc_t_idx, CC_t_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cc_qv_idx, CC_qv_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cc_ql_idx, CC_ql_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cc_qi_idx, CC_qi_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cc_nl_idx, CC_nl_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cc_ni_idx, CC_ni_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ call pbuf_get_field(pbuf, cc_qlst_idx, CC_qlst_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+
+ if (rate1_cw2pr_st_idx > 0) then
+ call pbuf_get_field(pbuf, rate1_cw2pr_st_idx, rate1ord_cw2pr_st_grid)
+ end if
+
+ end if
+
+ !-----------------------
+ ! These are only on the grid regardless of whether subcolumns are turned on or not
+ call pbuf_get_field(pbuf, ls_reffrain_idx, mgreffrain_grid)
+ call pbuf_get_field(pbuf, ls_reffsnow_idx, mgreffsnow_grid)
+ call pbuf_get_field(pbuf, acpr_idx, acprecl_grid)
+ call pbuf_get_field(pbuf, acgcme_idx, acgcme_grid)
+ call pbuf_get_field(pbuf, acnum_idx, acnum_grid)
+ call pbuf_get_field(pbuf, cmeliq_idx, cmeliq_grid)
+ call pbuf_get_field(pbuf, ast_idx, ast_grid, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+
+ call pbuf_get_field(pbuf, evprain_st_idx, evprain_st_grid)
+ call pbuf_get_field(pbuf, evpsnow_st_idx, evpsnow_st_grid)
+
+ ! Only MG 1 defines this field so far.
+ if (micro_mg_version == 1 .and. micro_mg_sub_version == 0) then
+ call pbuf_get_field(pbuf, am_evp_st_idx, am_evp_st_grid)
+ end if
+
+ !-------------------------------------------------------------------------------------
+ ! Microphysics assumes 'liquid stratus frac = ice stratus frac
+ ! = max( liquid stratus frac, ice stratus frac )'.
+ alst_mic => ast
+ aist_mic => ast
+
+ ! Output initial in-cloud LWP (before microphysics)
+
+ iclwpi = 0._r8
+ iciwpi = 0._r8
+
+ do i = 1, ncol
+ do k = top_lev, pver
+ iclwpi(i) = iclwpi(i) + &
+ min(state%q(i,k,ixcldliq) / max(mincld,ast(i,k)),0.005_r8) &
+ * state%pdel(i,k) / gravit
+ iciwpi(i) = iciwpi(i) + &
+ min(state%q(i,k,ixcldice) / max(mincld,ast(i,k)),0.005_r8) &
+ * state%pdel(i,k) / gravit
+ end do
+ end do
+
+ cldo(:ncol,top_lev:pver)=ast(:ncol,top_lev:pver)
+
+ ! Initialize local state from input.
+ call physics_state_copy(state, state_loc)
+
+ ! Initialize ptend for output.
+ lq = .false.
+ lq(1) = .true.
+ lq(ixcldliq) = .true.
+ lq(ixcldice) = .true.
+ lq(ixnumliq) = .true.
+ lq(ixnumice) = .true.
+ if (micro_mg_version > 1) then
+ lq(ixrain) = .true.
+ lq(ixsnow) = .true.
+ lq(ixnumrain) = .true.
+ lq(ixnumsnow) = .true.
+ end if
+
+ ! the name 'cldwat' triggers special tests on cldliq
+ ! and cldice in physics_update
+ call physics_ptend_init(ptend, psetcols, "cldwat", ls=.true., lq=lq)
+
+ select case (micro_mg_version)
+ case (1)
+ select case (micro_mg_sub_version)
+ case (0)
+ call micro_mg_get_cols1_0(ncol, nlev, top_lev, state%q(:,:,ixcldliq), &
+ state%q(:,:,ixcldice), mgncol, mgcols)
+ case (5)
+ call micro_mg_get_cols1_5(ncol, nlev, top_lev, state%q(:,:,ixcldliq), &
+ state%q(:,:,ixcldice), mgncol, mgcols)
+ end select
+ case (2)
+ call micro_mg_get_cols2_0(ncol, nlev, top_lev, state%q(:,:,ixcldliq), &
+ state%q(:,:,ixcldice), state%q(:,:,ixrain), state%q(:,:,ixsnow), &
+ mgncol, mgcols)
+ end select
+
+ packer = MGPacker(psetcols, pver, mgcols, top_lev)
+ post_proc = MGPostProc(packer)
+
+ allocate(packed_rate1ord_cw2pr_st(mgncol,nlev))
+ pckdptr => packed_rate1ord_cw2pr_st ! workaround an apparent pgi compiler bug on goldbach
+ call post_proc%add_field(p(rate1cld), pckdptr)
+ allocate(packed_tlat(mgncol,nlev))
+ call post_proc%add_field(p(tlat), p(packed_tlat))
+ allocate(packed_qvlat(mgncol,nlev))
+ call post_proc%add_field(p(qvlat), p(packed_qvlat))
+ allocate(packed_qctend(mgncol,nlev))
+ call post_proc%add_field(p(qcten), p(packed_qctend))
+ allocate(packed_qitend(mgncol,nlev))
+ call post_proc%add_field(p(qiten), p(packed_qitend))
+ allocate(packed_nctend(mgncol,nlev))
+ call post_proc%add_field(p(ncten), p(packed_nctend))
+ allocate(packed_nitend(mgncol,nlev))
+ call post_proc%add_field(p(niten), p(packed_nitend))
+
+ if (micro_mg_version > 1) then
+ allocate(packed_qrtend(mgncol,nlev))
+ call post_proc%add_field(p(qrten), p(packed_qrtend))
+ allocate(packed_qstend(mgncol,nlev))
+ call post_proc%add_field(p(qsten), p(packed_qstend))
+ allocate(packed_nrtend(mgncol,nlev))
+ call post_proc%add_field(p(nrten), p(packed_nrtend))
+ allocate(packed_nstend(mgncol,nlev))
+ call post_proc%add_field(p(nsten), p(packed_nstend))
+ allocate(packed_umr(mgncol,nlev))
+ call post_proc%add_field(p(umr), p(packed_umr))
+ allocate(packed_ums(mgncol,nlev))
+ call post_proc%add_field(p(ums), p(packed_ums))
+ else if (micro_mg_sub_version == 0) then
+ allocate(packed_am_evp_st(mgncol,nlev))
+ call post_proc%add_field(p(am_evp_st), p(packed_am_evp_st))
+ end if
+
+ allocate(packed_prect(mgncol))
+ call post_proc%add_field(p(prect), p(packed_prect))
+ allocate(packed_preci(mgncol))
+ call post_proc%add_field(p(preci), p(packed_preci))
+ allocate(packed_nevapr(mgncol,nlev))
+ call post_proc%add_field(p(nevapr), p(packed_nevapr))
+ allocate(packed_evapsnow(mgncol,nlev))
+ call post_proc%add_field(p(evapsnow), p(packed_evapsnow))
+ allocate(packed_prain(mgncol,nlev))
+ call post_proc%add_field(p(prain), p(packed_prain))
+ allocate(packed_prodsnow(mgncol,nlev))
+ call post_proc%add_field(p(prodsnow), p(packed_prodsnow))
+ allocate(packed_cmeout(mgncol,nlev))
+ call post_proc%add_field(p(cmeice), p(packed_cmeout))
+ allocate(packed_qsout(mgncol,nlev))
+ call post_proc%add_field(p(qsout), p(packed_qsout))
+ allocate(packed_rflx(mgncol,nlev+1))
+ call post_proc%add_field(p(rflx), p(packed_rflx))
+ allocate(packed_sflx(mgncol,nlev+1))
+ call post_proc%add_field(p(sflx), p(packed_sflx))
+ allocate(packed_qrout(mgncol,nlev))
+ call post_proc%add_field(p(qrout), p(packed_qrout))
+ allocate(packed_qcsevap(mgncol,nlev))
+ call post_proc%add_field(p(qcsevap), p(packed_qcsevap))
+ allocate(packed_qisevap(mgncol,nlev))
+ call post_proc%add_field(p(qisevap), p(packed_qisevap))
+ allocate(packed_qvres(mgncol,nlev))
+ call post_proc%add_field(p(qvres), p(packed_qvres))
+ allocate(packed_cmei(mgncol,nlev))
+ call post_proc%add_field(p(cmeiout), p(packed_cmei))
+ allocate(packed_vtrmc(mgncol,nlev))
+ call post_proc%add_field(p(vtrmc), p(packed_vtrmc))
+ allocate(packed_vtrmi(mgncol,nlev))
+ call post_proc%add_field(p(vtrmi), p(packed_vtrmi))
+ allocate(packed_qcsedten(mgncol,nlev))
+ call post_proc%add_field(p(qcsedten), p(packed_qcsedten))
+ allocate(packed_qisedten(mgncol,nlev))
+ call post_proc%add_field(p(qisedten), p(packed_qisedten))
+ if (micro_mg_version > 1) then
+ allocate(packed_qrsedten(mgncol,nlev))
+ call post_proc%add_field(p(qrsedten), p(packed_qrsedten))
+ allocate(packed_qssedten(mgncol,nlev))
+ call post_proc%add_field(p(qssedten), p(packed_qssedten))
+ end if
+
+ allocate(packed_pra(mgncol,nlev))
+ call post_proc%add_field(p(prao), p(packed_pra))
+ allocate(packed_prc(mgncol,nlev))
+ call post_proc%add_field(p(prco), p(packed_prc))
+ allocate(packed_mnuccc(mgncol,nlev))
+ call post_proc%add_field(p(mnuccco), p(packed_mnuccc))
+ allocate(packed_mnucct(mgncol,nlev))
+ call post_proc%add_field(p(mnuccto), p(packed_mnucct))
+ allocate(packed_msacwi(mgncol,nlev))
+ call post_proc%add_field(p(msacwio), p(packed_msacwi))
+ allocate(packed_psacws(mgncol,nlev))
+ call post_proc%add_field(p(psacwso), p(packed_psacws))
+ allocate(packed_bergs(mgncol,nlev))
+ call post_proc%add_field(p(bergso), p(packed_bergs))
+ allocate(packed_berg(mgncol,nlev))
+ call post_proc%add_field(p(bergo), p(packed_berg))
+ allocate(packed_melt(mgncol,nlev))
+ call post_proc%add_field(p(melto), p(packed_melt))
+ allocate(packed_homo(mgncol,nlev))
+ call post_proc%add_field(p(homoo), p(packed_homo))
+ allocate(packed_qcres(mgncol,nlev))
+ call post_proc%add_field(p(qcreso), p(packed_qcres))
+ allocate(packed_prci(mgncol,nlev))
+ call post_proc%add_field(p(prcio), p(packed_prci))
+ allocate(packed_prai(mgncol,nlev))
+ call post_proc%add_field(p(praio), p(packed_prai))
+ allocate(packed_qires(mgncol,nlev))
+ call post_proc%add_field(p(qireso), p(packed_qires))
+ allocate(packed_mnuccr(mgncol,nlev))
+ call post_proc%add_field(p(mnuccro), p(packed_mnuccr))
+ allocate(packed_pracs(mgncol,nlev))
+ call post_proc%add_field(p(pracso), p(packed_pracs))
+ allocate(packed_meltsdt(mgncol,nlev))
+ call post_proc%add_field(p(meltsdt), p(packed_meltsdt))
+ allocate(packed_frzrdt(mgncol,nlev))
+ call post_proc%add_field(p(frzrdt), p(packed_frzrdt))
+ allocate(packed_mnuccd(mgncol,nlev))
+ call post_proc%add_field(p(mnuccdo), p(packed_mnuccd))
+ allocate(packed_nrout(mgncol,nlev))
+ call post_proc%add_field(p(nrout), p(packed_nrout))
+ allocate(packed_nsout(mgncol,nlev))
+ call post_proc%add_field(p(nsout), p(packed_nsout))
+
+ allocate(packed_refl(mgncol,nlev))
+ call post_proc%add_field(p(refl), p(packed_refl), fillvalue=-9999._r8)
+ allocate(packed_arefl(mgncol,nlev))
+ call post_proc%add_field(p(arefl), p(packed_arefl))
+ allocate(packed_areflz(mgncol,nlev))
+ call post_proc%add_field(p(areflz), p(packed_areflz))
+ allocate(packed_frefl(mgncol,nlev))
+ call post_proc%add_field(p(frefl), p(packed_frefl))
+ allocate(packed_csrfl(mgncol,nlev))
+ call post_proc%add_field(p(csrfl), p(packed_csrfl), fillvalue=-9999._r8)
+ allocate(packed_acsrfl(mgncol,nlev))
+ call post_proc%add_field(p(acsrfl), p(packed_acsrfl))
+ allocate(packed_fcsrfl(mgncol,nlev))
+ call post_proc%add_field(p(fcsrfl), p(packed_fcsrfl))
+
+ allocate(packed_rercld(mgncol,nlev))
+ call post_proc%add_field(p(rercld), p(packed_rercld))
+ allocate(packed_ncai(mgncol,nlev))
+ call post_proc%add_field(p(ncai), p(packed_ncai))
+ allocate(packed_ncal(mgncol,nlev))
+ call post_proc%add_field(p(ncal), p(packed_ncal))
+ allocate(packed_qrout2(mgncol,nlev))
+ call post_proc%add_field(p(qrout2), p(packed_qrout2))
+ allocate(packed_qsout2(mgncol,nlev))
+ call post_proc%add_field(p(qsout2), p(packed_qsout2))
+ allocate(packed_nrout2(mgncol,nlev))
+ call post_proc%add_field(p(nrout2), p(packed_nrout2))
+ allocate(packed_nsout2(mgncol,nlev))
+ call post_proc%add_field(p(nsout2), p(packed_nsout2))
+ allocate(packed_freqs(mgncol,nlev))
+ call post_proc%add_field(p(freqs), p(packed_freqs))
+ allocate(packed_freqr(mgncol,nlev))
+ call post_proc%add_field(p(freqr), p(packed_freqr))
+ allocate(packed_nfice(mgncol,nlev))
+ call post_proc%add_field(p(nfice), p(packed_nfice))
+ if (micro_mg_version /= 1 .or. micro_mg_sub_version /= 0) then
+ allocate(packed_qcrat(mgncol,nlev))
+ call post_proc%add_field(p(qcrat), p(packed_qcrat), fillvalue=1._r8)
+ end if
+
+ ! The following are all variables related to sizes, where it does not
+ ! necessarily make sense to average over time steps. Instead, we keep
+ ! the value from the last substep, which is what "accum_null" does.
+ allocate(packed_rel(mgncol,nlev))
+ call post_proc%add_field(p(rel), p(packed_rel), &
+ fillvalue=10._r8, accum_method=accum_null)
+ allocate(packed_rei(mgncol,nlev))
+ call post_proc%add_field(p(rei), p(packed_rei), &
+ fillvalue=25._r8, accum_method=accum_null)
+ allocate(packed_lambdac(mgncol,nlev))
+ call post_proc%add_field(p(lambdac), p(packed_lambdac), &
+ accum_method=accum_null)
+ allocate(packed_mu(mgncol,nlev))
+ call post_proc%add_field(p(mu), p(packed_mu), &
+ accum_method=accum_null)
+ allocate(packed_des(mgncol,nlev))
+ call post_proc%add_field(p(des), p(packed_des), &
+ accum_method=accum_null)
+ allocate(packed_dei(mgncol,nlev))
+ call post_proc%add_field(p(dei), p(packed_dei), &
+ accum_method=accum_null)
+ allocate(packed_prer_evap(mgncol,nlev))
+ call post_proc%add_field(p(prer_evap), p(packed_prer_evap), &
+ accum_method=accum_null)
+
+ ! Allocate all the dummies with MG sizes.
+ allocate(rel_fn_dum(mgncol,nlev))
+ allocate(dsout2_dum(mgncol,nlev))
+ allocate(drout_dum(mgncol,nlev))
+ allocate(reff_rain_dum(mgncol,nlev))
+ allocate(reff_snow_dum(mgncol,nlev))
+
+ ! Pack input variables that are not updated during substeps.
+ allocate(packed_relvar(mgncol,nlev))
+ packed_relvar = packer%pack(relvar)
+ allocate(packed_accre_enhan(mgncol,nlev))
+ packed_accre_enhan = packer%pack(accre_enhan)
+
+ allocate(packed_p(mgncol,nlev))
+ packed_p = packer%pack(state_loc%pmid)
+ allocate(packed_pdel(mgncol,nlev))
+ packed_pdel = packer%pack(state_loc%pdel)
+
+ allocate(packed_pint(mgncol,nlev+1))
+ packed_pint = packer%pack_interface(state_loc%pint)
+
+ allocate(packed_cldn(mgncol,nlev))
+ packed_cldn = packer%pack(ast)
+ allocate(packed_liqcldf(mgncol,nlev))
+ packed_liqcldf = packer%pack(alst_mic)
+ allocate(packed_icecldf(mgncol,nlev))
+ packed_icecldf = packer%pack(aist_mic)
+
+ allocate(packed_naai(mgncol,nlev))
+ packed_naai = packer%pack(naai)
+ allocate(packed_npccn(mgncol,nlev))
+ packed_npccn = packer%pack(npccn)
+
+ allocate(packed_rndst(mgncol,nlev,size(rndst, 3)))
+ packed_rndst = packer%pack(rndst)
+ allocate(packed_nacon(mgncol,nlev,size(nacon, 3)))
+ packed_nacon = packer%pack(nacon)
+
+ if (.not. do_cldice) then
+ allocate(packed_tnd_qsnow(mgncol,nlev))
+ packed_tnd_qsnow = packer%pack(tnd_qsnow)
+ allocate(packed_tnd_nsnow(mgncol,nlev))
+ packed_tnd_nsnow = packer%pack(tnd_nsnow)
+ allocate(packed_re_ice(mgncol,nlev))
+ packed_re_ice = packer%pack(re_ice)
+ else
+ nullify(packed_tnd_qsnow)
+ nullify(packed_tnd_nsnow)
+ nullify(packed_re_ice)
+ end if
+
+ if (use_hetfrz_classnuc) then
+ allocate(packed_frzimm(mgncol,nlev))
+ packed_frzimm = packer%pack(frzimm)
+ allocate(packed_frzcnt(mgncol,nlev))
+ packed_frzcnt = packer%pack(frzcnt)
+ allocate(packed_frzdep(mgncol,nlev))
+ packed_frzdep = packer%pack(frzdep)
+ else
+ nullify(packed_frzimm)
+ nullify(packed_frzcnt)
+ nullify(packed_frzdep)
+ end if
+
+ ! Allocate input variables that are updated during substeps.
+ allocate(packed_t(mgncol,nlev))
+ allocate(packed_q(mgncol,nlev))
+ allocate(packed_qc(mgncol,nlev))
+ allocate(packed_nc(mgncol,nlev))
+ allocate(packed_qi(mgncol,nlev))
+ allocate(packed_ni(mgncol,nlev))
+ if (micro_mg_version > 1) then
+ allocate(packed_qr(mgncol,nlev))
+ allocate(packed_nr(mgncol,nlev))
+ allocate(packed_qs(mgncol,nlev))
+ allocate(packed_ns(mgncol,nlev))
+ end if
+
+ do it = 1, num_steps
+
+ ! Pack input variables that are updated during substeps.
+ packed_t = packer%pack(state_loc%t)
+ packed_q = packer%pack(state_loc%q(:,:,1))
+ packed_qc = packer%pack(state_loc%q(:,:,ixcldliq))
+ packed_nc = packer%pack(state_loc%q(:,:,ixnumliq))
+ packed_qi = packer%pack(state_loc%q(:,:,ixcldice))
+ packed_ni = packer%pack(state_loc%q(:,:,ixnumice))
+ if (micro_mg_version > 1) then
+ packed_qr = packer%pack(state_loc%q(:,:,ixrain))
+ packed_nr = packer%pack(state_loc%q(:,:,ixnumrain))
+ packed_qs = packer%pack(state_loc%q(:,:,ixsnow))
+ packed_ns = packer%pack(state_loc%q(:,:,ixnumsnow))
+ end if
+
+ select case (micro_mg_version)
+ case (1)
+ select case (micro_mg_sub_version)
+ case (0)
+
+ call micro_mg_tend1_0( &
+ microp_uniform, mgncol, nlev, mgncol, 1, dtime/num_steps, &
+ packed_t, packed_q, packed_qc, packed_qi, packed_nc, &
+ packed_ni, packed_p, packed_pdel, packed_cldn, packed_liqcldf,&
+ packed_relvar, packed_accre_enhan, &
+ packed_icecldf, packed_rate1ord_cw2pr_st, packed_naai, packed_npccn, &
+ packed_rndst, packed_nacon, packed_tlat, packed_qvlat, packed_qctend, &
+ packed_qitend, packed_nctend, packed_nitend, packed_rel, rel_fn_dum, &
+ packed_rei, packed_prect, packed_preci, packed_nevapr, packed_evapsnow, packed_am_evp_st, &
+ packed_prain, packed_prodsnow, packed_cmeout, packed_dei, packed_mu, &
+ packed_lambdac, packed_qsout, packed_des, packed_rflx, packed_sflx, &
+ packed_qrout, reff_rain_dum, reff_snow_dum, packed_qcsevap, packed_qisevap, &
+ packed_qvres, packed_cmei, packed_vtrmc, packed_vtrmi, packed_qcsedten, &
+ packed_qisedten, packed_pra, packed_prc, packed_mnuccc, packed_mnucct, &
+ packed_msacwi, packed_psacws, packed_bergs, packed_berg, packed_melt, &
+ packed_homo, packed_qcres, packed_prci, packed_prai, packed_qires, &
+ packed_mnuccr, packed_pracs, packed_meltsdt, packed_frzrdt, packed_mnuccd, &
+ packed_nrout, packed_nsout, packed_refl, packed_arefl, packed_areflz, &
+ packed_frefl, packed_csrfl, packed_acsrfl, packed_fcsrfl, packed_rercld, &
+ packed_ncai, packed_ncal, packed_qrout2, packed_qsout2, packed_nrout2, &
+ packed_nsout2, drout_dum, dsout2_dum, packed_freqs,packed_freqr, &
+ packed_nfice, packed_prer_evap, do_cldice, errstring, &
+ packed_tnd_qsnow, packed_tnd_nsnow, packed_re_ice, &
+ packed_frzimm, packed_frzcnt, packed_frzdep)
+
+ case (5)
+
+ call micro_mg_tend1_5( &
+ mgncol, nlev, dtime/num_steps, &
+ packed_t, packed_q, &
+ packed_qc, packed_qi, &
+ packed_nc, packed_ni, &
+ packed_relvar, packed_accre_enhan, &
+ packed_p, packed_pdel, packed_pint, &
+ packed_cldn, packed_liqcldf, packed_icecldf, &
+ packed_rate1ord_cw2pr_st, packed_naai, packed_npccn, packed_rndst, packed_nacon, &
+ packed_tlat, packed_qvlat, packed_qctend, packed_qitend, packed_nctend, packed_nitend, &
+ packed_rel, rel_fn_dum, packed_rei, packed_prect, packed_preci, &
+ packed_nevapr, packed_evapsnow, packed_prain, packed_prodsnow, packed_cmeout, packed_dei, &
+ packed_mu, packed_lambdac, packed_qsout, packed_des, packed_rflx, packed_sflx, &
+ packed_qrout, reff_rain_dum, reff_snow_dum, &
+ packed_qcsevap, packed_qisevap, packed_qvres, packed_cmei, packed_vtrmc, packed_vtrmi, &
+ packed_qcsedten, packed_qisedten, packed_pra, packed_prc, packed_mnuccc, packed_mnucct, &
+ packed_msacwi, packed_psacws, packed_bergs, packed_berg, packed_melt, packed_homo, &
+ packed_qcres, packed_prci, packed_prai, packed_qires, &
+ packed_mnuccr, packed_pracs, packed_meltsdt, packed_frzrdt, packed_mnuccd, &
+ packed_nrout, packed_nsout, packed_refl, packed_arefl, packed_areflz, packed_frefl, &
+ packed_csrfl, packed_acsrfl, packed_fcsrfl, packed_rercld, &
+ packed_ncai, packed_ncal, packed_qrout2, packed_qsout2, packed_nrout2, packed_nsout2, &
+ drout_dum, dsout2_dum, packed_freqs, packed_freqr, packed_nfice, packed_qcrat, &
+ errstring, &
+ packed_tnd_qsnow, packed_tnd_nsnow, packed_re_ice, packed_prer_evap, &
+ packed_frzimm, packed_frzcnt, packed_frzdep)
+
+ end select
+ case(2)
+ select case (micro_mg_sub_version)
+ case (0)
+
+ call micro_mg_tend2_0( &
+ mgncol, nlev, dtime/num_steps,&
+ packed_t, packed_q, &
+ packed_qc, packed_qi, &
+ packed_nc, packed_ni, &
+ packed_qr, packed_qs, &
+ packed_nr, packed_ns, &
+ packed_relvar, packed_accre_enhan, &
+ packed_p, packed_pdel, &
+ packed_cldn, packed_liqcldf, packed_icecldf, &
+ packed_rate1ord_cw2pr_st, &
+ packed_naai, packed_npccn, &
+ packed_rndst, packed_nacon, &
+ packed_tlat, packed_qvlat, &
+ packed_qctend, packed_qitend, &
+ packed_nctend, packed_nitend, &
+ packed_qrtend, packed_qstend, &
+ packed_nrtend, packed_nstend, &
+ packed_rel, rel_fn_dum, packed_rei, &
+ packed_prect, packed_preci, &
+ packed_nevapr, packed_evapsnow, &
+ packed_prain, packed_prodsnow, &
+ packed_cmeout, packed_dei, &
+ packed_mu, packed_lambdac, &
+ packed_qsout, packed_des, &
+ packed_rflx, packed_sflx, packed_qrout, &
+ reff_rain_dum, reff_snow_dum, &
+ packed_qcsevap, packed_qisevap, packed_qvres, &
+ packed_cmei, packed_vtrmc, packed_vtrmi, &
+ packed_umr, packed_ums, &
+ packed_qcsedten, packed_qisedten, &
+ packed_qrsedten, packed_qssedten, &
+ packed_pra, packed_prc, &
+ packed_mnuccc, packed_mnucct, packed_msacwi, &
+ packed_psacws, packed_bergs, packed_berg, &
+ packed_melt, packed_homo, &
+ packed_qcres, packed_prci, packed_prai, &
+ packed_qires, packed_mnuccr, packed_pracs, &
+ packed_meltsdt, packed_frzrdt, packed_mnuccd, &
+ packed_nrout, packed_nsout, &
+ packed_refl, packed_arefl, packed_areflz, &
+ packed_frefl, packed_csrfl, packed_acsrfl, &
+ packed_fcsrfl, packed_rercld, &
+ packed_ncai, packed_ncal, &
+ packed_qrout2, packed_qsout2, &
+ packed_nrout2, packed_nsout2, &
+ drout_dum, dsout2_dum, &
+ packed_freqs, packed_freqr, &
+ packed_nfice, packed_qcrat, &
+ errstring, &
+ packed_tnd_qsnow,packed_tnd_nsnow,packed_re_ice,&
+ packed_prer_evap, &
+ packed_frzimm, packed_frzcnt, packed_frzdep )
+ end select
+ end select
+
+ call handle_errmsg(errstring, subname="micro_mg_tend")
+
+ call physics_ptend_init(ptend_loc, psetcols, "micro_mg", &
+ ls=.true., lq=lq)
+
+ ! Set local tendency.
+ ptend_loc%s = packer%unpack(packed_tlat, 0._r8)
+ ptend_loc%q(:,:,1) = packer%unpack(packed_qvlat, 0._r8)
+ ptend_loc%q(:,:,ixcldliq) = packer%unpack(packed_qctend, 0._r8)
+ ptend_loc%q(:,:,ixcldice) = packer%unpack(packed_qitend, 0._r8)
+ ptend_loc%q(:,:,ixnumliq) = packer%unpack(packed_nctend, &
+ -state_loc%q(:,:,ixnumliq)/(dtime/num_steps))
+ if (do_cldice) then
+ ptend_loc%q(:,:,ixnumice) = packer%unpack(packed_nitend, &
+ -state_loc%q(:,:,ixnumice)/(dtime/num_steps))
+ else
+ ! In this case, the tendency should be all 0.
+ if (any(packed_nitend /= 0._r8)) &
+ call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud ice,"// &
+ " but micro_mg_tend has ice number tendencies.")
+ ptend_loc%q(:,:,ixnumice) = 0._r8
+ end if
+
+ if (micro_mg_version > 1) then
+ ptend_loc%q(:,:,ixrain) = packer%unpack(packed_qrtend, 0._r8)
+ ptend_loc%q(:,:,ixsnow) = packer%unpack(packed_qstend, 0._r8)
+ ptend_loc%q(:,:,ixnumrain) = packer%unpack(packed_nrtend, &
+ -state_loc%q(:,:,ixnumrain)/(dtime/num_steps))
+ ptend_loc%q(:,:,ixnumsnow) = packer%unpack(packed_nstend, &
+ -state_loc%q(:,:,ixnumsnow)/(dtime/num_steps))
+ end if
+
+ ! Sum into overall ptend
+ call physics_ptend_sum(ptend_loc, ptend, ncol)
+
+ ! Update local state
+ call physics_update(state_loc, ptend_loc, dtime/num_steps)
+
+ ! Sum all outputs for averaging.
+ call post_proc%accumulate()
+
+ end do
+
+ ! Divide ptend by substeps.
+ call physics_ptend_scale(ptend, 1._r8/num_steps, ncol)
+
+ ! Use summed outputs to produce averages
+ call post_proc%process_and_unpack()
+
+ call post_proc%finalize()
+
+ if (associated(packed_tnd_qsnow)) deallocate(packed_tnd_qsnow)
+ if (associated(packed_tnd_nsnow)) deallocate(packed_tnd_nsnow)
+ if (associated(packed_re_ice)) deallocate(packed_re_ice)
+ if (associated(packed_frzimm)) deallocate(packed_frzimm)
+ if (associated(packed_frzcnt)) deallocate(packed_frzcnt)
+ if (associated(packed_frzdep)) deallocate(packed_frzdep)
+
+ ! Check to make sure that the microphysics code is respecting the flags that control
+ ! whether MG should be prognosing cloud ice and cloud liquid or not.
+ if (.not. do_cldice) then
+ if (any(ptend%q(:ncol,top_lev:pver,ixcldice) /= 0.0_r8)) &
+ call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud ice,"// &
+ " but micro_mg_tend has ice mass tendencies.")
+ if (any(ptend%q(:ncol,top_lev:pver,ixnumice) /= 0.0_r8)) &
+ call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud ice,"// &
+ " but micro_mg_tend has ice number tendencies.")
+ end if
+ if (.not. do_cldliq) then
+ if (any(ptend%q(:ncol,top_lev:pver,ixcldliq) /= 0.0_r8)) &
+ call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud liquid,"// &
+ " but micro_mg_tend has liquid mass tendencies.")
+ if (any(ptend%q(:ncol,top_lev:pver,ixnumliq) /= 0.0_r8)) &
+ call endrun("micro_mg_cam:ERROR - MG microphysics is configured not to prognose cloud liquid,"// &
+ " but micro_mg_tend has liquid number tendencies.")
+ end if
+
+ mnuccdohet = 0._r8
+ do k=top_lev,pver
+ do i=1,ncol
+ if (naai(i,k) > 0._r8) then
+ mnuccdohet(i,k) = mnuccdo(i,k) - (naai_hom(i,k)/naai(i,k))*mnuccdo(i,k)
+ end if
+ end do
+ end do
+
+ mgflxprc(:ncol,top_lev:pverp) = rflx(:ncol,top_lev:pverp) + sflx(:ncol,top_lev:pverp)
+ mgflxsnw(:ncol,top_lev:pverp) = sflx(:ncol,top_lev:pverp)
+
+ mgmrprc(:ncol,top_lev:pver) = qrout(:ncol,top_lev:pver) + qsout(:ncol,top_lev:pver)
+ mgmrsnw(:ncol,top_lev:pver) = qsout(:ncol,top_lev:pver)
+
+ !! calculate effective radius of convective liquid and ice using dcon and deicon (not used by code, not useful for COSP)
+ !! hard-coded as average of hard-coded values used for deep/shallow convective detrainment (near line 1502/1505)
+ cvreffliq(:ncol,top_lev:pver) = 9.0_r8
+ cvreffice(:ncol,top_lev:pver) = 37.0_r8
+
+ ! Reassign rate1 if modal aerosols
+ if (rate1_cw2pr_st_idx > 0) then
+ rate1ord_cw2pr_st(:ncol,top_lev:pver) = rate1cld(:ncol,top_lev:pver)
+ end if
+
+ ! Sedimentation velocity for liquid stratus cloud droplet
+ wsedl(:ncol,top_lev:pver) = vtrmc(:ncol,top_lev:pver)
+
+ ! Microphysical tendencies for use in the macrophysics at the next time step
+ CC_T(:ncol,top_lev:pver) = tlat(:ncol,top_lev:pver)/cpair
+ CC_qv(:ncol,top_lev:pver) = qvlat(:ncol,top_lev:pver)
+ CC_ql(:ncol,top_lev:pver) = qcten(:ncol,top_lev:pver)
+ CC_qi(:ncol,top_lev:pver) = qiten(:ncol,top_lev:pver)
+ CC_nl(:ncol,top_lev:pver) = ncten(:ncol,top_lev:pver)
+ CC_ni(:ncol,top_lev:pver) = niten(:ncol,top_lev:pver)
+ CC_qlst(:ncol,top_lev:pver) = qcten(:ncol,top_lev:pver)/max(0.01_r8,alst_mic(:ncol,top_lev:pver))
+
+ ! Net micro_mg_cam condensation rate
+ qme(:ncol,top_lev:pver) = cmeliq(:ncol,top_lev:pver) + cmeiout(:ncol,top_lev:pver)
+
+ ! For precip, accumulate only total precip in prec_pcw and snow_pcw variables.
+ ! Other precip output variables are set to 0
+ ! Do not subscript by ncol here, because in physpkg we divide the whole
+ ! array and need to avoid an FPE due to uninitialized data.
+ prec_pcw = prect
+ snow_pcw = preci
+ prec_sed = 0._r8
+ snow_sed = 0._r8
+ prec_str = prec_pcw + prec_sed
+ snow_str = snow_pcw + snow_sed
+
+ icecldf(:ncol,top_lev:pver) = ast(:ncol,top_lev:pver)
+ liqcldf(:ncol,top_lev:pver) = ast(:ncol,top_lev:pver)
+
+ ! ------------------------------------------------------------ !
+ ! Compute in cloud ice and liquid mixing ratios !
+ ! Note that 'iclwp, iciwp' are used for radiation computation. !
+ ! ------------------------------------------------------------ !
+
+ icinc = 0._r8
+ icwnc = 0._r8
+ iciwpst = 0._r8
+ iclwpst = 0._r8
+ icswp = 0._r8
+ cldfsnow = 0._r8
+
+ do k = top_lev, pver
+ do i = 1, ncol
+ ! Limits for in-cloud mixing ratios consistent with MG microphysics
+ ! in-cloud mixing ratio maximum limit of 0.005 kg/kg
+ icimrst(i,k) = min( state_loc%q(i,k,ixcldice) / max(mincld,icecldf(i,k)),0.005_r8 )
+ icwmrst(i,k) = min( state_loc%q(i,k,ixcldliq) / max(mincld,liqcldf(i,k)),0.005_r8 )
+ icinc(i,k) = state_loc%q(i,k,ixnumice) / max(mincld,icecldf(i,k)) * &
+ state_loc%pmid(i,k) / (287.15_r8*state_loc%t(i,k))
+ icwnc(i,k) = state_loc%q(i,k,ixnumliq) / max(mincld,liqcldf(i,k)) * &
+ state_loc%pmid(i,k) / (287.15_r8*state_loc%t(i,k))
+ ! Calculate micro_mg_cam cloud water paths in each layer
+ ! Note: uses stratiform cloud fraction!
+ iciwpst(i,k) = min(state_loc%q(i,k,ixcldice)/max(mincld,ast(i,k)),0.005_r8) * state_loc%pdel(i,k) / gravit
+ iclwpst(i,k) = min(state_loc%q(i,k,ixcldliq)/max(mincld,ast(i,k)),0.005_r8) * state_loc%pdel(i,k) / gravit
+
+ ! ------------------------------ !
+ ! Adjust cloud fraction for snow !
+ ! ------------------------------ !
+ cldfsnow(i,k) = cld(i,k)
+ ! If cloud and only ice ( no convective cloud or ice ), then set to 0.
+ if( ( cldfsnow(i,k) .gt. 1.e-4_r8 ) .and. &
+ ( concld(i,k) .lt. 1.e-4_r8 ) .and. &
+ ( state_loc%q(i,k,ixcldliq) .lt. 1.e-10_r8 ) ) then
+ cldfsnow(i,k) = 0._r8
+ end if
+ ! If no cloud and snow, then set to 0.25
+ if( ( cldfsnow(i,k) .lt. 1.e-4_r8 ) .and. ( qsout(i,k) .gt. 1.e-6_r8 ) ) then
+ cldfsnow(i,k) = 0.25_r8
+ end if
+ ! Calculate in-cloud snow water path
+ icswp(i,k) = qsout(i,k) / max( mincld, cldfsnow(i,k) ) * state_loc%pdel(i,k) / gravit
+ end do
+ end do
+
+ ! Calculate cloud fraction for prognostic precip sizes.
+ if (micro_mg_version > 1) then
+ ! Cloud fraction for purposes of precipitation is maximum cloud
+ ! fraction out of all the layers that the precipitation may be
+ ! falling down from.
+ cldmax = max(mincld, ast)
+ do k = top_lev+1, pver
+ where (state_loc%q(:ncol,k-1,ixrain) >= qsmall .or. &
+ state_loc%q(:ncol,k-1,ixsnow) >= qsmall)
+ cldmax(:ncol,k) = max(cldmax(:ncol,k-1), cldmax(:ncol,k))
+ end where
+ end do
+ end if
+
+ ! ------------------------------------------------------ !
+ ! ------------------------------------------------------ !
+ ! All code from here to the end is on grid columns only !
+ ! ------------------------------------------------------ !
+ ! ------------------------------------------------------ !
+
+ ! Average the fields which are needed later in this paramterization to be on the grid
+ if (use_subcol_microp) then
+ call subcol_field_avg(prec_str, ngrdcol, lchnk, prec_str_grid)
+ call subcol_field_avg(iclwpst, ngrdcol, lchnk, iclwpst_grid)
+ call subcol_field_avg(cvreffliq, ngrdcol, lchnk, cvreffliq_grid)
+ call subcol_field_avg(cvreffice, ngrdcol, lchnk, cvreffice_grid)
+ call subcol_field_avg(mgflxprc, ngrdcol, lchnk, mgflxprc_grid)
+ call subcol_field_avg(mgflxsnw, ngrdcol, lchnk, mgflxsnw_grid)
+ call subcol_field_avg(qme, ngrdcol, lchnk, qme_grid)
+ call subcol_field_avg(nevapr, ngrdcol, lchnk, nevapr_grid)
+ call subcol_field_avg(prain, ngrdcol, lchnk, prain_grid)
+ call subcol_field_avg(evapsnow, ngrdcol, lchnk, evpsnow_st_grid)
+
+ if (micro_mg_version == 1 .and. micro_mg_sub_version == 0) then
+ call subcol_field_avg(am_evp_st, ngrdcol, lchnk, am_evp_st_grid)
+ end if
+
+ ! Average fields which are not in pbuf
+ call subcol_field_avg(qrout, ngrdcol, lchnk, qrout_grid)
+ call subcol_field_avg(qsout, ngrdcol, lchnk, qsout_grid)
+ call subcol_field_avg(nsout, ngrdcol, lchnk, nsout_grid)
+ call subcol_field_avg(nrout, ngrdcol, lchnk, nrout_grid)
+ call subcol_field_avg(cld, ngrdcol, lchnk, cld_grid)
+ call subcol_field_avg(qcreso, ngrdcol, lchnk, qcreso_grid)
+ call subcol_field_avg(melto, ngrdcol, lchnk, melto_grid)
+ call subcol_field_avg(mnuccco, ngrdcol, lchnk, mnuccco_grid)
+ call subcol_field_avg(mnuccto, ngrdcol, lchnk, mnuccto_grid)
+ call subcol_field_avg(bergo, ngrdcol, lchnk, bergo_grid)
+ call subcol_field_avg(homoo, ngrdcol, lchnk, homoo_grid)
+ call subcol_field_avg(msacwio, ngrdcol, lchnk, msacwio_grid)
+ call subcol_field_avg(psacwso, ngrdcol, lchnk, psacwso_grid)
+ call subcol_field_avg(bergso, ngrdcol, lchnk, bergso_grid)
+ call subcol_field_avg(cmeiout, ngrdcol, lchnk, cmeiout_grid)
+ call subcol_field_avg(qireso, ngrdcol, lchnk, qireso_grid)
+ call subcol_field_avg(prcio, ngrdcol, lchnk, prcio_grid)
+ call subcol_field_avg(praio, ngrdcol, lchnk, praio_grid)
+ call subcol_field_avg(icwmrst, ngrdcol, lchnk, icwmrst_grid)
+ call subcol_field_avg(icimrst, ngrdcol, lchnk, icimrst_grid)
+ call subcol_field_avg(liqcldf, ngrdcol, lchnk, liqcldf_grid)
+ call subcol_field_avg(icecldf, ngrdcol, lchnk, icecldf_grid)
+ call subcol_field_avg(icwnc, ngrdcol, lchnk, icwnc_grid)
+ call subcol_field_avg(icinc, ngrdcol, lchnk, icinc_grid)
+ call subcol_field_avg(state_loc%pdel, ngrdcol, lchnk, pdel_grid)
+ call subcol_field_avg(prao, ngrdcol, lchnk, prao_grid)
+ call subcol_field_avg(prco, ngrdcol, lchnk, prco_grid)
+
+ call subcol_field_avg(state_loc%q(:,:,ixnumliq), ngrdcol, lchnk, nc_grid)
+ call subcol_field_avg(state_loc%q(:,:,ixnumice), ngrdcol, lchnk, ni_grid)
+
+ if (micro_mg_version > 1) then
+ call subcol_field_avg(cldmax, ngrdcol, lchnk, cldmax_grid)
+
+ call subcol_field_avg(state_loc%q(:,:,ixrain), ngrdcol, lchnk, qr_grid)
+ call subcol_field_avg(state_loc%q(:,:,ixnumrain), ngrdcol, lchnk, nr_grid)
+ call subcol_field_avg(state_loc%q(:,:,ixsnow), ngrdcol, lchnk, qs_grid)
+ call subcol_field_avg(state_loc%q(:,:,ixnumsnow), ngrdcol, lchnk, ns_grid)
+ end if
+
+ else
+ ! These pbuf fields need to be assigned. There is no corresponding subcol_field_avg
+ ! as they are reset before being used, so it would be a needless calculation
+ lambdac_grid => lambdac
+ mu_grid => mu
+ rel_grid => rel
+ rei_grid => rei
+ dei_grid => dei
+ des_grid => des
+
+ ! fields already on grids, so just assign
+ prec_str_grid => prec_str
+ iclwpst_grid => iclwpst
+ cvreffliq_grid => cvreffliq
+ cvreffice_grid => cvreffice
+ mgflxprc_grid => mgflxprc
+ mgflxsnw_grid => mgflxsnw
+ qme_grid => qme
+ nevapr_grid => nevapr
+ prain_grid => prain
+
+ if (micro_mg_version == 1 .and. micro_mg_sub_version == 0) then
+ am_evp_st_grid = am_evp_st
+ end if
+
+ evpsnow_st_grid = evapsnow
+ qrout_grid = qrout
+ qsout_grid = qsout
+ nsout_grid = nsout
+ nrout_grid = nrout
+ cld_grid = cld
+ qcreso_grid = qcreso
+ melto_grid = melto
+ mnuccco_grid = mnuccco
+ mnuccto_grid = mnuccto
+ bergo_grid = bergo
+ homoo_grid = homoo
+ msacwio_grid = msacwio
+ psacwso_grid = psacwso
+ bergso_grid = bergso
+ cmeiout_grid = cmeiout
+ qireso_grid = qireso
+ prcio_grid = prcio
+ praio_grid = praio
+ icwmrst_grid = icwmrst
+ icimrst_grid = icimrst
+ liqcldf_grid = liqcldf
+ icecldf_grid = icecldf
+ icwnc_grid = icwnc
+ icinc_grid = icinc
+ pdel_grid = state_loc%pdel
+ prao_grid = prao
+ prco_grid = prco
+
+ nc_grid = state_loc%q(:,:,ixnumliq)
+ ni_grid = state_loc%q(:,:,ixnumice)
+
+ if (micro_mg_version > 1) then
+ cldmax_grid = cldmax
+
+ qr_grid = state_loc%q(:,:,ixrain)
+ nr_grid = state_loc%q(:,:,ixnumrain)
+ qs_grid = state_loc%q(:,:,ixsnow)
+ ns_grid = state_loc%q(:,:,ixnumsnow)
+ end if
+
+ end if
+
+ ! If on subcolumns, average the rest of the pbuf fields which were modified on subcolumns but are not used further in
+ ! this parameterization (no need to assign in the non-subcolumn case -- the else step)
+ if (use_subcol_microp) then
+ call subcol_field_avg(snow_str, ngrdcol, lchnk, snow_str_grid)
+ call subcol_field_avg(prec_pcw, ngrdcol, lchnk, prec_pcw_grid)
+ call subcol_field_avg(snow_pcw, ngrdcol, lchnk, snow_pcw_grid)
+ call subcol_field_avg(prec_sed, ngrdcol, lchnk, prec_sed_grid)
+ call subcol_field_avg(snow_sed, ngrdcol, lchnk, snow_sed_grid)
+ call subcol_field_avg(cldo, ngrdcol, lchnk, cldo_grid)
+ call subcol_field_avg(mgmrprc, ngrdcol, lchnk, mgmrprc_grid)
+ call subcol_field_avg(mgmrsnw, ngrdcol, lchnk, mgmrsnw_grid)
+ call subcol_field_avg(wsedl, ngrdcol, lchnk, wsedl_grid)
+ call subcol_field_avg(cc_t, ngrdcol, lchnk, cc_t_grid)
+ call subcol_field_avg(cc_qv, ngrdcol, lchnk, cc_qv_grid)
+ call subcol_field_avg(cc_ql, ngrdcol, lchnk, cc_ql_grid)
+ call subcol_field_avg(cc_qi, ngrdcol, lchnk, cc_qi_grid)
+ call subcol_field_avg(cc_nl, ngrdcol, lchnk, cc_nl_grid)
+ call subcol_field_avg(cc_ni, ngrdcol, lchnk, cc_ni_grid)
+ call subcol_field_avg(cc_qlst, ngrdcol, lchnk, cc_qlst_grid)
+ call subcol_field_avg(iciwpst, ngrdcol, lchnk, iciwpst_grid)
+ call subcol_field_avg(icswp, ngrdcol, lchnk, icswp_grid)
+ call subcol_field_avg(cldfsnow, ngrdcol, lchnk, cldfsnow_grid)
+
+ if (rate1_cw2pr_st_idx > 0) then
+ call subcol_field_avg(rate1ord_cw2pr_st, ngrdcol, lchnk, rate1ord_cw2pr_st_grid)
+ end if
+
+ end if
+
+ ! ------------------------------------- !
+ ! Size distribution calculation !
+ ! ------------------------------------- !
+
+ ! Calculate rho (on subcolumns if turned on) for size distribution
+ ! parameter calculations and average it if needed
+ !
+ ! State instead of state_loc to preserve answers for MG1 (and in any
+ ! case, it is unlikely to make much difference).
+ rho(:ncol,top_lev:) = state%pmid(:ncol,top_lev:) / &
+ (rair*state%t(:ncol,top_lev:))
+ if (use_subcol_microp) then
+ call subcol_field_avg(rho, ngrdcol, lchnk, rho_grid)
+ else
+ rho_grid = rho
+ end if
+
+ ! Effective radius for cloud liquid, fixed number.
+ mu_grid = 0._r8
+ lambdac_grid = 0._r8
+ rel_fn_grid = 10._r8
+
+ ncic_grid = 1.e8_r8
+
+ call size_dist_param_liq(mg_liq_props, icwmrst_grid(:ngrdcol,top_lev:), &
+ ncic_grid(:ngrdcol,top_lev:), rho_grid(:ngrdcol,top_lev:), &
+ mu_grid(:ngrdcol,top_lev:), lambdac_grid(:ngrdcol,top_lev:))
+
+ where (icwmrst_grid(:ngrdcol,top_lev:) > qsmall)
+ rel_fn_grid(:ngrdcol,top_lev:) = &
+ (mu_grid(:ngrdcol,top_lev:) + 3._r8)/ &
+ lambdac_grid(:ngrdcol,top_lev:)/2._r8 * 1.e6_r8
+ end where
+
+ ! Effective radius for cloud liquid, and size parameters
+ ! mu_grid and lambdac_grid.
+ mu_grid = 0._r8
+ lambdac_grid = 0._r8
+ rel_grid = 10._r8
+
+ ! Calculate ncic on the grid
+ ncic_grid(:ngrdcol,top_lev:) = nc_grid(:ngrdcol,top_lev:) / &
+ max(mincld,liqcldf_grid(:ngrdcol,top_lev:))
+
+ call size_dist_param_liq(mg_liq_props, icwmrst_grid(:ngrdcol,top_lev:), &
+ ncic_grid(:ngrdcol,top_lev:), rho_grid(:ngrdcol,top_lev:), &
+ mu_grid(:ngrdcol,top_lev:), lambdac_grid(:ngrdcol,top_lev:))
+
+ where (icwmrst_grid(:ngrdcol,top_lev:) >= qsmall)
+ rel_grid(:ngrdcol,top_lev:) = &
+ (mu_grid(:ngrdcol,top_lev:) + 3._r8) / &
+ lambdac_grid(:ngrdcol,top_lev:)/2._r8 * 1.e6_r8
+ elsewhere
+ ! Deal with the fact that size_dist_param_liq sets mu_grid to -100
+ ! wherever there is no cloud.
+ mu_grid(:ngrdcol,top_lev:) = 0._r8
+ end where
+
+ ! Rain/Snow effective diameter.
+ drout2_grid = 0._r8
+ reff_rain_grid = 0._r8
+ des_grid = 0._r8
+ dsout2_grid = 0._r8
+ reff_snow_grid = 0._r8
+
+ if (micro_mg_version > 1) then
+ ! Prognostic precipitation
+
+ where (qr_grid(:ngrdcol,top_lev:) >= 1.e-7_r8)
+ drout2_grid(:ngrdcol,top_lev:) = avg_diameter( &
+ qr_grid(:ngrdcol,top_lev:), &
+ nr_grid(:ngrdcol,top_lev:) * rho_grid(:ngrdcol,top_lev:), &
+ rho_grid(:ngrdcol,top_lev:), rhow)
+
+ reff_rain_grid(:ngrdcol,top_lev:) = drout2_grid(:ngrdcol,top_lev:) * &
+ 1.5_r8 * 1.e6_r8
+ end where
+
+ where (qs_grid(:ngrdcol,top_lev:) >= 1.e-7_r8)
+ dsout2_grid(:ngrdcol,top_lev:) = avg_diameter( &
+ qs_grid(:ngrdcol,top_lev:), &
+ ns_grid(:ngrdcol,top_lev:) * rho_grid(:ngrdcol,top_lev:), &
+ rho_grid(:ngrdcol,top_lev:), rhosn)
+
+ des_grid(:ngrdcol,top_lev:) = dsout2_grid(:ngrdcol,top_lev:) *&
+ 3._r8 * rhosn/rhows
+
+ reff_snow_grid(:ngrdcol,top_lev:) = dsout2_grid(:ngrdcol,top_lev:) * &
+ 1.5_r8 * 1.e6_r8
+ end where
+
+ else
+ ! Diagnostic precipitation
+
+ where (qrout_grid(:ngrdcol,top_lev:) >= 1.e-7_r8)
+ drout2_grid(:ngrdcol,top_lev:) = avg_diameter( &
+ qrout_grid(:ngrdcol,top_lev:), &
+ nrout_grid(:ngrdcol,top_lev:) * rho_grid(:ngrdcol,top_lev:), &
+ rho_grid(:ngrdcol,top_lev:), rhow)
+
+ reff_rain_grid(:ngrdcol,top_lev:) = drout2_grid(:ngrdcol,top_lev:) * &
+ 1.5_r8 * 1.e6_r8
+ end where
+
+ where (qsout_grid(:ngrdcol,top_lev:) >= 1.e-7_r8)
+ dsout2_grid(:ngrdcol,top_lev:) = avg_diameter( &
+ qsout_grid(:ngrdcol,top_lev:), &
+ nsout_grid(:ngrdcol,top_lev:) * rho_grid(:ngrdcol,top_lev:), &
+ rho_grid(:ngrdcol,top_lev:), rhosn)
+
+ des_grid(:ngrdcol,top_lev:) = dsout2_grid(:ngrdcol,top_lev:) &
+ * 3._r8 * rhosn/rhows
+
+ reff_snow_grid(:ngrdcol,top_lev:) = &
+ dsout2_grid(:ngrdcol,top_lev:) * 1.5_r8 * 1.e6_r8
+ end where
+
+ end if
+
+ ! Effective radius and diameter for cloud ice.
+ rei_grid = 25._r8
+
+ niic_grid(:ngrdcol,top_lev:) = ni_grid(:ngrdcol,top_lev:) / &
+ max(mincld,icecldf_grid(:ngrdcol,top_lev:))
+
+ call size_dist_param_basic(mg_ice_props, icimrst_grid(:ngrdcol,top_lev:), &
+ niic_grid(:ngrdcol,top_lev:), rei_grid(:ngrdcol,top_lev:))
+
+ where (icimrst_grid(:ngrdcol,top_lev:) >= qsmall)
+ rei_grid(:ngrdcol,top_lev:) = 1.5_r8/rei_grid(:ngrdcol,top_lev:) &
+ * 1.e6_r8
+ elsewhere
+ rei_grid(:ngrdcol,top_lev:) = 25._r8
+ end where
+
+ dei_grid = rei_grid * rhoi/rhows * 2._r8
+
+ ! Limiters for low cloud fraction.
+ do k = top_lev, pver
+ do i = 1, ngrdcol
+ ! Convert snow effective diameter to microns
+ des_grid(i,k) = des_grid(i,k) * 1.e6_r8
+ if ( ast_grid(i,k) < 1.e-4_r8 ) then
+ mu_grid(i,k) = mucon
+ lambdac_grid(i,k) = (mucon + 1._r8)/dcon
+ dei_grid(i,k) = deicon
+ end if
+ end do
+ end do
+
+ mgreffrain_grid(:ngrdcol,top_lev:pver) = reff_rain_grid(:ngrdcol,top_lev:pver)
+ mgreffsnow_grid(:ngrdcol,top_lev:pver) = reff_snow_grid(:ngrdcol,top_lev:pver)
+
+ ! ------------------------------------- !
+ ! Precipitation efficiency Calculation !
+ ! ------------------------------------- !
+
+ !-----------------------------------------------------------------------
+ ! Liquid water path
+
+ ! Compute liquid water paths, and column condensation
+ tgliqwp_grid(:ngrdcol) = 0._r8
+ tgcmeliq_grid(:ngrdcol) = 0._r8
+ do k = top_lev, pver
+ do i = 1, ngrdcol
+ tgliqwp_grid(i) = tgliqwp_grid(i) + iclwpst_grid(i,k)*cld_grid(i,k)
+
+ if (cmeliq_grid(i,k) > 1.e-12_r8) then
+ !convert cmeliq to right units: kgh2o/kgair/s * kgair/m2 / kgh2o/m3 = m/s
+ tgcmeliq_grid(i) = tgcmeliq_grid(i) + cmeliq_grid(i,k) * &
+ (pdel_grid(i,k) / gravit) / rhoh2o
+ end if
+ end do
+ end do
+
+ ! note: 1e-6 kgho2/kgair/s * 1000. pa / (9.81 m/s2) / 1000 kgh2o/m3 = 1e-7 m/s
+ ! this is 1ppmv of h2o in 10hpa
+ ! alternatively: 0.1 mm/day * 1.e-4 m/mm * 1/86400 day/s = 1.e-9
+
+ !-----------------------------------------------------------------------
+ ! precipitation efficiency calculation (accumulate cme and precip)
+
+ minlwp = 0.01_r8 !minimum lwp threshold (kg/m3)
+
+ ! zero out precip efficiency and total averaged precip
+ pe_grid(:ngrdcol) = 0._r8
+ tpr_grid(:ngrdcol) = 0._r8
+ pefrac_grid(:ngrdcol) = 0._r8
+
+ ! accumulate precip and condensation
+ do i = 1, ngrdcol
+
+ acgcme_grid(i) = acgcme_grid(i) + tgcmeliq_grid(i)
+ acprecl_grid(i) = acprecl_grid(i) + prec_str_grid(i)
+ acnum_grid(i) = acnum_grid(i) + 1
+
+ ! if LWP is zero, then 'end of cloud': calculate precip efficiency
+ if (tgliqwp_grid(i) < minlwp) then
+ if (acprecl_grid(i) > 5.e-8_r8) then
+ tpr_grid(i) = max(acprecl_grid(i)/acnum_grid(i), 1.e-15_r8)
+ if (acgcme_grid(i) > 1.e-10_r8) then
+ pe_grid(i) = min(max(acprecl_grid(i)/acgcme_grid(i), 1.e-15_r8), 1.e5_r8)
+ pefrac_grid(i) = 1._r8
+ end if
+ end if
+
+ ! reset counters
+! if (pe_grid(i) /= 0._r8 .and. (pe_grid(i) < 1.e-8_r8 .or. pe_grid(i) > 1.e3_r8)) then
+! write (iulog,*) 'PE_grid:ANOMALY pe_grid, acprecl_grid, acgcme_grid, tpr_grid, acnum_grid ', &
+! pe_grid(i),acprecl_grid(i), acgcme_grid(i), tpr_grid(i), acnum_grid(i)
+! endif
+
+ acprecl_grid(i) = 0._r8
+ acgcme_grid(i) = 0._r8
+ acnum_grid(i) = 0
+ end if ! end LWP zero conditional
+
+ ! if never find any rain....(after 10^3 timesteps...)
+ if (acnum_grid(i) > 1000) then
+ acnum_grid(i) = 0
+ acprecl_grid(i) = 0._r8
+ acgcme_grid(i) = 0._r8
+ end if
+
+ end do
+
+ !-----------------------------------------------------------------------
+ ! vertical average of non-zero accretion, autoconversion and ratio.
+ ! vars: vprco_grid(i),vprao_grid(i),racau_grid(i),cnt_grid
+
+ vprao_grid = 0._r8
+ cnt_grid = 0
+ do k = top_lev, pver
+ vprao_grid(:ngrdcol) = vprao_grid(:ngrdcol) + prao_grid(:ngrdcol,k)
+ where (prao_grid(:ngrdcol,k) /= 0._r8) cnt_grid(:ngrdcol) = cnt_grid(:ngrdcol) + 1
+ end do
+
+ where (cnt_grid > 0) vprao_grid = vprao_grid/cnt_grid
+
+ vprco_grid = 0._r8
+ cnt_grid = 0
+ do k = top_lev, pver
+ vprco_grid(:ngrdcol) = vprco_grid(:ngrdcol) + prco_grid(:ngrdcol,k)
+ where (prco_grid(:ngrdcol,k) /= 0._r8) cnt_grid(:ngrdcol) = cnt_grid(:ngrdcol) + 1
+ end do
+
+ where (cnt_grid > 0)
+ vprco_grid = vprco_grid/cnt_grid
+ racau_grid = vprao_grid/vprco_grid
+ elsewhere
+ racau_grid = 0._r8
+ end where
+
+ racau_grid = min(racau_grid, 1.e10_r8)
+
+ ! --------------------- !
+ ! History Output Fields !
+ ! --------------------- !
+
+ ! Column droplet concentration
+ cdnumc_grid(:ngrdcol) = sum(nc_grid(:ngrdcol,top_lev:pver) * &
+ pdel_grid(:ngrdcol,top_lev:pver)/gravit, dim=2)
+
+ ! Averaging for new output fields
+ efcout_grid = 0._r8
+ efiout_grid = 0._r8
+ ncout_grid = 0._r8
+ niout_grid = 0._r8
+ freql_grid = 0._r8
+ freqi_grid = 0._r8
+ icwmrst_grid_out = 0._r8
+ icimrst_grid_out = 0._r8
+
+ do k = top_lev, pver
+ do i = 1, ngrdcol
+ if ( liqcldf_grid(i,k) > 0.01_r8 .and. icwmrst_grid(i,k) > 5.e-5_r8 ) then
+ efcout_grid(i,k) = rel_grid(i,k) * liqcldf_grid(i,k)
+ ncout_grid(i,k) = icwnc_grid(i,k) * liqcldf_grid(i,k)
+ freql_grid(i,k) = liqcldf_grid(i,k)
+ icwmrst_grid_out(i,k) = icwmrst_grid(i,k)
+ end if
+ if ( icecldf_grid(i,k) > 0.01_r8 .and. icimrst_grid(i,k) > 1.e-6_r8 ) then
+ efiout_grid(i,k) = rei_grid(i,k) * icecldf_grid(i,k)
+ niout_grid(i,k) = icinc_grid(i,k) * icecldf_grid(i,k)
+ freqi_grid(i,k) = icecldf_grid(i,k)
+ icimrst_grid_out(i,k) = icimrst_grid(i,k)
+ end if
+ end do
+ end do
+
+ ! Cloud top effective radius and number.
+ fcti_grid = 0._r8
+ fctl_grid = 0._r8
+ ctrel_grid = 0._r8
+ ctrei_grid = 0._r8
+ ctnl_grid = 0._r8
+ ctni_grid = 0._r8
+ do i = 1, ngrdcol
+ do k = top_lev, pver
+ if ( liqcldf_grid(i,k) > 0.01_r8 .and. icwmrst_grid(i,k) > 1.e-7_r8 ) then
+ ctrel_grid(i) = rel_grid(i,k) * liqcldf_grid(i,k)
+ ctnl_grid(i) = icwnc_grid(i,k) * liqcldf_grid(i,k)
+ fctl_grid(i) = liqcldf_grid(i,k)
+ exit
+ end if
+ if ( icecldf_grid(i,k) > 0.01_r8 .and. icimrst_grid(i,k) > 1.e-7_r8 ) then
+ ctrei_grid(i) = rei_grid(i,k) * icecldf_grid(i,k)
+ ctni_grid(i) = icinc_grid(i,k) * icecldf_grid(i,k)
+ fcti_grid(i) = icecldf_grid(i,k)
+ exit
+ end if
+ end do
+ end do
+
+ ! Evaporation of stratiform precipitation fields for UNICON
+ evprain_st_grid(:ngrdcol,:pver) = nevapr_grid(:ngrdcol,:pver) - evpsnow_st_grid(:ngrdcol,:pver)
+ do k = top_lev, pver
+ do i = 1, ngrdcol
+ evprain_st_grid(i,k) = max(evprain_st_grid(i,k), 0._r8)
+ evpsnow_st_grid(i,k) = max(evpsnow_st_grid(i,k), 0._r8)
+ end do
+ end do
+
+ ! Assign the values to the pbuf pointers if they exist in pbuf
+ if (qrain_idx > 0) qrout_grid_ptr = qrout_grid
+ if (qsnow_idx > 0) qsout_grid_ptr = qsout_grid
+ if (nrain_idx > 0) nrout_grid_ptr = nrout_grid
+ if (nsnow_idx > 0) nsout_grid_ptr = nsout_grid
+
+ ! --------------------------------------------- !
+ ! General outfield calls for microphysics !
+ ! --------------------------------------------- !
+
+ ! Output a handle of variables which are calculated on the fly
+ ftem_grid = 0._r8
+
+ ftem_grid(:ngrdcol,top_lev:pver) = qcreso_grid(:ngrdcol,top_lev:pver)
+ call outfld( 'MPDW2V', ftem_grid, pcols, lchnk)
+
+ ftem_grid(:ngrdcol,top_lev:pver) = melto_grid(:ngrdcol,top_lev:pver) - mnuccco_grid(:ngrdcol,top_lev:pver)&
- mnuccto_grid(:ngrdcol,top_lev:pver) - bergo_grid(:ngrdcol,top_lev:pver) - homoo_grid(:ngrdcol,top_lev:pver)&
- msacwio_grid(:ngrdcol,top_lev:pver)
- call outfld( 'MPDW2I', ftem_grid, pcols, lchnk)
+ call outfld( 'MPDW2I', ftem_grid, pcols, lchnk)
- ftem_grid(:ngrdcol,top_lev:pver) = -prao_grid(:ngrdcol,top_lev:pver) - prco_grid(:ngrdcol,top_lev:pver)&
+ ftem_grid(:ngrdcol,top_lev:pver) = -prao_grid(:ngrdcol,top_lev:pver) - prco_grid(:ngrdcol,top_lev:pver)&
- psacwso_grid(:ngrdcol,top_lev:pver) - bergso_grid(:ngrdcol,top_lev:pver)
- call outfld( 'MPDW2P', ftem_grid, pcols, lchnk)
-
- ftem_grid(:ngrdcol,top_lev:pver) = cmeiout_grid(:ngrdcol,top_lev:pver) + qireso_grid(:ngrdcol,top_lev:pver)
- call outfld( 'MPDI2V', ftem_grid, pcols, lchnk)
-
- ftem_grid(:ngrdcol,top_lev:pver) = -melto_grid(:ngrdcol,top_lev:pver) + mnuccco_grid(:ngrdcol,top_lev:pver) &
- + mnuccto_grid(:ngrdcol,top_lev:pver) + bergo_grid(:ngrdcol,top_lev:pver) + homoo_grid(:ngrdcol,top_lev:pver)&
- + msacwio_grid(:ngrdcol,top_lev:pver)
- call outfld( 'MPDI2W', ftem_grid, pcols, lchnk)
-
- ftem_grid(:ngrdcol,top_lev:pver) = -prcio_grid(:ngrdcol,top_lev:pver) - praio_grid(:ngrdcol,top_lev:pver)
- call outfld( 'MPDI2P', ftem_grid, pcols, lchnk)
-
- ! Output fields which have not been averaged already, averaging if use_subcol_microp is true
- call outfld('MPICLWPI', iclwpi, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MPICIWPI', iciwpi, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('REFL', refl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('AREFL', arefl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('AREFLZ', areflz, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('FREFL', frefl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('CSRFL', csrfl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('ACSRFL', acsrfl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('FCSRFL', fcsrfl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('RERCLD', rercld, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('NCAL', ncal, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('NCAI', ncai, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('AQRAIN', qrout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('AQSNOW', qsout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('ANRAIN', nrout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('ANSNOW', nsout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('FREQR', freqr, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('FREQS', freqs, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MPDT', tlat, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MPDQ', qvlat, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MPDLIQ', qcten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MPDICE', qiten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('EVAPSNOW', evapsnow, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('QCSEVAP', qcsevap, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('QISEVAP', qisevap, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('QVRES', qvres, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('VTRMC', vtrmc, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('VTRMI', vtrmi, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('QCSEDTEN', qcsedten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('QISEDTEN', qisedten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MNUCCDO', mnuccdo, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MNUCCDOhet', mnuccdohet, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MNUCCRO', mnuccro, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('PRACSO', pracso , psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('MELTSDT', meltsdt, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('FRZRDT', frzrdt , psetcols, lchnk, avg_subcol_field=use_subcol_microp)
- call outfld('FICE', nfice, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
-
- ! Example subcolumn outfld call
- if (use_subcol_microp) then
- call outfld('FICE_SCOL', nfice, psubcols*pcols, lchnk)
- end if
-
-
- ! Output fields which are already on the grid
- call outfld('QRAIN', qrout_grid, pcols, lchnk)
- call outfld('QSNOW', qsout_grid, pcols, lchnk)
- call outfld('NRAIN', nrout_grid, pcols, lchnk)
- call outfld('NSNOW', nsout_grid, pcols, lchnk)
- call outfld('CV_REFFLIQ', cvreffliq_grid, pcols, lchnk)
- call outfld('CV_REFFICE', cvreffice_grid, pcols, lchnk)
- call outfld('LS_FLXPRC', mgflxprc_grid, pcols, lchnk)
- call outfld('LS_FLXSNW', mgflxsnw_grid, pcols, lchnk)
- call outfld('CME', qme_grid, pcols, lchnk)
- call outfld('PRODPREC', prain_grid, pcols, lchnk)
- call outfld('EVAPPREC', nevapr_grid, pcols, lchnk)
- call outfld('QCRESO', qcreso_grid, pcols, lchnk)
- call outfld('LS_REFFRAIN', mgreffrain_grid, pcols, lchnk)
- call outfld('LS_REFFSNOW', mgreffsnow_grid, pcols, lchnk)
- call outfld('DSNOW', des_grid, pcols, lchnk)
- call outfld('ADRAIN', drout2_grid, pcols, lchnk)
- call outfld('ADSNOW', dsout2_grid, pcols, lchnk)
- call outfld('PE', pe_grid, pcols, lchnk)
- call outfld('PEFRAC', pefrac_grid, pcols, lchnk)
- call outfld('APRL', tpr_grid, pcols, lchnk)
- call outfld('VPRAO', vprao_grid, pcols, lchnk)
- call outfld('VPRCO', vprco_grid, pcols, lchnk)
- call outfld('RACAU', racau_grid, pcols, lchnk)
- call outfld('AREL', efcout_grid, pcols, lchnk)
- call outfld('AREI', efiout_grid, pcols, lchnk)
- call outfld('AWNC' , ncout_grid, pcols, lchnk)
- call outfld('AWNI' , niout_grid, pcols, lchnk)
- call outfld('FREQL', freql_grid, pcols, lchnk)
- call outfld('FREQI', freqi_grid, pcols, lchnk)
- call outfld('ACTREL', ctrel_grid, pcols, lchnk)
- call outfld('ACTREI', ctrei_grid, pcols, lchnk)
- call outfld('ACTNL', ctnl_grid, pcols, lchnk)
- call outfld('ACTNI', ctni_grid, pcols, lchnk)
- call outfld('FCTL', fctl_grid, pcols, lchnk)
- call outfld('FCTI', fcti_grid, pcols, lchnk)
- call outfld('ICINC', icinc_grid, pcols, lchnk)
- call outfld('ICWNC', icwnc_grid, pcols, lchnk)
- call outfld('EFFLIQ_IND', rel_fn_grid, pcols, lchnk)
- call outfld('CDNUMC', cdnumc_grid, pcols, lchnk)
- call outfld('REL', rel_grid, pcols, lchnk)
- call outfld('REI', rei_grid, pcols, lchnk)
- call outfld('ICIMRST', icimrst_grid_out, pcols, lchnk)
- call outfld('ICWMRST', icwmrst_grid_out, pcols, lchnk)
- call outfld('CMEIOUT', cmeiout_grid, pcols, lchnk)
- call outfld('PRAO', prao_grid, pcols, lchnk)
- call outfld('PRCO', prco_grid, pcols, lchnk)
- call outfld('MNUCCCO', mnuccco_grid, pcols, lchnk)
- call outfld('MNUCCTO', mnuccto_grid, pcols, lchnk)
- call outfld('MSACWIO', msacwio_grid, pcols, lchnk)
- call outfld('PSACWSO', psacwso_grid, pcols, lchnk)
- call outfld('BERGSO', bergso_grid, pcols, lchnk)
- call outfld('BERGO', bergo_grid, pcols, lchnk)
- call outfld('MELTO', melto_grid, pcols, lchnk)
- call outfld('HOMOO', homoo_grid, pcols, lchnk)
- call outfld('PRCIO', prcio_grid, pcols, lchnk)
- call outfld('PRAIO', praio_grid, pcols, lchnk)
- call outfld('QIRESO', qireso_grid, pcols, lchnk)
-
- ! ptend_loc is deallocated in physics_update above
- call physics_state_dealloc(state_loc)
+ call outfld( 'MPDW2P', ftem_grid, pcols, lchnk)
+
+ ftem_grid(:ngrdcol,top_lev:pver) = cmeiout_grid(:ngrdcol,top_lev:pver) + qireso_grid(:ngrdcol,top_lev:pver)
+ call outfld( 'MPDI2V', ftem_grid, pcols, lchnk)
+
+ ftem_grid(:ngrdcol,top_lev:pver) = -melto_grid(:ngrdcol,top_lev:pver) + mnuccco_grid(:ngrdcol,top_lev:pver) &
+ + mnuccto_grid(:ngrdcol,top_lev:pver) + bergo_grid(:ngrdcol,top_lev:pver) + homoo_grid(:ngrdcol,top_lev:pver)&
+ + msacwio_grid(:ngrdcol,top_lev:pver)
+ call outfld( 'MPDI2W', ftem_grid, pcols, lchnk)
+
+ ftem_grid(:ngrdcol,top_lev:pver) = -prcio_grid(:ngrdcol,top_lev:pver) - praio_grid(:ngrdcol,top_lev:pver)
+ call outfld( 'MPDI2P', ftem_grid, pcols, lchnk)
+
+ ! Output fields which have not been averaged already, averaging if use_subcol_microp is true
+ call outfld('MPICLWPI', iclwpi, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MPICIWPI', iciwpi, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('REFL', refl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('AREFL', arefl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('AREFLZ', areflz, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('FREFL', frefl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('CSRFL', csrfl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('ACSRFL', acsrfl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('FCSRFL', fcsrfl, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('RERCLD', rercld, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('NCAL', ncal, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('NCAI', ncai, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('AQRAIN', qrout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('AQSNOW', qsout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('ANRAIN', nrout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('ANSNOW', nsout2, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('FREQR', freqr, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('FREQS', freqs, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MPDT', tlat, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MPDQ', qvlat, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MPDLIQ', qcten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MPDICE', qiten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('EVAPSNOW', evapsnow, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('QCSEVAP', qcsevap, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('QISEVAP', qisevap, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('QVRES', qvres, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('VTRMC', vtrmc, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('VTRMI', vtrmi, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('QCSEDTEN', qcsedten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('QISEDTEN', qisedten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ if (micro_mg_version > 1) then
+ call outfld('QRSEDTEN', qrsedten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('QSSEDTEN', qssedten, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ end if
+ call outfld('MNUCCDO', mnuccdo, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MNUCCDOhet', mnuccdohet, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MNUCCRO', mnuccro, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('PRACSO', pracso , psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('MELTSDT', meltsdt, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('FRZRDT', frzrdt , psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('FICE', nfice, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+
+ if (micro_mg_version > 1) then
+ call outfld('UMR', umr, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ call outfld('UMS', ums, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ end if
+
+ if (.not. (micro_mg_version == 1 .and. micro_mg_sub_version == 0)) then
+ call outfld('QCRAT', qcrat, psetcols, lchnk, avg_subcol_field=use_subcol_microp)
+ end if
+
+ ! Example subcolumn outfld call
+ if (use_subcol_microp) then
+ call outfld('FICE_SCOL', nfice, psubcols*pcols, lchnk)
+ end if
+
+ ! Output fields which are already on the grid
+ call outfld('QRAIN', qrout_grid, pcols, lchnk)
+ call outfld('QSNOW', qsout_grid, pcols, lchnk)
+ call outfld('NRAIN', nrout_grid, pcols, lchnk)
+ call outfld('NSNOW', nsout_grid, pcols, lchnk)
+ call outfld('CV_REFFLIQ', cvreffliq_grid, pcols, lchnk)
+ call outfld('CV_REFFICE', cvreffice_grid, pcols, lchnk)
+ call outfld('LS_FLXPRC', mgflxprc_grid, pcols, lchnk)
+ call outfld('LS_FLXSNW', mgflxsnw_grid, pcols, lchnk)
+ call outfld('CME', qme_grid, pcols, lchnk)
+ call outfld('PRODPREC', prain_grid, pcols, lchnk)
+ call outfld('EVAPPREC', nevapr_grid, pcols, lchnk)
+ call outfld('QCRESO', qcreso_grid, pcols, lchnk)
+ call outfld('LS_REFFRAIN', mgreffrain_grid, pcols, lchnk)
+ call outfld('LS_REFFSNOW', mgreffsnow_grid, pcols, lchnk)
+ call outfld('DSNOW', des_grid, pcols, lchnk)
+ call outfld('ADRAIN', drout2_grid, pcols, lchnk)
+ call outfld('ADSNOW', dsout2_grid, pcols, lchnk)
+ call outfld('PE', pe_grid, pcols, lchnk)
+ call outfld('PEFRAC', pefrac_grid, pcols, lchnk)
+ call outfld('APRL', tpr_grid, pcols, lchnk)
+ call outfld('VPRAO', vprao_grid, pcols, lchnk)
+ call outfld('VPRCO', vprco_grid, pcols, lchnk)
+ call outfld('RACAU', racau_grid, pcols, lchnk)
+ call outfld('AREL', efcout_grid, pcols, lchnk)
+ call outfld('AREI', efiout_grid, pcols, lchnk)
+ call outfld('AWNC' , ncout_grid, pcols, lchnk)
+ call outfld('AWNI' , niout_grid, pcols, lchnk)
+ call outfld('FREQL', freql_grid, pcols, lchnk)
+ call outfld('FREQI', freqi_grid, pcols, lchnk)
+ call outfld('ACTREL', ctrel_grid, pcols, lchnk)
+ call outfld('ACTREI', ctrei_grid, pcols, lchnk)
+ call outfld('ACTNL', ctnl_grid, pcols, lchnk)
+ call outfld('ACTNI', ctni_grid, pcols, lchnk)
+ call outfld('FCTL', fctl_grid, pcols, lchnk)
+ call outfld('FCTI', fcti_grid, pcols, lchnk)
+ call outfld('ICINC', icinc_grid, pcols, lchnk)
+ call outfld('ICWNC', icwnc_grid, pcols, lchnk)
+ call outfld('EFFLIQ_IND', rel_fn_grid, pcols, lchnk)
+ call outfld('CDNUMC', cdnumc_grid, pcols, lchnk)
+ call outfld('REL', rel_grid, pcols, lchnk)
+ call outfld('REI', rei_grid, pcols, lchnk)
+ call outfld('ICIMRST', icimrst_grid_out, pcols, lchnk)
+ call outfld('ICWMRST', icwmrst_grid_out, pcols, lchnk)
+ call outfld('CMEIOUT', cmeiout_grid, pcols, lchnk)
+ call outfld('PRAO', prao_grid, pcols, lchnk)
+ call outfld('PRCO', prco_grid, pcols, lchnk)
+ call outfld('MNUCCCO', mnuccco_grid, pcols, lchnk)
+ call outfld('MNUCCTO', mnuccto_grid, pcols, lchnk)
+ call outfld('MSACWIO', msacwio_grid, pcols, lchnk)
+ call outfld('PSACWSO', psacwso_grid, pcols, lchnk)
+ call outfld('BERGSO', bergso_grid, pcols, lchnk)
+ call outfld('BERGO', bergo_grid, pcols, lchnk)
+ call outfld('MELTO', melto_grid, pcols, lchnk)
+ call outfld('HOMOO', homoo_grid, pcols, lchnk)
+ call outfld('PRCIO', prcio_grid, pcols, lchnk)
+ call outfld('PRAIO', praio_grid, pcols, lchnk)
+ call outfld('QIRESO', qireso_grid, pcols, lchnk)
+
+ ! ptend_loc is deallocated in physics_update above
+ call physics_state_dealloc(state_loc)
end subroutine micro_mg_cam_tend
+function p1(tin) result(pout)
+ real(r8), target, intent(in) :: tin(:)
+ real(r8), pointer :: pout(:)
+ pout => tin
+end function p1
+
+function p2(tin) result(pout)
+ real(r8), target, intent(in) :: tin(:,:)
+ real(r8), pointer :: pout(:,:)
+ pout => tin
+end function p2
+
end module micro_mg_cam
diff --git a/models/atm/cam/src/physics/cam/micro_mg_data.F90 b/models/atm/cam/src/physics/cam/micro_mg_data.F90
new file mode 100644
index 000000000000..9a4d0c4a5ed2
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/micro_mg_data.F90
@@ -0,0 +1,550 @@
+module micro_mg_data
+
+!
+! Packing and time averaging for the MG interface.
+!
+! Use is as follows:
+!
+! 1) Figure out which columns will do averaging (mgncol) and the number of
+! levels where the microphysics will run (nlev).
+!
+! 2) Create an MGPacker object and assign it as follows:
+!
+! packer = MGPacker(pcols, pver, mgcols, top_lev)
+!
+! Where [pcols, pver] is the shape of the ultimate input/output arrays
+! that are defined at level midpoints.
+!
+! 3) Create a post-processing array of type MGPostProc:
+!
+! post_proc = MGPostProc(packer)
+!
+! 4) Add pairs of pointers for packed and unpacked representations, already
+! associated with buffers of the correct dimensions:
+!
+! call post_proc%add_field(unpacked_pointer, packed_pointer, &
+! fillvalue, accum_mean)
+!
+! The third value is the default value used to "unpack" for points with
+! no "packed" part, and the fourth value is the method used to
+! accumulate values over time steps. These two arguments can be omitted,
+! in which case the default value will be 0 and the accumulation method
+! will take the mean.
+!
+! 5) Use the packed fields in MG, and for each MG iteration, do:
+!
+! call post_proc%accumulate()
+!
+! 6) Perform final accumulation and scatter values into the unpacked arrays:
+!
+! call post_proc%process_and_unpack()
+!
+! 7) Destroy the object when complete:
+!
+! call post_proc%finalize()
+!
+! Caveat: MGFieldPostProc will hit a divide-by-zero error if you try to
+! take the mean over 0 steps.
+!
+
+! This include header defines CPP macros that only have an effect for debug
+! builds.
+#include "shr_assert.h"
+
+use shr_kind_mod, only: r8 => shr_kind_r8
+use shr_log_mod, only: &
+ errMsg => shr_log_errMsg, &
+ OOBMsg => shr_log_OOBMsg
+use shr_sys_mod, only: shr_sys_abort
+
+implicit none
+private
+
+public :: MGPacker
+public :: MGFieldPostProc
+public :: accum_null
+public :: accum_mean
+public :: MGPostProc
+
+type :: MGPacker
+ ! Unpacked array dimensions.
+ integer :: pcols
+ integer :: pver
+ ! Calculated packed dimensions, stored for convenience.
+ integer :: mgncol
+ integer :: nlev
+ ! Which columns are packed.
+ integer, allocatable :: mgcols(:)
+ ! Topmost level to copy into the packed array.
+ integer :: top_lev
+ contains
+ procedure, private :: pack_1D
+ procedure, private :: pack_2D
+ procedure, private :: pack_3D
+ generic :: pack => pack_1D, pack_2D, pack_3D
+ procedure :: pack_interface
+ procedure, private :: unpack_1D
+ procedure, private :: unpack_1D_array_fill
+ procedure, private :: unpack_2D
+ procedure, private :: unpack_2D_array_fill
+ procedure, private :: unpack_3D
+ procedure, private :: unpack_3D_array_fill
+ generic :: unpack => unpack_1D, unpack_1D_array_fill, &
+ unpack_2D, unpack_2D_array_fill, unpack_3D, unpack_3D_array_fill
+ procedure :: finalize => MGPacker_finalize
+end type MGPacker
+
+interface MGPacker
+ module procedure new_MGPacker
+end interface
+
+! Enum for time accumulation/averaging methods.
+integer, parameter :: accum_null = 0
+integer, parameter :: accum_mean = 1
+
+type :: MGFieldPostProc
+ integer :: accum_method = -1
+ integer :: rank = -1
+ integer :: num_steps = 0
+ real(r8) :: fillvalue = 0._r8
+ real(r8), pointer :: unpacked_1D(:) => null()
+ real(r8), pointer :: packed_1D(:) => null()
+ real(r8), allocatable :: buffer_1D(:)
+ real(r8), pointer :: unpacked_2D(:,:) => null()
+ real(r8), pointer :: packed_2D(:,:) => null()
+ real(r8), allocatable :: buffer_2D(:,:)
+ contains
+ procedure :: accumulate => MGFieldPostProc_accumulate
+ procedure :: process_and_unpack => MGFieldPostProc_process_and_unpack
+ procedure :: unpack_only => MGFieldPostProc_unpack_only
+ procedure :: finalize => MGFieldPostProc_finalize
+end type MGFieldPostProc
+
+interface MGFieldPostProc
+ module procedure MGFieldPostProc_1D
+ module procedure MGFieldPostProc_2D
+end interface MGFieldPostProc
+
+#define VECTOR_NAME MGFieldPostProcVec
+#define TYPE_NAME type(MGFieldPostProc)
+#define THROW(string) call shr_sys_abort(string)
+
+public :: VECTOR_NAME
+
+#include "dynamic_vector_typedef.inc"
+
+type MGPostProc
+ type(MGPacker) :: packer
+ type(MGFieldPostProcVec) :: field_procs
+ contains
+ procedure, private :: add_field_1D
+ procedure, private :: add_field_2D
+ generic :: add_field => add_field_1D, add_field_2D
+ procedure :: accumulate => MGPostProc_accumulate
+ procedure :: process_and_unpack => MGPostProc_process_and_unpack
+ procedure :: unpack_only => MGPostProc_unpack_only
+ procedure :: finalize => MGPostProc_finalize
+ procedure, private :: MGPostProc_copy
+ generic :: assignment(=) => MGPostProc_copy
+end type MGPostProc
+
+interface MGPostProc
+ module procedure new_MGPostProc
+end interface MGPostProc
+
+contains
+
+function new_MGPacker(pcols, pver, mgcols, top_lev)
+ integer, intent(in) :: pcols, pver
+ integer, intent(in) :: mgcols(:)
+ integer, intent(in) :: top_lev
+
+ type(MGPacker) :: new_MGPacker
+
+ new_MGPacker%pcols = pcols
+ new_MGPacker%pver = pver
+ new_MGPacker%mgncol = size(mgcols)
+ new_MGPacker%nlev = pver - top_lev + 1
+
+ allocate(new_MGPacker%mgcols(new_MGPacker%mgncol))
+ new_MGPacker%mgcols = mgcols
+ new_MGPacker%top_lev = top_lev
+
+end function new_MGPacker
+
+! Rely on the fact that intent(out) forces the compiler to deallocate all
+! allocatable components and restart the type from scratch. Although
+! compiler support for finalization varies, this seems to be one of the few
+! cases where all major compilers are reliable, and humans are not.
+subroutine MGPacker_finalize(self)
+ class(MGPacker), intent(out) :: self
+end subroutine MGPacker_finalize
+
+function pack_1D(self, unpacked) result(packed)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: unpacked(:)
+
+ real(r8) :: packed(self%mgncol)
+
+ SHR_ASSERT(size(unpacked) == self%pcols, errMsg(__FILE__, __LINE__))
+
+ packed = unpacked(self%mgcols)
+
+end function pack_1D
+
+! Separation of pack and pack_interface is to workaround a PGI bug.
+function pack_2D(self, unpacked) result(packed)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: unpacked(:,:)
+
+ real(r8) :: packed(self%mgncol,self%nlev)
+
+ SHR_ASSERT(size(unpacked, 1) == self%pcols, errMsg(__FILE__, __LINE__))
+
+ packed = unpacked(self%mgcols,self%top_lev:)
+
+end function pack_2D
+
+function pack_interface(self, unpacked) result(packed)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: unpacked(:,:)
+
+ real(r8) :: packed(self%mgncol,self%nlev+1)
+
+ packed = unpacked(self%mgcols,self%top_lev:)
+
+end function pack_interface
+
+function pack_3D(self, unpacked) result(packed)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: unpacked(:,:,:)
+
+ real(r8) :: packed(self%mgncol,self%nlev,size(unpacked, 3))
+
+ SHR_ASSERT(size(unpacked,1) == self%pcols, errMsg(__FILE__, __LINE__))
+
+ packed = unpacked(self%mgcols,self%top_lev:,:)
+
+end function pack_3D
+
+function unpack_1D(self, packed, fill) result(unpacked)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: packed(:)
+ real(r8), intent(in) :: fill
+
+ real(r8) :: unpacked(self%pcols)
+
+ SHR_ASSERT(size(packed) == self%mgncol, errMsg(__FILE__, __LINE__))
+
+ unpacked = fill
+ unpacked(self%mgcols) = packed
+
+end function unpack_1D
+
+function unpack_1D_array_fill(self, packed, fill) result(unpacked)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: packed(:)
+ real(r8), intent(in) :: fill(:)
+
+ real(r8) :: unpacked(self%pcols)
+
+ SHR_ASSERT(size(packed) == self%mgncol, errMsg(__FILE__, __LINE__))
+
+ unpacked = fill
+ unpacked(self%mgcols) = packed
+
+end function unpack_1D_array_fill
+
+function unpack_2D(self, packed, fill) result(unpacked)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: packed(:,:)
+ real(r8), intent(in) :: fill
+
+ real(r8) :: unpacked(self%pcols,self%pver+size(packed, 2)-self%nlev)
+
+ SHR_ASSERT(size(packed, 1) == self%mgncol, errMsg(__FILE__, __LINE__))
+
+ unpacked = fill
+ unpacked(self%mgcols,self%top_lev:) = packed
+
+end function unpack_2D
+
+function unpack_2D_array_fill(self, packed, fill) result(unpacked)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: packed(:,:)
+ real(r8), intent(in) :: fill(:,:)
+
+ real(r8) :: unpacked(self%pcols,self%pver+size(packed, 2)-self%nlev)
+
+ SHR_ASSERT(size(packed, 1) == self%mgncol, errMsg(__FILE__, __LINE__))
+
+ unpacked = fill
+ unpacked(self%mgcols,self%top_lev:) = packed
+
+end function unpack_2D_array_fill
+
+function unpack_3D(self, packed, fill) result(unpacked)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: packed(:,:,:)
+ real(r8), intent(in) :: fill
+
+ real(r8) :: unpacked(self%pcols,self%pver,size(packed, 3))
+
+ SHR_ASSERT(size(packed, 1) == self%mgncol, errMsg(__FILE__, __LINE__))
+
+ unpacked = fill
+ unpacked(self%mgcols,self%top_lev:,:) = packed
+
+end function unpack_3D
+
+function unpack_3D_array_fill(self, packed, fill) result(unpacked)
+ class(MGPacker), intent(in) :: self
+ real(r8), intent(in) :: packed(:,:,:)
+ real(r8), intent(in) :: fill(:,:,:)
+
+ real(r8) :: unpacked(self%pcols,self%pver,size(packed, 3))
+
+ SHR_ASSERT(size(packed, 1) == self%mgncol, errMsg(__FILE__, __LINE__))
+
+ unpacked = fill
+ unpacked(self%mgcols,self%top_lev:,:) = packed
+
+end function unpack_3D_array_fill
+
+function MGFieldPostProc_1D(unpacked_ptr, packed_ptr, fillvalue, &
+ accum_method) result(field_proc)
+ real(r8), pointer, intent(in) :: unpacked_ptr(:)
+ real(r8), pointer, intent(in) :: packed_ptr(:)
+ real(r8), intent(in), optional :: fillvalue
+ integer, intent(in), optional :: accum_method
+ type(MGFieldPostProc) :: field_proc
+
+ field_proc%rank = 1
+ field_proc%unpacked_1D => unpacked_ptr
+ field_proc%packed_1D => packed_ptr
+ if (present(fillvalue)) then
+ field_proc%fillvalue = fillvalue
+ else
+ field_proc%fillvalue = 0._r8
+ end if
+ if (present(accum_method)) then
+ field_proc%accum_method = accum_method
+ else
+ field_proc%accum_method = accum_mean
+ end if
+
+end function MGFieldPostProc_1D
+
+function MGFieldPostProc_2D(unpacked_ptr, packed_ptr, fillvalue, &
+ accum_method) result(field_proc)
+ real(r8), pointer, intent(in) :: unpacked_ptr(:,:)
+ real(r8), pointer, intent(in) :: packed_ptr(:,:)
+ real(r8), intent(in), optional :: fillvalue
+ integer, intent(in), optional :: accum_method
+ type(MGFieldPostProc) :: field_proc
+
+ field_proc%rank = 2
+ field_proc%unpacked_2D => unpacked_ptr
+ field_proc%packed_2D => packed_ptr
+ if (present(fillvalue)) then
+ field_proc%fillvalue = fillvalue
+ else
+ field_proc%fillvalue = 0._r8
+ end if
+ if (present(accum_method)) then
+ field_proc%accum_method = accum_method
+ else
+ field_proc%accum_method = accum_mean
+ end if
+
+end function MGFieldPostProc_2D
+
+! Use the same intent(out) trick as for MGPacker, which is actually more
+! useful here.
+subroutine MGFieldPostProc_finalize(self)
+ class(MGFieldPostProc), intent(out) :: self
+end subroutine MGFieldPostProc_finalize
+
+subroutine MGFieldPostProc_accumulate(self)
+ class(MGFieldPostProc), intent(inout) :: self
+
+ select case (self%accum_method)
+ case (accum_null)
+ ! "Null" method does nothing.
+ case (accum_mean)
+ ! Allocation is done on the first accumulation step to allow the
+ ! MGFieldPostProc to be copied after construction without copying the
+ ! allocated array (until this function is first called).
+ self%num_steps = self%num_steps + 1
+ select case (self%rank)
+ case (1)
+ SHR_ASSERT(associated(self%packed_1D), errMsg(__FILE__, __LINE__))
+ if (.not. allocated(self%buffer_1D)) then
+ allocate(self%buffer_1D(size(self%packed_1D)))
+ self%buffer_1D = 0._r8
+ end if
+ self%buffer_1D = self%buffer_1D + self%packed_1D
+ case (2)
+ SHR_ASSERT(associated(self%packed_2D), errMsg(__FILE__, __LINE__))
+ if (.not. allocated(self%buffer_2D)) then
+ ! Awkward; in F2008 can be replaced by source/mold.
+ allocate(self%buffer_2D(&
+ size(self%packed_2D, 1),size(self%packed_2D, 2)))
+ self%buffer_2D = 0._r8
+ end if
+ self%buffer_2D = self%buffer_2D + self%packed_2D
+ case default
+ call shr_sys_abort(errMsg(__FILE__, __LINE__) // &
+ " Unsupported rank for MGFieldPostProc accumulation.")
+ end select
+ case default
+ call shr_sys_abort(errMsg(__FILE__, __LINE__) // &
+ " Unrecognized MGFieldPostProc accumulation method.")
+ end select
+
+end subroutine MGFieldPostProc_accumulate
+
+subroutine MGFieldPostProc_process_and_unpack(self, packer)
+ class(MGFieldPostProc), intent(inout) :: self
+ class(MGPacker), intent(in) :: packer
+
+ select case (self%accum_method)
+ case (accum_null)
+ ! "Null" method just leaves the value as the last time step, so don't
+ ! actually need to do anything.
+ case (accum_mean)
+ select case (self%rank)
+ case (1)
+ SHR_ASSERT(associated(self%packed_1D), errMsg(__FILE__, __LINE__))
+ self%packed_1D = self%buffer_1D/self%num_steps
+ case (2)
+ SHR_ASSERT(associated(self%packed_2D), errMsg(__FILE__, __LINE__))
+ self%packed_2D = self%buffer_2D/self%num_steps
+ case default
+ call shr_sys_abort(errMsg(__FILE__, __LINE__) // &
+ " Unsupported rank for MGFieldPostProc accumulation.")
+ end select
+ case default
+ call shr_sys_abort(errMsg(__FILE__, __LINE__) // &
+ " Unrecognized MGFieldPostProc accumulation method.")
+ end select
+
+ call self%unpack_only(packer)
+
+end subroutine MGFieldPostProc_process_and_unpack
+
+subroutine MGFieldPostProc_unpack_only(self, packer)
+ class(MGFieldPostProc), intent(inout) :: self
+ class(MGPacker), intent(in) :: packer
+
+ select case (self%rank)
+ case (1)
+ SHR_ASSERT(associated(self%unpacked_1D), errMsg(__FILE__, __LINE__))
+ self%unpacked_1D = packer%unpack(self%packed_1D, self%fillvalue)
+ case (2)
+ SHR_ASSERT(associated(self%unpacked_2D), errMsg(__FILE__, __LINE__))
+ self%unpacked_2D = packer%unpack(self%packed_2D, self%fillvalue)
+ case default
+ call shr_sys_abort(errMsg(__FILE__, __LINE__) // &
+ " Unsupported rank for MGFieldPostProc unpacking.")
+ end select
+
+end subroutine MGFieldPostProc_unpack_only
+
+#include "dynamic_vector_procdef.inc"
+
+function new_MGPostProc(packer) result(post_proc)
+ type(MGPacker), intent(in) :: packer
+
+ type(MGPostProc) :: post_proc
+
+ post_proc%packer = packer
+ call post_proc%field_procs%clear()
+
+end function new_MGPostProc
+
+! Can't use the same intent(out) trick, because PGI doesn't get the
+! recursive deallocation right.
+subroutine MGPostProc_finalize(self)
+ class(MGPostProc), intent(inout) :: self
+
+ integer :: i
+
+ call self%packer%finalize()
+ do i = 1, self%field_procs%vsize()
+ call self%field_procs%data(i)%finalize()
+ end do
+ call self%field_procs%clear()
+ call self%field_procs%shrink_to_fit()
+
+end subroutine MGPostProc_finalize
+
+subroutine add_field_1D(self, unpacked_ptr, packed_ptr, fillvalue, &
+ accum_method)
+ class(MGPostProc), intent(inout) :: self
+ real(r8), pointer, intent(in) :: unpacked_ptr(:)
+ real(r8), pointer, intent(in) :: packed_ptr(:)
+ real(r8), intent(in), optional :: fillvalue
+ integer, intent(in), optional :: accum_method
+
+ call self%field_procs%push_back(MGFieldPostProc(unpacked_ptr, &
+ packed_ptr, fillvalue, accum_method))
+
+end subroutine add_field_1D
+
+subroutine add_field_2D(self, unpacked_ptr, packed_ptr, fillvalue, &
+ accum_method)
+ class(MGPostProc), intent(inout) :: self
+ real(r8), pointer, intent(in) :: unpacked_ptr(:,:)
+ real(r8), pointer, intent(in) :: packed_ptr(:,:)
+ real(r8), intent(in), optional :: fillvalue
+ integer, intent(in), optional :: accum_method
+
+ call self%field_procs%push_back(MGFieldPostProc(unpacked_ptr, &
+ packed_ptr, fillvalue, accum_method))
+
+end subroutine add_field_2D
+
+subroutine MGPostProc_accumulate(self)
+ class(MGPostProc), intent(inout) :: self
+
+ integer :: i
+
+ do i = 1, self%field_procs%vsize()
+ call self%field_procs%data(i)%accumulate()
+ end do
+
+end subroutine MGPostProc_accumulate
+
+subroutine MGPostProc_process_and_unpack(self)
+ class(MGPostProc), intent(inout) :: self
+
+ integer :: i
+
+ do i = 1, self%field_procs%vsize()
+ call self%field_procs%data(i)%process_and_unpack(self%packer)
+ end do
+
+end subroutine MGPostProc_process_and_unpack
+
+subroutine MGPostProc_unpack_only(self)
+ class(MGPostProc), intent(inout) :: self
+
+ integer :: i
+
+ do i = 1, self%field_procs%vsize()
+ call self%field_procs%data(i)%unpack_only(self%packer)
+ end do
+
+end subroutine MGPostProc_unpack_only
+
+! This is necessary only to work around Intel/PGI bugs.
+subroutine MGPostProc_copy(lhs, rhs)
+ class(MGPostProc), intent(out) :: lhs
+ type(MGPostProc), intent(in) :: rhs
+
+ lhs%packer = rhs%packer
+ lhs%field_procs = rhs%field_procs
+end subroutine MGPostProc_copy
+
+end module micro_mg_data
diff --git a/models/atm/cam/src/physics/cam/micro_mg_utils.F90 b/models/atm/cam/src/physics/cam/micro_mg_utils.F90
index ef14ba9aeec3..55486a627b21 100644
--- a/models/atm/cam/src/physics/cam/micro_mg_utils.F90
+++ b/models/atm/cam/src/physics/cam/micro_mg_utils.F90
@@ -48,6 +48,7 @@ module micro_mg_utils
size_dist_param_liq, &
size_dist_param_basic, &
avg_diameter, &
+ rising_factorial, &
ice_deposition_sublimation, &
kk2000_liq_autoconversion, &
ice_autoconversion, &
@@ -115,9 +116,6 @@ module micro_mg_utils
real(r8), parameter, public :: rhow = 1000._r8 ! bulk density liquid
real(r8), parameter, public :: rhows = 917._r8 ! bulk density water solid
-! autoconversion size threshold for cloud ice to snow (m)
-real(r8) :: dcs
-
! fall speed parameters, V = aD^b (V is in m/s)
! droplets
real(r8), parameter, public :: ac = 3.e7_r8
@@ -133,8 +131,7 @@ module micro_mg_utils
real(r8), parameter, public :: br = 0.8_r8
! mass of new crystal due to aerosol freezing and growth (kg)
-real(r8), parameter, public :: mi0 = &
- 4._r8/3._r8*pi*rhoi*(10.e-6_r8)*(10.e-6_r8)*(10.e-6_r8)
+real(r8), parameter, public :: mi0 = 4._r8/3._r8*pi*rhoi*(10.e-6_r8)**3
!=================================================
! Private module parameters
@@ -153,9 +150,6 @@ module micro_mg_utils
real(r8), parameter :: dsph = 3._r8
! Bounds for mean diameter for different constituents.
-! (E.g. ice must be at least 10 microns but no more than twice the
-! threshold for autoconversion to snow.
-real(r8) :: lam_bnd_ice(2)
real(r8), parameter :: lam_bnd_rain(2) = 1._r8/[500.e-6_r8, 20.e-6_r8]
real(r8), parameter :: lam_bnd_snow(2) = 1._r8/[2000.e-6_r8, 10.e-6_r8]
@@ -173,7 +167,7 @@ module micro_mg_utils
! collection efficiencies
! aggregation of cloud ice and snow
-real(r8), parameter :: eii = 0.1_r8
+real(r8), parameter :: eii = 0.5_r8
! immersion freezing parameters, bigg 1953
real(r8), parameter :: bimm = 100._r8
@@ -201,6 +195,21 @@ module micro_mg_utils
real(r8) :: gamma_half_br_plus5
real(r8) :: gamma_half_bs_plus5
+!=========================================================
+! Utilities that are cheaper if the compiler knows that
+! some argument is an integer.
+!=========================================================
+
+interface rising_factorial
+ module procedure rising_factorial_r8
+ module procedure rising_factorial_integer
+end interface rising_factorial
+
+interface var_coef
+ module procedure var_coef_r8
+ module procedure var_coef_integer
+end interface var_coef
+
!==========================================================================
contains
!==========================================================================
@@ -216,7 +225,7 @@ module micro_mg_utils
! Check the list at the top of this module for descriptions of all other
! arguments.
subroutine micro_mg_utils_init( kind, rh2o, cpair, tmelt_in, latvap, &
- latice, errstring, dcs_in)
+ latice, dcs, errstring)
integer, intent(in) :: kind
real(r8), intent(in) :: rh2o
@@ -224,10 +233,14 @@ subroutine micro_mg_utils_init( kind, rh2o, cpair, tmelt_in, latvap, &
real(r8), intent(in) :: tmelt_in
real(r8), intent(in) :: latvap
real(r8), intent(in) :: latice
- real(r8), intent(in) :: dcs_in
+ real(r8), intent(in) :: dcs
character(128), intent(out) :: errstring
+ ! Name this array to workaround an XLF bug (otherwise could just use the
+ ! expression that sets it).
+ real(r8) :: ice_lambda_bounds(2)
+
!-----------------------------------------------------------------------
errstring = ' '
@@ -242,9 +255,6 @@ subroutine micro_mg_utils_init( kind, rh2o, cpair, tmelt_in, latvap, &
rv= rh2o ! water vapor gas constant
cpp = cpair ! specific heat of dry air
tmelt = tmelt_in
- dcs = dcs_in
- lam_bnd_ice(1) = 1._r8/(2._r8*dcs)
- lam_bnd_ice(2) = 1._r8/10.e-6_r8
! latent heats
@@ -259,8 +269,15 @@ subroutine micro_mg_utils_init( kind, rh2o, cpair, tmelt_in, latvap, &
! Don't specify lambda bounds for cloud liquid, as they are determined by
! pgam dynamically.
- mg_liq_props = MGHydrometeorProps(rhow, dsph, min_mean_mass=min_mean_mass_liq)
- mg_ice_props = MGHydrometeorProps(rhoi, dsph, lam_bnd_ice, min_mean_mass_ice)
+ mg_liq_props = MGHydrometeorProps(rhow, dsph, &
+ min_mean_mass=min_mean_mass_liq)
+
+ ! Mean ice diameter can not grow bigger than twice the autoconversion
+ ! threshold for snow.
+ ice_lambda_bounds = 1._r8/[2._r8*dcs, 10.e-6_r8]
+ mg_ice_props = MGHydrometeorProps(rhoi, dsph, &
+ ice_lambda_bounds, min_mean_mass_ice)
+
mg_rain_props = MGHydrometeorProps(rhow, dsph, lam_bnd_rain)
mg_snow_props = MGHydrometeorProps(rhosn, dsph, lam_bnd_snow)
@@ -294,6 +311,34 @@ end function NewMGHydrometeorProps
!FORMULAS
!========================================================================
+! Use gamma function to implement rising factorial extended to the reals.
+pure function rising_factorial_r8(x, n) result(res)
+ real(r8), intent(in) :: x, n
+ real(r8) :: res
+
+ res = gamma(x+n)/gamma(x)
+
+end function rising_factorial_r8
+
+! Rising factorial can be performed much cheaper if n is a small integer.
+pure function rising_factorial_integer(x, n) result(res)
+ real(r8), intent(in) :: x
+ integer, intent(in) :: n
+ real(r8) :: res
+
+ integer :: i
+ real(r8) :: factor
+
+ res = 1._r8
+ factor = x
+
+ do i = 1, n
+ res = res * factor
+ factor = factor + 1._r8
+ end do
+
+end function rising_factorial_integer
+
! Calculate correction due to latent heat for evaporation/sublimation
elemental function calc_ab(t, qv, xxl) result(ab)
real(r8), intent(in) :: t ! Temperature
@@ -329,6 +374,7 @@ elemental subroutine size_dist_param_liq(props, qcic, ncic, rho, pgam, lamc)
props_loc = props
! Get pgam from fit to observations of martin et al. 1994
+#if ! defined(CLUBB_BFB_S2) && ! defined(CLUBB_BFB_ALL)
pgam = 0.0005714_r8*(ncic/1.e6_r8*rho) + 0.2714_r8
pgam = 1._r8/(pgam**2) - 1._r8
pgam = max(pgam, 2._r8)
@@ -337,6 +383,21 @@ elemental subroutine size_dist_param_liq(props, qcic, ncic, rho, pgam, lamc)
! Set coefficient for use in size_dist_param_basic.
props_loc%shape_coef = pi * props_loc%rho / 6._r8 * &
rising_factorial(pgam+1._r8, props_loc%eff_dim)
+#else
+ pgam = 0.0005714_r8*1.e-6_r8*ncic*rho + 0.2714_r8
+ pgam = 1._r8/(pgam**2) - 1._r8
+ pgam = max(pgam, 2._r8)
+
+ ! Set coefficient for use in size_dist_param_basic.
+ ! The 3D case is so common and optimizable that we specialize it:
+ if (props_loc%eff_dim == 3._r8) then
+ props_loc%shape_coef = pi / 6._r8 * props_loc%rho * &
+ rising_factorial(pgam+1._r8, 3)
+ else
+ props_loc%shape_coef = pi / 6._r8 * props_loc%rho * &
+ rising_factorial(pgam+1._r8, props_loc%eff_dim)
+ end if
+#endif
! Limit to between 2 and 50 microns mean size.
props_loc%lambda_bounds = (pgam+1._r8)*1._r8/[50.e-6_r8, 2.e-6_r8]
@@ -351,17 +412,6 @@ elemental subroutine size_dist_param_liq(props, qcic, ncic, rho, pgam, lamc)
lamc = 0._r8
end if
-contains
-
- ! Use gamma function to implement rising factorial extended to the reals.
- elemental function rising_factorial(x, n)
- real(r8), intent(in) :: x, n
- real(r8) :: rising_factorial
-
- rising_factorial = gamma(x+n)/gamma(x)
-
- end function rising_factorial
-
end subroutine size_dist_param_liq
! Basic routine for getting size distribution parameters.
@@ -405,8 +455,9 @@ end subroutine size_dist_param_basic
real(r8) elemental function avg_diameter(q, n, rho_air, rho_sub)
! Finds the average diameter of particles given their density, and
! mass/number concentrations in the air.
+ ! Assumes that diameter follows an exponential distribution.
real(r8), intent(in) :: q ! mass mixing ratio
- real(r8), intent(in) :: n ! number concentration
+ real(r8), intent(in) :: n ! number concentration (per volume)
real(r8), intent(in) :: rho_air ! local density of the air
real(r8), intent(in) :: rho_sub ! density of the particle substance
@@ -414,15 +465,27 @@ real(r8) elemental function avg_diameter(q, n, rho_air, rho_sub)
end function avg_diameter
-real(r8) elemental function var_coef(relvar, a)
+elemental function var_coef_r8(relvar, a) result(res)
! Finds a coefficient for process rates based on the relative variance
! of cloud water.
real(r8), intent(in) :: relvar
real(r8), intent(in) :: a
+ real(r8) :: res
+
+ res = rising_factorial(relvar, a) / relvar**a
+
+end function var_coef_r8
+
+elemental function var_coef_integer(relvar, a) result(res)
+ ! Finds a coefficient for process rates based on the relative variance
+ ! of cloud water.
+ real(r8), intent(in) :: relvar
+ integer, intent(in) :: a
+ real(r8) :: res
- var_coef = gamma(relvar + a) / (gamma(relvar) * relvar**a)
+ res = rising_factorial(relvar, a) / relvar**a
-end function var_coef
+end function var_coef_integer
!========================================================================
!MICROPHYSICAL PROCESS CALCULATIONS
@@ -488,7 +551,7 @@ elemental subroutine ice_deposition_sublimation(t, qv, qi, ni, &
if (t < tmelt .and. vap_dep>0._r8) then
ice_sublim=0._r8
else
- !hm, make ice_sublim negative for consistency with other evap/sub processes
+ ! make ice_sublim negative for consistency with other evap/sub processes
ice_sublim=min(vap_dep,0._r8)
vap_dep=0._r8
end if
@@ -546,12 +609,12 @@ elemental subroutine kk2000_liq_autoconversion(microp_uniform, qcic, &
! assume exponential sub-grid distribution of qc, resulting in additional
! factor related to qcvar below
- ! hm switch for sub-columns, don't include sub-grid qc
+ ! switch for sub-columns, don't include sub-grid qc
prc = prc_coef * &
- 1350._r8 * qcic**2.47_r8 * (ncic/1.e6_r8*rho)**(-1.79_r8)
- nprc = prc/droplet_mass_25um
- nprc1 = prc/(qcic/ncic)
+ 1350._r8 * qcic**2.47_r8 * (ncic*1.e-6_r8*rho)**(-1.79_r8)
+ nprc = prc * (1._r8/droplet_mass_25um)
+ nprc1 = prc*ncic/qcic
else
prc=0._r8
@@ -565,12 +628,13 @@ end subroutine kk2000_liq_autoconversion
! Autoconversion of cloud ice to snow
! similar to Ferrier (1994)
-elemental subroutine ice_autoconversion(t, qiic, lami, n0i, prci, nprci)
+elemental subroutine ice_autoconversion(t, qiic, lami, n0i, dcs, prci, nprci)
real(r8), intent(in) :: t
real(r8), intent(in) :: qiic
real(r8), intent(in) :: lami
real(r8), intent(in) :: n0i
+ real(r8), intent(in) :: dcs
real(r8), intent(out) :: prci
real(r8), intent(out) :: nprci
@@ -578,17 +642,29 @@ elemental subroutine ice_autoconversion(t, qiic, lami, n0i, prci, nprci)
! Assume autoconversion timescale of 180 seconds.
real(r8), parameter :: ac_time = 180._r8
+ ! Average mass of an ice particle.
+ real(r8) :: m_ip
+ ! Ratio of autoconversion diameter to average diameter.
+ real(r8) :: d_rat
+
if (t <= tmelt .and. qiic >= qsmall) then
- nprci = n0i/(lami*ac_time)*exp(-lami*dcs)
+ d_rat = lami*dcs
+
+ ! Rate of ice particle conversion (number).
+ nprci = n0i/(lami*ac_time)*exp(-d_rat)
+
+ m_ip = (rhoi*pi/6._r8) / lami**3
- prci = pi*rhoi*n0i/(6._r8*ac_time)* &
- (dcs**3/lami+3._r8*dcs**2/lami**2+ &
- 6._r8*dcs/lami**3+6._r8/lami**4)*exp(-lami*dcs)
+ ! Rate of mass conversion.
+ ! Note that this is:
+ ! m n (d^3 + 3 d^2 + 6 d + 6)
+ prci = m_ip * nprci * &
+ (((d_rat + 3._r8)*d_rat + 6._r8)*d_rat + 6._r8)
else
- prci=0._r8
- nprci=0._r8
+ prci = 0._r8
+ nprci = 0._r8
end if
end subroutine ice_autoconversion
@@ -597,7 +673,7 @@ end subroutine ice_autoconversion
!===================================
elemental subroutine immersion_freezing(microp_uniform, t, pgam, lamc, &
- cdist1, qcic, relvar, mnuccc, nnuccc)
+ qcic, ncic, relvar, mnuccc, nnuccc)
logical, intent(in) :: microp_uniform
@@ -607,10 +683,10 @@ elemental subroutine immersion_freezing(microp_uniform, t, pgam, lamc, &
! Cloud droplet size distribution parameters
real(r8), intent(in) :: pgam
real(r8), intent(in) :: lamc
- real(r8), intent(in) :: cdist1
- ! MMR of in-cloud liquid water
+ ! MMR and number concentration of in-cloud liquid water
real(r8), intent(in) :: qcic
+ real(r8), intent(in) :: ncic
! Relative variance of cloud water
real(r8), intent(in) :: relvar
@@ -620,27 +696,24 @@ elemental subroutine immersion_freezing(microp_uniform, t, pgam, lamc, &
real(r8), intent(out) :: nnuccc ! Number
! Coefficients that will be omitted for sub-columns
- real(r8) :: dum, dum1
+ real(r8) :: dum
if (.not. microp_uniform) then
- dum = var_coef(relvar, 2._r8)
- dum1 = var_coef(relvar, 1._r8)
+ dum = var_coef(relvar, 2)
else
dum = 1._r8
- dum1 = 1._r8
end if
if (qcic >= qsmall .and. t < 269.15_r8) then
- mnuccc = dum * &
- pi*pi/36._r8*rhow* &
- cdist1*gamma(7._r8+pgam)* &
- bimm*(exp(aimm*(tmelt - t))-1._r8)/lamc**3/lamc**3
+ nnuccc = &
+ pi/6._r8*ncic*rising_factorial(pgam+1._r8, 3)* &
+ bimm*(exp(aimm*(tmelt - t))-1._r8)/lamc**3
- nnuccc = dum1 * &
- pi/6._r8*cdist1*gamma(pgam+4._r8) &
- *bimm*(exp(aimm*(tmelt - t))-1._r8)/lamc**3
+ mnuccc = dum * nnuccc * &
+ pi/6._r8*rhow* &
+ rising_factorial(pgam+4._r8, 3)/lamc**3
else
mnuccc = 0._r8
@@ -654,7 +727,7 @@ end subroutine immersion_freezing
! dust size and number in multiple bins are read in from companion routine
pure subroutine contact_freezing (microp_uniform, t, p, rndst, nacon, &
- pgam, lamc, cdist1, qcic, relvar, mnucct, nnucct)
+ pgam, lamc, qcic, ncic, relvar, mnucct, nnucct)
logical, intent(in) :: microp_uniform
@@ -666,10 +739,10 @@ pure subroutine contact_freezing (microp_uniform, t, p, rndst, nacon, &
! Size distribution parameters for cloud droplets
real(r8), intent(in) :: pgam(:)
real(r8), intent(in) :: lamc(:)
- real(r8), intent(in) :: cdist1(:)
- ! MMR of in-cloud liquid water
+ ! MMR and number concentration of in-cloud liquid water
real(r8), intent(in) :: qcic(:)
+ real(r8), intent(in) :: ncic(:)
! Relative cloud water variance
real(r8), intent(in) :: relvar(:)
@@ -689,6 +762,9 @@ pure subroutine contact_freezing (microp_uniform, t, p, rndst, nacon, &
! Coefficients not used for subcolumns
real(r8) :: dum, dum1
+ ! Common factor between mass and number.
+ real(r8) :: contact_factor
+
integer :: i
do i = 1,size(t)
@@ -713,13 +789,13 @@ pure subroutine contact_freezing (microp_uniform, t, p, rndst, nacon, &
ndfaer = 1.381e-23_r8*t(i)*nslip/(6._r8*pi*viscosity*rndst(i,:)) ! aerosol diffusivity (m2/s)
- mnucct(i) = dum * &
- dot_product(ndfaer,nacon(i,:)*tcnt)*pi*pi/3._r8*rhow* &
- cdist1(i)*gamma(pgam(i)+5._r8)/lamc(i)**4
+ contact_factor = dot_product(ndfaer,nacon(i,:)*tcnt) * pi * &
+ ncic(i) * (pgam(i) + 1._r8) / lamc(i)
+
+ mnucct(i) = dum * contact_factor * &
+ pi/3._r8*rhow*rising_factorial(pgam(i)+2._r8, 3)/lamc(i)**3
- nnucct(i) = dum1 * &
- dot_product(ndfaer,nacon(i,:)*tcnt)*2._r8*pi* &
- cdist1(i)*gamma(pgam(i)+2._r8)/lamc(i)
+ nnucct(i) = dum1 * 2._r8 * contact_factor
else
@@ -751,10 +827,8 @@ elemental subroutine snow_self_aggregation(t, rho, asn, rhosn, qsic, nsic, nsagg
real(r8), intent(out) :: nsagg
if (qsic >= qsmall .and. t <= tmelt) then
- nsagg = -1108._r8*asn*eii* &
- pi**((1._r8-bs)/3._r8)*rhosn**((-2._r8-bs)/3._r8)* &
- rho**((2._r8+bs)/3._r8)*qsic**((2._r8+bs)/3._r8)* &
- (nsic*rho)**((4._r8-bs)/3._r8) /(4._r8*720._r8*rho)
+ nsagg = -1108._r8*eii/(4._r8*720._r8*rhosn)*asn*qsic*nsic*rho*&
+ ((qsic/nsic)*(1._r8/(rhosn*pi)))**((bs-1._r8)/3._r8)
else
nsagg=0._r8
end if
@@ -800,6 +874,9 @@ elemental subroutine accrete_cloud_water_snow(t, rho, asn, uns, mu, qcic, ncic,
real(r8) :: dum
real(r8) :: eci ! collection efficiency for riming of snow by droplets
+ ! Fraction of cloud droplets accreted per second
+ real(r8) :: accrete_rate
+
! ignore collision of snow with droplets above freezing
if (qsic >= qsmall .and. t <= tmelt .and. qcic >= qsmall) then
@@ -810,7 +887,7 @@ elemental subroutine accrete_cloud_water_snow(t, rho, asn, uns, mu, qcic, ncic,
! collection efficiency is approximation based on stoke's law (Thompson et al. 2004)
dc0 = (pgam+1._r8)/lamc
- dum = dc0*dc0*uns*rhow/(9._r8*mu*(1._r8/lams))
+ dum = dc0*dc0*uns*rhow*lams/(9._r8*mu)
eci = dum*dum/((dum+0.4_r8)*(dum+0.4_r8))
eci = max(eci,0._r8)
@@ -818,9 +895,9 @@ elemental subroutine accrete_cloud_water_snow(t, rho, asn, uns, mu, qcic, ncic,
! no impact of sub-grid distribution of qc since psacws
! is linear in qc
-
- psacws = pi/4._r8*asn*qcic*rho*n0s*eci*gamma_bs_plus3 / lams**(bs+3._r8)
- npsacws = pi/4._r8*asn*ncic*rho*n0s*eci*gamma_bs_plus3 / lams**(bs+3._r8)
+ accrete_rate = pi/4._r8*asn*rho*n0s*eci*gamma_bs_plus3 / lams**(bs+3._r8)
+ psacws = accrete_rate*qcic
+ npsacws = accrete_rate*ncic
else
psacws = 0._r8
npsacws = 0._r8
@@ -844,16 +921,14 @@ elemental subroutine secondary_ice_production(t, psacws, msacwi, nsacwi)
if((t < 270.16_r8) .and. (t >= 268.16_r8)) then
nsacwi = 3.5e8_r8*(270.16_r8-t)/2.0_r8*psacws
- msacwi = min(nsacwi*mi0, psacws)
else if((t < 268.16_r8) .and. (t >= 265.16_r8)) then
nsacwi = 3.5e8_r8*(t-265.16_r8)/3.0_r8*psacws
- msacwi = min(nsacwi*mi0, psacws)
else
nsacwi = 0.0_r8
- msacwi = 0.0_r8
endif
- psacws = max(0.0_r8,psacws - nsacwi*mi0)
+ msacwi = min(nsacwi*mi0, psacws)
+ psacws = psacws - msacwi
end subroutine secondary_ice_production
@@ -894,21 +969,24 @@ elemental subroutine accrete_rain_snow(t, rho, umr, ums, unr, uns, qric, qsic, &
! Collection efficiency for accretion of rain by snow
real(r8), parameter :: ecr = 1.0_r8
+ ! Ratio of average snow diameter to average rain diameter.
+ real(r8) :: d_rat
+ ! Common factor between mass and number expressions
+ real(r8) :: common_factor
+
if (qric >= icsmall .and. qsic >= icsmall .and. t <= tmelt) then
- pracs = pi*pi*ecr*(((1.2_r8*umr-0.95_r8*ums)**2 + &
- 0.08_r8*ums*umr)**0.5_r8 * &
- rhow * rho * n0r * n0s * &
- (5._r8/(lamr**6 * lams)+ &
- 2._r8/(lamr**5 * lams**2)+ &
- 0.5_r8/(lamr**4 * lams**3)))
+ common_factor = pi*ecr*rho*n0r*n0s/(lamr**3 * lams)
+
+ d_rat = lamr/lams
+
+ pracs = common_factor*pi*rhow* &
+ sqrt((1.2_r8*umr-0.95_r8*ums)**2 + 0.08_r8*ums*umr) / lamr**3 * &
+ ((0.5_r8*d_rat + 2._r8)*d_rat + 5._r8)
- npracs = pi/2._r8*rho*ecr* (1.7_r8*(unr-uns)**2 + &
- 0.3_r8*unr*uns)**0.5_r8 * &
- n0r*n0s* &
- (1._r8/(lamr**3 * lams)+ &
- 1._r8/(lamr**2 * lams**2)+ &
- 1._r8/(lamr * lams**3))
+ npracs = common_factor*0.5_r8* &
+ sqrt(1.7_r8*(unr-uns)**2 + 0.3_r8*unr*uns) * &
+ ((d_rat + 1._r8)*d_rat + 1._r8)
else
pracs = 0._r8
@@ -936,14 +1014,11 @@ elemental subroutine heterogeneous_rain_freezing(t, qric, nric, lamr, mnuccr, nn
if (t < 269.15_r8 .and. qric >= qsmall) then
- ! Division by lamr**3 twice is old workaround to avoid overflow.
- ! Probably no longer necessary
- mnuccr = 20._r8*pi*pi*rhow*nric*bimm* &
- (exp(aimm*(tmelt - t))-1._r8)/lamr**3 &
- /lamr**3
-
nnuccr = pi*nric*bimm* &
(exp(aimm*(tmelt - t))-1._r8)/lamr**3
+
+ mnuccr = nnuccr * 20._r8*pi*rhow/lamr**3
+
else
mnuccr = 0._r8
nnuccr = 0._r8
@@ -989,7 +1064,7 @@ elemental subroutine accrete_cloud_water_rain(microp_uniform, qric, qcic, &
! include sub-grid distribution of cloud water
pra = pra_coef * 67._r8*(qcic*qric)**1.15_r8
- npra = pra/(qcic/ncic)
+ npra = pra*ncic/qcic
else
pra = 0._r8
@@ -1047,13 +1122,17 @@ elemental subroutine accrete_cloud_ice_snow(t, rho, asn, qiic, niic, qsic, &
real(r8), intent(out) :: prai ! MMR
real(r8), intent(out) :: nprai ! Number
+ ! Fraction of cloud ice particles accreted per second
+ real(r8) :: accrete_rate
+
if (qsic >= qsmall .and. qiic >= qsmall .and. t <= tmelt) then
- prai = pi/4._r8 * asn * qiic * rho * n0s * eii * gamma_bs_plus3/ &
+ accrete_rate = pi/4._r8 * eii * asn * rho * n0s * gamma_bs_plus3/ &
lams**(bs+3._r8)
- nprai = pi/4._r8 * asn * niic * rho * n0s * eii * gamma_bs_plus3/ &
- lams**(bs+3._r8)
+ prai = accrete_rate * qiic
+ nprai = accrete_rate * niic
+
else
prai = 0._r8
nprai = 0._r8
@@ -1068,7 +1147,7 @@ end subroutine accrete_cloud_ice_snow
! except for transfer of cloud water to snow through bergeron process
elemental subroutine evaporate_sublimate_precip(t, rho, dv, mu, sc, q, qvl, qvi, &
- lcldm, cldmax, arn, asn, qcic, qiic, qric, qsic, lamr, n0r, lams, n0s, &
+ lcldm, precip_frac, arn, asn, qcic, qiic, qric, qsic, lamr, n0r, lams, n0s, &
pre, prds)
real(r8), intent(in) :: t ! temperature
@@ -1080,7 +1159,7 @@ elemental subroutine evaporate_sublimate_precip(t, rho, dv, mu, sc, q, qvl, qvi,
real(r8), intent(in) :: qvl ! saturation humidity (water)
real(r8), intent(in) :: qvi ! saturation humidity (ice)
real(r8), intent(in) :: lcldm ! liquid cloud fraction
- real(r8), intent(in) :: cldmax ! precipitation fraction (maximum overlap)
+ real(r8), intent(in) :: precip_frac ! precipitation fraction (maximum overlap)
! fallspeed parameters
real(r8), intent(in) :: arn ! rain
@@ -1121,7 +1200,7 @@ elemental subroutine evaporate_sublimate_precip(t, rho, dv, mu, sc, q, qvl, qvi,
! only calculate if there is some precip fraction > cloud fraction
- if (cldmax > dum) then
+ if (precip_frac > dum) then
! calculate q for out-of-cloud region
qclr=(q-dum*qvl)/(1._r8-dum)
@@ -1139,9 +1218,9 @@ elemental subroutine evaporate_sublimate_precip(t, rho, dv, mu, sc, q, qvl, qvi,
pre = eps*(qclr-qvl)/ab
! only evaporate in out-of-cloud region
- ! and distribute across cldmax
- pre=min(pre*(cldmax-dum),0._r8)
- pre=pre/cldmax
+ ! and distribute across precip_frac
+ pre=min(pre*(precip_frac-dum),0._r8)
+ pre=pre/precip_frac
else
pre = 0._r8
end if
@@ -1156,9 +1235,9 @@ elemental subroutine evaporate_sublimate_precip(t, rho, dv, mu, sc, q, qvl, qvi,
(lams**(5._r8/2._r8+bs/2._r8)))
prds = eps*(qclr-qvi)/ab
- ! only sublimate in out-of-cloud region and distribute over cldmax
- prds=min(prds*(cldmax-dum),0._r8)
- prds=prds/cldmax
+ ! only sublimate in out-of-cloud region and distribute over precip_frac
+ prds=min(prds*(precip_frac-dum),0._r8)
+ prds=prds/precip_frac
else
prds = 0._r8
end if
diff --git a/models/atm/cam/src/physics/cam/microp_aero.F90 b/models/atm/cam/src/physics/cam/microp_aero.F90
index 84177b859809..a5b180977c90 100644
--- a/models/atm/cam/src/physics/cam/microp_aero.F90
+++ b/models/atm/cam/src/physics/cam/microp_aero.F90
@@ -2,7 +2,7 @@ module microp_aero
!---------------------------------------------------------------------------------
! Purpose:
-! CAM Interface for aerosol activation
+! CAM driver layer for aerosol activation processes.
!
! ***N.B.*** This module is currently hardcoded to recognize only the aerosols/modes that
! affect the climate calculation. This is implemented by using list
@@ -15,30 +15,36 @@ module microp_aero
! Gettelman et al., 2010 J. Geophys. Res. - Atmospheres (G2010)
! for questions contact Andrew Gettelman (andrew@ucar.edu)
! Modifications: A. Gettelman Nov 2010 - changed to support separation of
-! microphysics and macrophysics and concentrate aerosol information here
+! microphysics and macrophysics and concentrate aerosol information here
+! B. Eaton, Sep 2014 - Refactored to move CAM interface code into the CAM
+! interface modules and preserve just the driver layer functionality here.
!
!---------------------------------------------------------------------------------
use shr_kind_mod, only: r8=>shr_kind_r8
use spmd_utils, only: masterproc
use ppgrid, only: pcols, pver, pverp
-use physconst, only: rair, tmelt
-use constituents, only: cnst_get_ind, pcnst
+use ref_pres, only: top_lev => trop_cloud_top_lev
+use physconst, only: rair
+use constituents, only: cnst_get_ind
use physics_types, only: physics_state, physics_ptend, physics_ptend_init
use physics_buffer, only: physics_buffer_desc, pbuf_get_index, pbuf_old_tim_idx, pbuf_get_field
-use phys_control, only: phys_getopts
+use phys_control, only: phys_getopts, use_hetfrz_classnuc
use rad_constituents, only: rad_cnst_get_info, rad_cnst_get_aer_mmr, rad_cnst_get_aer_props, &
- rad_cnst_get_mode_num, rad_cnst_get_mode_props
-use shr_spfn_mod, only: erf => shr_spfn_erf, &
- erfc => shr_spfn_erfc
-use wv_saturation, only: qsat_water
-use nucleate_ice, only: nucleati
+ rad_cnst_get_mode_num
+
+use nucleate_ice_cam, only: use_preexisting_ice, nucleate_ice_cam_readnl, nucleate_ice_cam_register, &
+ nucleate_ice_cam_init, nucleate_ice_cam_calc
+
use ndrop, only: ndrop_init, dropmixnuc
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
+
use cam_history, only: addfld, phys_decomp, add_default, outfld
use cam_logfile, only: iulog
use cam_abortutils, only: endrun
-use ref_pres, only: top_lev => trop_cloud_top_lev
implicit none
private
@@ -48,7 +54,8 @@ module microp_aero
! Private module data
-character(len=16) :: eddy_scheme ! eddy scheme
+character(len=16) :: eddy_scheme
+logical :: micro_do_icesupersat
! contact freezing due to dust
! dust number mean radius (m), Zender et al JGR 2003 assuming number mode radius of 0.6 micron, sigma=2
@@ -57,7 +64,7 @@ module microp_aero
real(r8), parameter :: rn_dst3 = 1.576e-6_r8
real(r8), parameter :: rn_dst4 = 3.026e-6_r8
-real(r8), public :: bulk_scale ! prescribed aerosol bulk sulfur scale factor
+real(r8) :: bulk_scale ! prescribed aerosol bulk sulfur scale factor
! smallest mixing ratio considered in microphysics
real(r8), parameter :: qsmall = 1.e-18_r8
@@ -75,7 +82,6 @@ module microp_aero
integer :: wp2_idx = -1
integer :: ast_idx = -1
integer :: cldo_idx = -1
-integer :: dgnum_idx = -1
integer :: dgnumwet_idx = -1
! Bulk aerosols
@@ -84,14 +90,11 @@ module microp_aero
integer :: naer_all ! number of aerosols affecting climate
integer :: idxsul = -1 ! index in aerosol list for sulfate
-integer :: idxdst1 = -1 ! index in aerosol list for dust1
integer :: idxdst2 = -1 ! index in aerosol list for dust2
integer :: idxdst3 = -1 ! index in aerosol list for dust3
integer :: idxdst4 = -1 ! index in aerosol list for dust4
-integer :: idxbcphi = -1 ! index in aerosol list for Soot (BCPHIL)
! modal aerosols
-logical :: prog_modal_aero
logical :: clim_modal_aero
integer :: mode_accum_idx = -1 ! index of accumulation mode
@@ -102,14 +105,14 @@ module microp_aero
integer :: coarse_dust_idx = -1 ! index of dust in coarse mode
integer :: coarse_nacl_idx = -1 ! index of nacl in coarse mode
-integer :: naai_idx, naai_hom_idx, npccn_idx, rndst_idx, nacon_idx
+integer :: npccn_idx, rndst_idx, nacon_idx
-real(r8) :: sigmag_aitken
logical :: separate_dust = .false.
-!===============================================================================
+!=========================================================================================
contains
-!===============================================================================
+!=========================================================================================
+
subroutine microp_aero_register
!-----------------------------------------------------------------------
!
@@ -122,15 +125,18 @@ subroutine microp_aero_register
use ppgrid, only: pcols
use physics_buffer, only: pbuf_add_field, dtype_r8
- call pbuf_add_field('NAAI', 'physpkg',dtype_r8,(/pcols,pver/), naai_idx)
- call pbuf_add_field('NAAI_HOM', 'physpkg',dtype_r8,(/pcols,pver/), naai_hom_idx)
call pbuf_add_field('NPCCN', 'physpkg',dtype_r8,(/pcols,pver/), npccn_idx)
+
call pbuf_add_field('RNDST', 'physpkg',dtype_r8,(/pcols,pver,4/), rndst_idx)
call pbuf_add_field('NACON', 'physpkg',dtype_r8,(/pcols,pver,4/), nacon_idx)
+ call nucleate_ice_cam_register()
+ call hetfrz_classnuc_cam_register()
end subroutine microp_aero_register
+!=========================================================================================
+
subroutine microp_aero_init
!-----------------------------------------------------------------------
@@ -143,7 +149,7 @@ subroutine microp_aero_init
!-----------------------------------------------------------------------
! local variables
- integer :: iaer
+ integer :: iaer, ierr
integer :: m, n, nmodes, nspec
character(len=32) :: str32
@@ -152,8 +158,9 @@ subroutine microp_aero_init
!-----------------------------------------------------------------------
! Query the PBL eddy scheme
- call phys_getopts(eddy_scheme_out = eddy_scheme, &
- history_amwg_out = history_amwg)
+ call phys_getopts(eddy_scheme_out = eddy_scheme, &
+ history_amwg_out = history_amwg, &
+ micro_do_icesupersat_out = micro_do_icesupersat)
! Access the physical properties of the aerosols that are affecting the climate
! by using routines from the rad_constituents module.
@@ -166,16 +173,13 @@ subroutine microp_aero_init
select case(trim(eddy_scheme))
case ('diag_TKE')
- tke_idx = pbuf_get_index('tke')
+ tke_idx = pbuf_get_index('tke')
case ('CLUBB_SGS')
- wp2_idx = pbuf_get_index('WP2')
+ wp2_idx = pbuf_get_index('WP2_nadv')
case default
kvh_idx = pbuf_get_index('kvh')
end select
- ! prog_modal_aero determines whether prognostic modal aerosols are present in the run.
- call phys_getopts(prog_modal_aero_out=prog_modal_aero)
-
! clim_modal_aero determines whether modal aerosols are used in the climate calculation.
! The modal aerosols can be either prognostic or prescribed.
call rad_cnst_get_info(0, nmodes=nmodes)
@@ -186,7 +190,6 @@ subroutine microp_aero_init
if (clim_modal_aero) then
cldo_idx = pbuf_get_index('CLDO')
- dgnum_idx = pbuf_get_index('DGNUM' )
dgnumwet_idx = pbuf_get_index('DGNUMWET')
call ndrop_init()
@@ -251,9 +254,6 @@ subroutine microp_aero_init
call endrun(routine//': ERROR required mode-species type not found')
end if
- ! get specific mode properties
- call rad_cnst_get_mode_props(0, mode_aitken_idx, sigmag=sigmag_aitken)
-
else
! Props needed for BAM number concentration calcs.
@@ -270,11 +270,9 @@ subroutine microp_aero_init
! Look for sulfate, dust, and soot in this list (Bulk aerosol only)
if (trim(aername(iaer)) == 'SULFATE') idxsul = iaer
- if (trim(aername(iaer)) == 'DUST1') idxdst1 = iaer
if (trim(aername(iaer)) == 'DUST2') idxdst2 = iaer
if (trim(aername(iaer)) == 'DUST3') idxdst3 = iaer
if (trim(aername(iaer)) == 'DUST4') idxdst4 = iaer
- if (trim(aername(iaer)) == 'BCPHIL') idxbcphi = iaer
end do
call ndrop_bam_init()
@@ -285,18 +283,17 @@ subroutine microp_aero_init
call addfld('WSUB ', 'm/s ', pver, 'A', 'Diagnostic sub-grid vertical velocity' ,phys_decomp)
call addfld('WSUBI ', 'm/s ', pver, 'A', 'Diagnostic sub-grid vertical velocity for ice' ,phys_decomp)
- call addfld('NIHF', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to homogenous freezing', phys_decomp)
- call addfld('NIDEP', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to deposition nucleation',phys_decomp)
- call addfld('NIIMM', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to immersion freezing', phys_decomp)
- call addfld('NIMEY', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to meyers deposition', phys_decomp)
if (history_amwg) then
call add_default ('WSUB ', 1, ' ')
end if
+ call nucleate_ice_cam_init(mincld, bulk_scale)
+ call hetfrz_classnuc_cam_init(mincld)
+
end subroutine microp_aero_init
-!===============================================================================
+!=========================================================================================
subroutine microp_aero_readnl(nlfile)
@@ -338,9 +335,12 @@ subroutine microp_aero_readnl(nlfile)
! set local variables
bulk_scale = microp_aero_bulk_scale
+ call nucleate_ice_cam_readnl(nlfile)
+ call hetfrz_classnuc_cam_readnl(nlfile)
+
end subroutine microp_aero_readnl
-!===============================================================================
+!=========================================================================================
subroutine microp_aero_run ( &
state, ptend, deltatin, pbuf)
@@ -351,45 +351,20 @@ subroutine microp_aero_run ( &
real(r8), intent(in) :: deltatin ! time step (s)
type(physics_buffer_desc), pointer :: pbuf(:)
-
-
-
! local workspace
! all units mks unless otherwise stated
integer :: i, k, m
integer :: itim_old
- integer :: lchnk
- integer :: ncol
integer :: nmodes
- integer :: nucboast
real(r8), pointer :: ast(:,:)
- real(r8) :: icecldf(pcols,pver) ! ice cloud fraction
- real(r8) :: liqcldf(pcols,pver) ! liquid cloud fraction
-
- real(r8), pointer :: naai(:,:) ! number of activated aerosol for ice nucleation
- real(r8), pointer :: naai_hom(:,:) ! number of activated aerosol for ice nucleation (homogeneous freezing only)
real(r8), pointer :: npccn(:,:) ! number of CCN (liquid activated)
+
real(r8), pointer :: rndst(:,:,:) ! radius of 4 dust bins for contact freezing
real(r8), pointer :: nacon(:,:,:) ! number in 4 dust bins for contact freezing
- real(r8), pointer :: t(:,:) ! input temperature (K)
- real(r8), pointer :: qn(:,:) ! input water vapor mixing ratio (kg/kg)
- ! note: all input cloud variables are grid-averaged
- real(r8), pointer :: qc(:,:) ! cloud water mixing ratio (kg/kg)
- real(r8), pointer :: qi(:,:) ! cloud ice mixing ratio (kg/kg)
- real(r8), pointer :: nc(:,:) ! cloud water number conc (1/kg)
- real(r8), pointer :: ni(:,:) ! cloud ice number conc (1/kg)
- real(r8), pointer :: pmid(:,:) ! pressure at layer midpoints (pa)
- real(r8), pointer :: pdel(:,:) ! pressure difference across level (pa)
- real(r8), pointer :: pint(:,:) ! air pressure layer interfaces (pa)
- real(r8), pointer :: rpdel(:,:) ! inverse pressure difference across level (pa)
- real(r8), pointer :: zm(:,:) ! geopotential height of model levels (m)
- real(r8), pointer :: omega(:,:) ! vertical velocity (Pa/s)
- real(r8), pointer :: num_accum(:,:) ! number m.r. of accumulation mode
- real(r8), pointer :: num_aitken(:,:) ! number m.r. of aitken mode
real(r8), pointer :: num_coarse(:,:) ! number m.r. of coarse mode
real(r8), pointer :: coarse_dust(:,:) ! mass m.r. of coarse dust
real(r8), pointer :: coarse_nacl(:,:) ! mass m.r. of coarse nacl
@@ -401,17 +376,14 @@ subroutine microp_aero_run ( &
real(r8), pointer :: cldn(:,:) ! cloud fraction
real(r8), pointer :: cldo(:,:) ! old cloud fraction
- real(r8), pointer :: dgnum(:,:,:) ! aerosol mode dry diameter
real(r8), pointer :: dgnumwet(:,:,:) ! aerosol mode diameter
real(r8), pointer :: aer_mmr(:,:) ! aerosol mass mixing ratio
real(r8) :: rho(pcols,pver) ! air density (kg m-3)
- real(r8) :: relhum(pcols,pver) ! relative humidity
- real(r8) :: icldm(pcols,pver) ! ice cloud fraction
+
real(r8) :: lcldm(pcols,pver) ! liq cloud fraction
- real(r8) :: nfice(pcols,pver) ! fice variable
- real(r8) :: dumfice ! dummy var in fice calc
+
real(r8) :: lcldn(pcols,pver) ! fractional coverage of new liquid cloud
real(r8) :: lcldo(pcols,pver) ! fractional coverage of old liquid cloud
real(r8) :: qcld ! total cloud water
@@ -419,74 +391,63 @@ subroutine microp_aero_run ( &
real(r8) :: dum, dum2 ! temporary dummy variable
real(r8) :: dmc, ssmc ! variables for modal scheme.
- real(r8) :: so4_num ! so4 aerosol number (#/cm^3)
- real(r8) :: soot_num ! soot (hydrophilic) aerosol number (#/cm^3)
- real(r8) :: dst1_num,dst2_num,dst3_num,dst4_num ! dust aerosol number (#/cm^3)
- real(r8) :: dst_num ! total dust aerosol number (#/cm^3)
-
- real(r8) :: qs(pcols) ! liquid-ice weighted sat mixing rat (kg/kg)
- real(r8) :: es(pcols) ! liquid-ice weighted sat vapor press (pa)
- real(r8) :: gammas(pcols) ! parameter for cond/evap of cloud water
-
! bulk aerosol variables
real(r8), allocatable :: naer2(:,:,:) ! bulk aerosol number concentration (1/m3)
real(r8), allocatable :: maerosol(:,:,:) ! bulk aerosol mass conc (kg/m3)
real(r8) :: wsub(pcols,pver) ! diagnosed sub-grid vertical velocity st. dev. (m/s)
real(r8) :: wsubi(pcols,pver) ! diagnosed sub-grid vertical velocity ice (m/s)
-
- ! history output for ice nucleation
- real(r8) :: nihf(pcols,pver) !output number conc of ice nuclei due to heterogenous freezing (1/m3)
- real(r8) :: niimm(pcols,pver) !output number conc of ice nuclei due to immersion freezing (hetero nuc) (1/m3)
- real(r8) :: nidep(pcols,pver) !output number conc of ice nuclei due to deoposion nucleation (hetero nuc) (1/m3)
- real(r8) :: nimey(pcols,pver) !output number conc of ice nuclei due to meyers deposition (1/m3)
+ real(r8) :: nucboast
real(r8) :: wght
+ real(r8), allocatable :: factnum(:,:,:) ! activation fraction for aerosol number
!-------------------------------------------------------------------------------
- lchnk = state%lchnk
- ncol = state%ncol
- t => state%t
- qn => state%q(:,:,1)
- qc => state%q(:,:,cldliq_idx)
- qi => state%q(:,:,cldice_idx)
- nc => state%q(:,:,numliq_idx)
- ni => state%q(:,:,numice_idx)
- pmid => state%pmid
- pdel => state%pdel
- pint => state%pint
- rpdel => state%rpdel
- zm => state%zm
- omega => state%omega
+ associate( &
+ lchnk => state%lchnk, &
+ ncol => state%ncol, &
+ t => state%t, &
+ qc => state%q(:,:,cldliq_idx), &
+ qi => state%q(:,:,cldice_idx), &
+ nc => state%q(:,:,numliq_idx), &
+ pmid => state%pmid )
itim_old = pbuf_old_tim_idx()
- call pbuf_get_field(pbuf, ast_idx, ast, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
-
- liqcldf(:ncol,:pver) = ast(:ncol,:pver)
- icecldf(:ncol,:pver) = ast(:ncol,:pver)
+ if (micro_do_icesupersat) then
+ call pbuf_get_field(pbuf, cldo_idx, ast, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ else
+ call pbuf_get_field(pbuf, ast_idx, ast, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ endif
- call pbuf_get_field(pbuf, naai_idx, naai)
- call pbuf_get_field(pbuf, naai_hom_idx, naai_hom)
call pbuf_get_field(pbuf, npccn_idx, npccn)
+
call pbuf_get_field(pbuf, nacon_idx, nacon)
call pbuf_get_field(pbuf, rndst_idx, rndst)
if (clim_modal_aero) then
itim_old = pbuf_old_tim_idx()
- call pbuf_get_field(pbuf, ast_idx, cldn, start=(/1,1,itim_old/), kount=(/pcols,pver,1/) )
+
+ if (micro_do_icesupersat) then
+ call pbuf_get_field(pbuf, cldo_idx, cldn, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+ else
+ call pbuf_get_field(pbuf, ast_idx, cldn, start=(/1,1,itim_old/), kount=(/pcols,pver,1/) )
+ endif
+
call pbuf_get_field(pbuf, cldo_idx, cldo, start=(/1,1,itim_old/), kount=(/pcols,pver,1/) )
+
call rad_cnst_get_info(0, nmodes=nmodes)
- call pbuf_get_field(pbuf, dgnum_idx, dgnum, start=(/1,1,1/), kount=(/pcols,pver,nmodes/) )
call pbuf_get_field(pbuf, dgnumwet_idx, dgnumwet, start=(/1,1,1/), kount=(/pcols,pver,nmodes/) )
+
+ allocate(factnum(pcols,pver,nmodes))
+
end if
! initialize output
- naai(1:ncol,1:pver) = 0._r8
- naai_hom(1:ncol,1:pver) = 0._r8
npccn(1:ncol,1:pver) = 0._r8
+
nacon(1:ncol,1:pver,:) = 0._r8
! set default or fixed dust bins for contact freezing
@@ -495,11 +456,10 @@ subroutine microp_aero_run ( &
rndst(1:ncol,1:pver,3) = rn_dst3
rndst(1:ncol,1:pver,4) = rn_dst4
- ! initialize history output fields for ice nucleation
- nihf(1:ncol,1:pver) = 0._r8
- niimm(1:ncol,1:pver) = 0._r8
- nidep(1:ncol,1:pver) = 0._r8
- nimey(1:ncol,1:pver) = 0._r8
+ ! save copy of cloud borne aerosols for use in heterogeneous freezing
+ if (use_hetfrz_classnuc) then
+ call hetfrz_classnuc_cam_save_cbaero(state, pbuf)
+ end if
! initialize time-varying parameters
do k = top_lev, pver
@@ -510,8 +470,6 @@ subroutine microp_aero_run ( &
if (clim_modal_aero) then
! mode number mixing ratios
- call rad_cnst_get_mode_num(0, mode_accum_idx, 'a', state, pbuf, num_accum)
- call rad_cnst_get_mode_num(0, mode_aitken_idx, 'a', state, pbuf, num_aitken)
call rad_cnst_get_mode_num(0, mode_coarse_dst_idx, 'a', state, pbuf, num_coarse)
! mode specie mass m.r.
@@ -527,7 +485,7 @@ subroutine microp_aero_run ( &
do m = 1, naer_all
call rad_cnst_get_aer_mmr(0, m, state, pbuf, aer_mmr)
maerosol(:ncol,:,m) = aer_mmr(:ncol,:)*rho(:ncol,:)
-
+
if (m .eq. idxsul) then
naer2(:ncol,:,m) = maerosol(:ncol,:,m)*num_to_mass_aer(m)*bulk_scale
else
@@ -548,6 +506,7 @@ subroutine microp_aero_run ( &
call pbuf_get_field(pbuf, wp2_idx, wp2, start=(/1,1,itim_old/),kount=(/pcols,pverp,1/))
allocate(tke(pcols,pverp))
tke(:ncol,:) = (3._r8/2._r8)*wp2(:ncol,:)
+
case default
call pbuf_get_field(pbuf, kvh_idx, kvh)
end select
@@ -561,174 +520,59 @@ subroutine microp_aero_run ( &
select case (trim(eddy_scheme))
case ('diag_TKE', 'CLUBB_SGS')
- wsub(i,k) = sqrt(0.5_r8*(tke(i,k) + tke(i,k+1))*(2._r8/3._r8))
- wsub(i,k) = min(wsub(i,k),10._r8)
+ wsub(i,k) = sqrt(0.5_r8*(tke(i,k) + tke(i,k+1))*(2._r8/3._r8))
+ wsub(i,k) = min(wsub(i,k),10._r8)
case default
! get sub-grid vertical velocity from diff coef.
! following morrison et al. 2005, JAS
! assume mixing length of 30 m
- dum = (kvh(i,k) + kvh(i,k+1))/2._r8/30._r8
+ dum = (kvh(i,k) + kvh(i,k+1))/2._r8/30._r8
! use maximum sub-grid vertical vel of 10 m/s
- dum = min(dum, 10._r8)
+ dum = min(dum, 10._r8)
! set wsub to value at current vertical level
- wsub(i,k) = dum
- end select
-
- wsubi(i,k) = max(0.001_r8, wsub(i,k))
- wsubi(i,k) = min(wsubi(i,k), 0.2_r8)
-
-#ifdef CLUBB_SGS
- if (wsubi(i,k) .le. 0.04_r8) then
- nucboast=100._r8
- wsubi(i,k)=nucboast*wsubi(i,k) ! boost ice SGS vertical velocity in CAM-CLUBB
- ! to force nucleation in upper-level stratiform
- ! clouds. Temporary fix until cloud-top radiative
- ! cooling parameterization is added to CLUBB similar
- ! to the one of appendix C of Bretherton and Park (2009).
- endif
-#endif
-
- wsub(i,k) = max(0.20_r8, wsub(i,k))
- end do
- end do
- call outfld( 'WSUB' , wsub, pcols, lchnk )
- call outfld( 'WSUBI' , wsubi, pcols, lchnk )
-
- if (trim(eddy_scheme) == 'CLUBB_SGS') deallocate(tke)
-
- !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
- !Get humidity and saturation vapor pressures
-
- ! find wet bulk temperature and saturation value for provisional t and q without
- ! condensation
-
- do k = top_lev, pver
-
- call qsat_water(t(:ncol,k), pmid(:ncol,k), &
- es(:ncol), qs(:ncol), gam=gammas(:ncol))
-
- do i = 1, ncol
+ wsub(i,k) = dum
+ end select
- relhum(i,k) = qn(i,k)/qs(i)
+ if (eddy_scheme == 'CLUBB_SGS') then
+ wsubi(i,k) = max(0.2_r8, wsub(i,k))
+ wsubi(i,k) = min(wsubi(i,k), 10.0_r8)
+ else
+ wsubi(i,k) = max(0.001_r8, wsub(i,k))
+ if (.not. use_preexisting_ice) then
+ wsubi(i,k) = min(wsubi(i,k), 0.2_r8)
+ endif
+ endif
- ! get cloud fraction, check for minimum
- icldm(i,k) = max(icecldf(i,k), mincld)
- lcldm(i,k) = max(liqcldf(i,k), mincld)
+ wsub(i,k) = max(0.20_r8, wsub(i,k))
- ! calculate nfice based on liquid and ice mmr (no rain and snow mmr available yet)
- nfice(i,k) = 0._r8
- dumfice = qc(i,k) + qi(i,k)
- if (dumfice > qsmall .and. qi(i,k) > qsmall) then
- nfice(i,k) = qi(i,k)/dumfice
- end if
end do
end do
- !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
- !ICE Nucleation
-
- do k = top_lev, pver
- do i = 1, ncol
-
- if (t(i,k).lt.tmelt - 5._r8) then
-
-
- ! compute aerosol number for so4, soot, and dust with units #/cm^3
- so4_num = 0._r8
- soot_num = 0._r8
- dst1_num = 0._r8
- dst2_num = 0._r8
- dst3_num = 0._r8
- dst4_num = 0._r8
- dst_num = 0._r8
-
- if (clim_modal_aero) then
- !For modal aerosols, assume for the upper troposphere:
- ! soot = accumulation mode
- ! sulfate = aiken mode
- ! dust = coarse mode
- ! since modal has internal mixtures.
- soot_num = num_accum(i,k)*rho(i,k)*1.0e-6_r8
- dmc = coarse_dust(i,k)*rho(i,k)
- ssmc = coarse_nacl(i,k)*rho(i,k)
-
- if ( separate_dust ) then
- ! 7-mode -- has separate dust and seasalt mode types and no need for weighting
- wght = 1._r8
- else
- ! 3-mode -- needs weighting for dust since dust and seasalt are combined in the "coarse" mode type
- wght = dmc/(ssmc + dmc)
- endif
-
- if (dmc > 0._r8) then
- dst_num = wght * num_coarse(i,k)*rho(i,k)*1.0e-6_r8
- else
- dst_num = 0.0_r8
- end if
-
- if (dgnum(i,k,mode_aitken_idx) > 0._r8) then
- ! only allow so4 with D>0.1 um in ice nucleation
- so4_num = num_aitken(i,k)*rho(i,k)*1.0e-6_r8 &
- * (0.5_r8 - 0.5_r8*erf(log(0.1e-6_r8/dgnum(i,k,mode_aitken_idx))/ &
- (2._r8**0.5_r8*log(sigmag_aitken))))
- else
- so4_num = 0.0_r8
- end if
- so4_num = max(0.0_r8, so4_num)
-
- else
-
- if (idxsul > 0) then
- so4_num = naer2(i,k,idxsul)/25._r8 *1.0e-6_r8
- end if
- if (idxbcphi > 0) then
- soot_num = naer2(i,k,idxbcphi)/25._r8 *1.0e-6_r8
- end if
- if (idxdst1 > 0) then
- dst1_num = naer2(i,k,idxdst1)/25._r8 *1.0e-6_r8
- end if
- if (idxdst2 > 0) then
- dst2_num = naer2(i,k,idxdst2)/25._r8 *1.0e-6_r8
- end if
- if (idxdst3 > 0) then
- dst3_num = naer2(i,k,idxdst3)/25._r8 *1.0e-6_r8
- end if
- if (idxdst4 > 0) then
- dst4_num = naer2(i,k,idxdst4)/25._r8 *1.0e-6_r8
- end if
- dst_num = dst1_num + dst2_num + dst3_num + dst4_num
+ call outfld('WSUB', wsub, pcols, lchnk)
+ call outfld('WSUBI', wsubi, pcols, lchnk)
- end if
+ if (trim(eddy_scheme) == 'CLUBB_SGS') deallocate(tke)
- ! *** Turn off soot nucleation ***
- soot_num = 0.0_r8
+ !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+ !ICE Nucleation
- call nucleati( &
- wsubi(i,k), t(i,k), relhum(i,k), icldm(i,k), qc(i,k), &
- nfice(i,k), rho(i,k), so4_num, dst_num, soot_num, &
- naai(i,k), nihf(i,k), niimm(i,k), nidep(i,k), nimey(i,k))
+ call nucleate_ice_cam_calc(state, wsubi, pbuf)
- naai_hom(i,k) = nihf(i,k)
+ !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+ ! get liquid cloud fraction, check for minimum
- ! output activated ice (convert from #/kg -> #/m3)
- nihf(i,k) = nihf(i,k) *rho(i,k)
- niimm(i,k) = niimm(i,k)*rho(i,k)
- nidep(i,k) = nidep(i,k)*rho(i,k)
- nimey(i,k) = nimey(i,k)*rho(i,k)
- end if
+ do k = top_lev, pver
+ do i = 1, ncol
+ lcldm(i,k) = max(ast(i,k), mincld)
end do
end do
- call outfld('NIHF', nihf, pcols, lchnk)
- call outfld('NIIMM', niimm, pcols, lchnk)
- call outfld('NIDEP', nidep, pcols, lchnk)
- call outfld('NIMEY', nimey, pcols, lchnk)
-
+ !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
+ ! Droplet Activation
if (clim_modal_aero) then
- !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
- !droplet activation for modal aerosol
+ ! for modal aerosol
! partition cloud fraction into liquid water part
lcldn = 0._r8
@@ -747,14 +591,13 @@ subroutine microp_aero_run ( &
call dropmixnuc( &
state, ptend, deltatin, pbuf, wsub, &
- lcldn, lcldo, nctend_mixnuc)
+ lcldn, lcldo, nctend_mixnuc, factnum)
npccn(:ncol,:) = nctend_mixnuc(:ncol,:)
else
- !cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc
- !droplet activation for bulk aerosol
+ ! for bulk aerosol
! no tendencies returned from ndrop_bam_run, so just init ptend here
call physics_ptend_init(ptend, state%psetcols, 'none')
@@ -775,11 +618,7 @@ subroutine microp_aero_run ( &
dum = 0._r8
end if
- ! note: deltatin/2. accounts for sub step in microphysics
- ! ***** This assumes two sub-steps in microphysics. It's dangerous to
- ! ***** make that assumption here. Should move all coding related to
- ! ***** microphysics substepping into the microphysics.
- npccn(i,k) = (dum - nc(i,k)/lcldm(i,k))/(deltatin/2._r8)*lcldm(i,k)
+ npccn(i,k) = (dum*lcldm(i,k) - nc(i,k))/deltatin
end do
end do
@@ -858,12 +697,21 @@ subroutine microp_aero_run ( &
end if
-end subroutine microp_aero_run
+ ! heterogeneous freezing
+ if (use_hetfrz_classnuc) then
-!===============================================================================
+ call hetfrz_classnuc_cam_calc(state, deltatin, factnum, pbuf)
+ end if
-!===============================================================================
+ if (clim_modal_aero) then
+ deallocate(factnum)
+ end if
-end module microp_aero
+ end associate
+
+end subroutine microp_aero_run
+
+!=========================================================================================
+end module microp_aero
diff --git a/models/atm/cam/src/physics/cam/microp_driver.F90 b/models/atm/cam/src/physics/cam/microp_driver.F90
index 85ef68764f13..68a8865ed125 100644
--- a/models/atm/cam/src/physics/cam/microp_driver.F90
+++ b/models/atm/cam/src/physics/cam/microp_driver.F90
@@ -6,20 +6,19 @@ module microp_driver
!
!-------------------------------------------------------------------------------------------------------
-use shr_kind_mod, only: r8 => shr_kind_r8
-use ppgrid, only: pver
-use physics_types, only: physics_state, physics_ptend, physics_tend, &
- physics_ptend_copy, physics_ptend_sum
-use physics_buffer,only: pbuf_get_index, pbuf_get_field, physics_buffer_desc
-use phys_control, only: phys_getopts
-
-use cldwat2m_macro,only: ini_macro
-use micro_mg_cam, only: micro_mg_cam_readnl, micro_mg_cam_register, &
- micro_mg_cam_implements_cnst, micro_mg_cam_init_cnst, &
- micro_mg_cam_init, micro_mg_cam_tend
-use cam_logfile, only: iulog
-use cam_abortutils, only: endrun
-use perf_mod, only: t_startf, t_stopf
+use shr_kind_mod, only: r8 => shr_kind_r8
+use ppgrid, only: pver
+use physics_types, only: physics_state, physics_ptend, physics_tend, &
+ physics_ptend_copy, physics_ptend_sum
+use physics_buffer, only: pbuf_get_index, pbuf_get_field, physics_buffer_desc
+use phys_control, only: phys_getopts
+
+use micro_mg_cam, only: micro_mg_cam_readnl, micro_mg_cam_register, &
+ micro_mg_cam_implements_cnst, micro_mg_cam_init_cnst, &
+ micro_mg_cam_init, micro_mg_cam_tend
+use cam_logfile, only: iulog
+use cam_abortutils, only: endrun
+use perf_mod, only: t_startf, t_stopf
implicit none
private
@@ -139,8 +138,6 @@ subroutine microp_driver_init(pbuf2d)
! Initialize the microphysics parameterizations
!-----------------------------------------------------------------------
- call ini_macro()
-
select case (microp_scheme)
case ('MG')
call micro_mg_cam_init(pbuf2d)
diff --git a/models/atm/cam/src/physics/cam/ndrop.F90 b/models/atm/cam/src/physics/cam/ndrop.F90
index 4e2f12f3086e..a30c97685856 100644
--- a/models/atm/cam/src/physics/cam/ndrop.F90
+++ b/models/atm/cam/src/physics/cam/ndrop.F90
@@ -26,14 +26,14 @@ module ndrop
rad_cnst_get_aer_props, rad_cnst_get_mode_props, &
rad_cnst_get_mam_mmr_idx, rad_cnst_get_mode_num_idx
use cam_history, only: addfld, add_default, phys_decomp, fieldname_len, outfld
-use cam_abortutils, only: endrun
+use cam_abortutils, only: endrun
use cam_logfile, only: iulog
implicit none
private
save
-public ndrop_init, dropmixnuc
+public ndrop_init, dropmixnuc, activate_modal
real(r8), allocatable :: alogsig(:) ! natl log of geometric standard dev of aerosol
real(r8), allocatable :: exp45logsig(:)
@@ -289,7 +289,7 @@ end subroutine ndrop_init
subroutine dropmixnuc( &
state, ptend, dtmicro, pbuf, wsub, &
- cldn, cldo, tendnd)
+ cldn, cldo, tendnd, factnum)
! vertical diffusion and nucleation of cloud droplets
! assume cloud presence controlled by cloud fraction
@@ -309,7 +309,7 @@ subroutine dropmixnuc( &
! output arguments
real(r8), intent(out) :: tendnd(pcols,pver) ! change in droplet number concentration (#/kg/s)
-
+ real(r8), intent(out) :: factnum(:,:,:) ! activation fraction for aerosol number
!--------------------Local storage-------------------------------------
integer :: lchnk ! chunk identifier
@@ -479,7 +479,8 @@ subroutine dropmixnuc( &
end do
end do
- wtke = 0._r8
+ factnum = 0._r8
+ wtke = 0._r8
if (prog_modal_aero) then
! aerosol tendencies
@@ -630,6 +631,8 @@ subroutine dropmixnuc( &
vaerosol, hygro, fn, fm, fluxn, &
fluxm,flux_fullact(k))
+ factnum(i,k,:) = fn
+
dumc = (cldn_tmp - cldo_tmp)
do m = 1, ntot_amode
mm = mam_idx(m,0)
@@ -714,6 +717,8 @@ subroutine dropmixnuc( &
vaerosol, hygro, fn, fm, fluxn, &
fluxm, flux_fullact(k))
+ factnum(i,k,:) = fn
+
if (k < pver) then
dumc = cldn(i,k) - cldn(i,kp1)
else
@@ -1157,7 +1162,7 @@ end subroutine explmix
subroutine activate_modal(wbar, sigw, wdiab, wminf, wmaxf, tair, rhoair, &
na, nmode, volume, hygro, &
- fn, fm, fluxn, fluxm, flux_fullact )
+ fn, fm, fluxn, fluxm, flux_fullact, smax_prescribed)
! calculates number, surface, and mass fraction of aerosols activated as CCN
! calculates flux of cloud droplets, surface area, and aerosol mass into cloud
@@ -1172,29 +1177,32 @@ subroutine activate_modal(wbar, sigw, wdiab, wminf, wmaxf, tair, rhoair, &
! input
- real(r8) :: wbar ! grid cell mean vertical velocity (m/s)
- real(r8) :: sigw ! subgrid standard deviation of vertical vel (m/s)
- real(r8) :: wdiab ! diabatic vertical velocity (0 if adiabatic)
- real(r8) :: wminf ! minimum updraft velocity for integration (m/s)
- real(r8) :: wmaxf ! maximum updraft velocity for integration (m/s)
- real(r8) :: tair ! air temperature (K)
- real(r8) :: rhoair ! air density (kg/m3)
- real(r8) :: na(:) ! aerosol number concentration (/m3)
- integer :: nmode ! number of aerosol modes
- real(r8) :: volume(:) ! aerosol volume concentration (m3/m3)
- real(r8) :: hygro(:) ! hygroscopicity of aerosol mode
+ real(r8), intent(in) :: wbar ! grid cell mean vertical velocity (m/s)
+ real(r8), intent(in) :: sigw ! subgrid standard deviation of vertical vel (m/s)
+ real(r8), intent(in) :: wdiab ! diabatic vertical velocity (0 if adiabatic)
+ real(r8), intent(in) :: wminf ! minimum updraft velocity for integration (m/s)
+ real(r8), intent(in) :: wmaxf ! maximum updraft velocity for integration (m/s)
+ real(r8), intent(in) :: tair ! air temperature (K)
+ real(r8), intent(in) :: rhoair ! air density (kg/m3)
+ real(r8), intent(in) :: na(:) ! aerosol number concentration (/m3)
+ integer, intent(in) :: nmode ! number of aerosol modes
+ real(r8), intent(in) :: volume(:) ! aerosol volume concentration (m3/m3)
+ real(r8), intent(in) :: hygro(:) ! hygroscopicity of aerosol mode
! output
- real(r8) :: fn(:) ! number fraction of aerosols activated
- real(r8) :: fm(:) ! mass fraction of aerosols activated
- real(r8) :: fluxn(:) ! flux of activated aerosol number fraction into cloud (cm/s)
- real(r8) :: fluxm(:) ! flux of activated aerosol mass fraction into cloud (cm/s)
- real(r8) :: flux_fullact ! flux of activated aerosol fraction assuming 100% activation (cm/s)
+ real(r8), intent(out) :: fn(:) ! number fraction of aerosols activated
+ real(r8), intent(out) :: fm(:) ! mass fraction of aerosols activated
+ real(r8), intent(out) :: fluxn(:) ! flux of activated aerosol number fraction into cloud (cm/s)
+ real(r8), intent(out) :: fluxm(:) ! flux of activated aerosol mass fraction into cloud (cm/s)
+ real(r8), intent(out) :: flux_fullact ! flux of activated aerosol fraction assuming 100% activation (cm/s)
! rce-comment
! used for consistency check -- this should match (ekd(k)*zs(k))
! also, fluxm/flux_fullact gives fraction of aerosol mass flux
! that is activated
+
+ ! optional
+ real(r8), optional, intent(in) :: smax_prescribed ! prescribed max. supersaturation for secondary activation
! local
@@ -1265,6 +1273,10 @@ subroutine activate_modal(wbar, sigw, wdiab, wminf, wmaxf, tair, rhoair, &
if(sigw.le.1.e-5_r8.and.wbar.le.0._r8)return
+ if ( present( smax_prescribed ) ) then
+ if (smax_prescribed <= 0.0_r8) return
+ end if
+
pres=rair*rhoair*tair
diff0=0.211e-4_r8*(p0/pres)*(tair/t0)**1.94_r8
conduct0=(5.69_r8+0.017_r8*(tair-t0))*4.186e2_r8*1.e-5_r8 ! convert to J/m/s/deg
@@ -1354,7 +1366,11 @@ subroutine activate_modal(wbar, sigw, wdiab, wminf, wmaxf, tair, rhoair, &
zeta(m)=twothird*sqrtalw*aten/sqrtg(m)
enddo
- call maxsat(zeta,eta,nmode,smc,smax)
+ if ( present( smax_prescribed ) ) then
+ smax = smax_prescribed
+ else
+ call maxsat(zeta,eta,nmode,smc,smax)
+ endif
! write(iulog,*)'w,smax=',w,smax
lnsmax=log(smax)
@@ -1508,7 +1524,11 @@ subroutine activate_modal(wbar, sigw, wdiab, wminf, wmaxf, tair, rhoair, &
zeta(m)=twothird*sqrtalw*aten/sqrtg(m)
enddo
- call maxsat(zeta,eta,nmode,smc,smax)
+ if ( present( smax_prescribed ) ) then
+ smax = smax_prescribed
+ else
+ call maxsat(zeta,eta,nmode,smc,smax)
+ endif
lnsmax=log(smax)
xmincoeff=alogaten-twothird*(lnsmax-alog2)-alog3
@@ -1542,11 +1562,11 @@ subroutine maxsat(zeta,eta,nmode,smc,smax)
! Abdul-Razzak and Ghan, A parameterization of aerosol activation.
! 2. Multiple aerosol types. J. Geophys. Res., 105, 6837-6844.
- integer :: nmode ! number of modes
- real(r8) :: smc(nmode) ! critical supersaturation for number mode radius
- real(r8) :: zeta(nmode)
- real(r8) :: eta(nmode)
- real(r8) :: smax ! maximum supersaturation
+ integer, intent(in) :: nmode ! number of modes
+ real(r8), intent(in) :: smc(nmode) ! critical supersaturation for number mode radius
+ real(r8), intent(in) :: zeta(nmode)
+ real(r8), intent(in) :: eta(nmode)
+ real(r8), intent(out) :: smax ! maximum supersaturation
integer :: m ! mode index
real(r8) :: sum, g1, g2, g1sqrt, g2sqrt
@@ -1570,7 +1590,9 @@ subroutine maxsat(zeta,eta,nmode,smc,smax)
g1=zeta(m)/eta(m)
g1sqrt=sqrt(g1)
g1=g1sqrt*g1
- g1=g1sqrt*g1
+#if ! defined(CLUBB_BFB_S1) && ! defined(CLUBB_BFB_ALL)
+ g1=g1sqrt*g1 !Removed as a bugfix. Restored here if to be B4B with original model
+#endif
g2=smc(m)/sqrt(eta(m)+3._r8*zeta(m))
g2sqrt=sqrt(g2)
g2=g2sqrt*g2
diff --git a/models/atm/cam/src/physics/cam/nucleate_ice.F90 b/models/atm/cam/src/physics/cam/nucleate_ice.F90
index 1403d1e2f218..85a0b3bf0955 100644
--- a/models/atm/cam/src/physics/cam/nucleate_ice.F90
+++ b/models/atm/cam/src/physics/cam/nucleate_ice.F90
@@ -1,49 +1,107 @@
module nucleate_ice
-!---------------------------------------------------------------------------------
+!-------------------------------------------------------------------------------
! Purpose:
-! Ice nucleation code.
+! A parameterization of ice nucleation.
!
-!---------------------------------------------------------------------------------
+! *** This module is intended to be a "portable" code layer. Ideally it should
+! *** not contain any use association of modules that belong to the model framework.
+!
+!
+! Method:
+! The current method is based on Liu & Penner (2005) & Liu et al. (2007)
+! It related the ice nucleation with the aerosol number, temperature and the
+! updraft velocity. It includes homogeneous freezing of sulfate & immersion
+! freezing on mineral dust (soot disabled) in cirrus clouds, and
+! Meyers et al. (1992) deposition nucleation in mixed-phase clouds
+!
+! The effect of preexisting ice crystals on ice nucleation in cirrus clouds is included,
+! and also consider the sub-grid variability of temperature in cirrus clouds,
+! following X. Shi et al. ACP (2014).
+!
+! Ice nucleation in mixed-phase clouds now uses classical nucleation theory (CNT),
+! follows Y. Wang et al. ACP (2014), Hoose et al. (2010).
+!
+! Authors:
+! Xiaohong Liu, 01/2005, modifications by A. Gettelman 2009-2010
+! Xiangjun Shi & Xiaohong Liu, 01/2014.
+!
+! With help from C. C. Chen and B. Eaton (2014)
+!-------------------------------------------------------------------------------
-use shr_kind_mod, only: r8=>shr_kind_r8
use wv_saturation, only: svp_water, svp_ice
-use cam_logfile, only: iulog
implicit none
private
save
-public :: nucleati
+integer, parameter :: r8 = selected_real_kind(12)
+
+public :: nucleati_init, nucleati
+
+logical :: use_preexisting_ice
+logical :: use_hetfrz_classnuc
+integer :: iulog
+real(r8) :: pi
+real(r8) :: mincld
+
+! Subgrid scale factor on relative humidity (dimensionless)
+real(r8) :: subgrid
+
+real(r8), parameter :: Shet = 1.3_r8 ! het freezing threshold
+real(r8), parameter :: rhoice = 0.5e3_r8 ! kg/m3, Wpice is not sensitive to rhoice
+real(r8), parameter :: minweff= 0.001_r8 ! m/s
+real(r8), parameter :: gamma1=1.0_r8
+real(r8), parameter :: gamma2=1.0_r8
+real(r8), parameter :: gamma3=2.0_r8
+real(r8), parameter :: gamma4=6.0_r8
+
+real(r8) :: ci
!===============================================================================
contains
!===============================================================================
+subroutine nucleati_init( &
+ use_preexisting_ice_in, use_hetfrz_classnuc_in, iulog_in, pi_in, &
+ mincld_in, subgrid_in)
+
+ logical, intent(in) :: use_preexisting_ice_in
+ logical, intent(in) :: use_hetfrz_classnuc_in
+ integer, intent(in) :: iulog_in
+ real(r8), intent(in) :: pi_in
+ real(r8), intent(in) :: mincld_in
+ real(r8), intent(in) :: subgrid_in
+
+ use_preexisting_ice = use_preexisting_ice_in
+ use_hetfrz_classnuc = use_hetfrz_classnuc_in
+ iulog = iulog_in
+ pi = pi_in
+ mincld = mincld_in
+ subgrid = subgrid_in
+
+ ci = rhoice*pi/6._r8
+
+end subroutine nucleati_init
+
+!===============================================================================
+
subroutine nucleati( &
- wbar, tair, relhum, cldn, qc, &
- nfice, rhoair, so4_num, dst_num, soot_num, &
- nuci, onihf, oniimm, onidep, onimey)
-
- !---------------------------------------------------------------
- ! Purpose:
- ! The parameterization of ice nucleation.
- !
- ! Method: The current method is based on Liu & Penner (2005)
- ! It related the ice nucleation with the aerosol number, temperature and the
- ! updraft velocity. It includes homogeneous freezing of sulfate, immersion
- ! freezing of soot, and Meyers et al. (1992) deposition nucleation
- !
- ! Authors: Xiaohong Liu, 01/2005, modifications by A. Gettelman 2009-2010
- !----------------------------------------------------------------
+ wbar, tair, pmid, relhum, cldn, &
+ qc, qi, ni_in, rhoair, &
+ so4_num, dst_num, soot_num, &
+ nuci, onihf, oniimm, onidep, onimey, &
+ wpice, weff, fhom)
! Input Arguments
real(r8), intent(in) :: wbar ! grid cell mean vertical velocity (m/s)
real(r8), intent(in) :: tair ! temperature (K)
+ real(r8), intent(in) :: pmid ! pressure at layer midpoints (pa)
real(r8), intent(in) :: relhum ! relative humidity with respective to liquid
real(r8), intent(in) :: cldn ! new value of cloud fraction (fraction)
real(r8), intent(in) :: qc ! liquid water mixing ratio (kg/kg)
- real(r8), intent(in) :: nfice ! ice mass fraction
+ real(r8), intent(in) :: qi ! grid-mean preexisting cloud ice mass mixing ratio (kg/kg)
+ real(r8), intent(in) :: ni_in ! grid-mean preexisting cloud ice number conc (#/kg)
real(r8), intent(in) :: rhoair ! air density (kg/m3)
real(r8), intent(in) :: so4_num ! so4 aerosol number (#/cm^3)
real(r8), intent(in) :: dst_num ! total dust aerosol number (#/cm^3)
@@ -55,6 +113,9 @@ subroutine nucleati( &
real(r8), intent(out) :: oniimm ! nucleated number from immersion freezing
real(r8), intent(out) :: onidep ! nucleated number from deposition nucleation
real(r8), intent(out) :: onimey ! nucleated number from deposition nucleation (meyers: mixed phase)
+ real(r8), intent(out) :: wpice ! diagnosed Vertical velocity Reduction caused by preexisting ice (m/s), at Shom
+ real(r8), intent(out) :: weff ! effective Vertical velocity for ice nucleation (m/s); weff=wbar-wpice
+ real(r8), intent(out) :: fhom ! how much fraction of cloud can reach Shom
! Local workspace
real(r8) :: nihf ! nucleated number from homogeneous freezing of so4
@@ -62,11 +123,55 @@ subroutine nucleati( &
real(r8) :: nidep ! nucleated number from deposition nucleation
real(r8) :: nimey ! nucleated number from deposition nucleation (meyers)
real(r8) :: n1, ni ! nucleated number
- real(r8) :: tc, A, B, C, regm, RHw ! work variable
+ real(r8) :: tc, A, B, regm ! work variable
real(r8) :: esl, esi, deles ! work variable
- real(r8) :: subgrid
+ real(r8) :: wbar1, wbar2
+
+ ! used in SUBROUTINE Vpreice
+ real(r8) :: Ni_preice ! cloud ice number conc (1/m3)
+ real(r8) :: lami,Ri_preice ! mean cloud ice radius (m)
+ real(r8) :: Shom ! initial ice saturation ratio; if <1, use hom threshold Si
+ real(r8) :: detaT,RHimean ! temperature standard deviation, mean cloudy RHi
+ real(r8) :: wpicehet ! diagnosed Vertical velocity Reduction caused by preexisting ice (m/s), at shet
+
+ real(r8) :: weffhet ! effective Vertical velocity for ice nucleation (m/s) weff=wbar-wpicehet
!-------------------------------------------------------------------------------
+ ! temp variables that depend on use_preexisting_ice
+ wbar1 = wbar
+ wbar2 = wbar
+
+ if (use_preexisting_ice) then
+
+ Ni_preice = ni_in*rhoair ! (convert from #/kg -> #/m3)
+ Ni_preice = Ni_preice / max(mincld,cldn) ! in-cloud ice number density
+
+ if (Ni_preice > 10.0_r8) then ! > 0.01/L = 10/m3
+ Shom = -1.5_r8 ! if Shom<1 , Shom will be recalculated in SUBROUTINE Vpreice, according to Ren & McKenzie, 2005
+ lami = (gamma4*ci*ni_in/qi)**(1._r8/3._r8)
+ Ri_preice = 0.5_r8/lami ! radius
+ Ri_preice = max(Ri_preice, 1e-8_r8) ! >0.01micron
+ call Vpreice(pmid, tair, Ri_preice, Ni_preice, Shom, wpice)
+ call Vpreice(pmid, tair, Ri_preice, Ni_preice, Shet, wpicehet)
+ else
+ wpice = 0.0_r8
+ wpicehet = 0.0_r8
+ endif
+
+ weff = max(wbar-wpice, minweff)
+ wpice = min(wpice, wbar)
+ weffhet = max(wbar-wpicehet,minweff)
+ wpicehet = min(wpicehet, wbar)
+
+ wbar1 = weff
+ wbar2 = weffhet
+
+ detaT = wbar/0.23_r8
+ RHimean = 1.0_r8
+ call frachom(tair, RHimean, detaT, fhom)
+
+ end if
+
ni = 0._r8
tc = tair - 273.15_r8
@@ -74,65 +179,136 @@ subroutine nucleati( &
niimm = 0._r8
nidep = 0._r8
nihf = 0._r8
+ deles = 0._r8
+ esi = 0._r8
- if(so4_num.ge.1.0e-10_r8 .and. (soot_num+dst_num).ge.1.0e-10_r8 .and. cldn.gt.0._r8) then
+ if(so4_num >= 1.0e-10_r8 .and. (soot_num+dst_num) >= 1.0e-10_r8 .and. cldn > 0._r8) then
- !-----------------------------
- ! RHw parameterization for heterogeneous immersion nucleation
- A = 0.0073_r8
- B = 1.477_r8
- C = 131.74_r8
- RHw=(A*tc*tc+B*tc+C)*0.01_r8 ! RHi ~ 120-130%
+#ifdef USE_XLIU_MOD
+!++ Mod from Xiaohong is the following two line conditional.
+! It changes answers so needs climate validation.
+ if ((relhum*svp_water(tair)/svp_ice(tair)*subgrid).ge.1.2_r8) then
+ if ( ((tc.le.0.0_r8).and.(tc.ge.-37.0_r8).and.(qc.lt.1.e-12_r8)).or.(tc.le.-37.0_r8)) then
+#else
+ if((tc.le.-35.0_r8) .and. ((relhum*svp_water(tair)/svp_ice(tair)*subgrid).ge.1.2_r8)) then ! use higher RHi threshold
+#endif
- subgrid = 1.2_r8
+ A = -1.4938_r8 * log(soot_num+dst_num) + 12.884_r8
+ B = -10.41_r8 * log(soot_num+dst_num) - 67.69_r8
+ regm = A * log(wbar1) + B
- if((tc.le.-35.0_r8) .and. ((relhum*svp_water(tair)/svp_ice(tair)*subgrid).ge.1.2_r8)) then ! use higher RHi threshold
+ ! heterogeneous nucleation only
+ if (tc .gt. regm) then
- A = -1.4938_r8 * log(soot_num+dst_num) + 12.884_r8
- B = -10.41_r8 * log(soot_num+dst_num) - 67.69_r8
- regm = A * log(wbar) + B
+ if(tc.lt.-40._r8 .and. wbar1.gt.1._r8) then ! exclude T<-40 & W>1m/s from hetero. nucleation
- if(tc.gt.regm) then ! heterogeneous nucleation only
- if(tc.lt.-40._r8 .and. wbar.gt.1._r8) then ! exclude T<-40 & W>1m/s from hetero. nucleation
- call hf(tc,wbar,relhum,subgrid,so4_num,nihf)
- niimm=0._r8
- nidep=0._r8
- n1=nihf
- else
- call hetero(tc,wbar,soot_num+dst_num,niimm,nidep)
- nihf=0._r8
- n1=niimm+nidep
- endif
- elseif (tc.lt.regm-5._r8) then ! homogeneous nucleation only
- call hf(tc,wbar,relhum,subgrid,so4_num,nihf)
- niimm=0._r8
- nidep=0._r8
- n1=nihf
- else ! transition between homogeneous and heterogeneous: interpolate in-between
- if(tc.lt.-40._r8 .and. wbar.gt.1._r8) then ! exclude T<-40 & W>1m/s from hetero. nucleation
- call hf(tc,wbar,relhum,subgrid,so4_num,nihf)
+ call hf(tc,wbar1,relhum,so4_num,nihf)
+ niimm=0._r8
+ nidep=0._r8
+
+ if (use_preexisting_ice) then
+ if (nihf.gt.1e-3_r8) then ! hom occur, add preexisting ice
+ niimm=min(dst_num,Ni_preice*1e-6_r8) ! assuming dst_num freeze firstly
+ nihf=nihf + Ni_preice*1e-6_r8 - niimm
+ endif
+ nihf=nihf*fhom
+ n1=nihf+niimm
+ else
+ n1=nihf
+ end if
+
+ else
+
+ call hetero(tc,wbar2,soot_num+dst_num,niimm,nidep)
+
+ if (use_preexisting_ice) then
+ if (niimm .gt. 1e-6_r8) then ! het freezing occur, add preexisting ice
+ niimm = niimm + Ni_preice*1e-6_r8
+ niimm = min(dst_num, niimm) ! niimm < dst_num
+ end if
+ end if
+ nihf=0._r8
+ n1=niimm+nidep
+
+ endif
+
+ ! homogeneous nucleation only
+ else if (tc.lt.regm-5._r8) then
+
+ call hf(tc,wbar1,relhum,so4_num,nihf)
niimm=0._r8
nidep=0._r8
- n1=nihf
+
+ if (use_preexisting_ice) then
+ if (nihf.gt.1e-3_r8) then ! hom occur, add preexisting ice
+ niimm=min(dst_num,Ni_preice*1e-6_r8) ! assuming dst_num freeze firstly
+ nihf=nihf + Ni_preice*1e-6_r8 - niimm
+ endif
+ nihf=nihf*fhom
+ n1=nihf+niimm
+ else
+ n1=nihf
+ end if
+
+ ! transition between homogeneous and heterogeneous: interpolate in-between
else
- call hf(regm-5._r8,wbar,relhum,subgrid,so4_num,nihf)
- call hetero(regm,wbar,soot_num+dst_num,niimm,nidep)
+ if (tc.lt.-40._r8 .and. wbar1.gt.1._r8) then ! exclude T<-40 & W>1m/s from hetero. nucleation
- if(nihf.le.(niimm+nidep)) then
- n1=nihf
- else
- n1=(niimm+nidep)*((niimm+nidep)/nihf)**((tc-regm)/5._r8)
- endif
- endif
- endif
+ call hf(tc, wbar1, relhum, so4_num, nihf)
+ niimm = 0._r8
+ nidep = 0._r8
- ni=n1
+ if (use_preexisting_ice) then
+ if (nihf .gt. 1e-3_r8) then ! hom occur, add preexisting ice
+ niimm = min(dst_num, Ni_preice*1e-6_r8) ! assuming dst_num freeze firstly
+ nihf = nihf + Ni_preice*1e-6_r8 - niimm
+ endif
+ nihf = nihf*fhom
+ n1 = nihf + niimm
+ else
+ n1 = nihf
+ end if
- endif
- endif
+ else
- ! deposition/condensation nucleation in mixed clouds (-401
+ ENDIF
+
+ R = R_in*1e2_r8 ! m => cm
+ C = C_in*1e-6_r8 ! m-3 => cm-3
+ T_1 = 1.0_r8/ T
+ PICE = WVP1c * EXP(-(WVP2c*T_1))
+ ALP4 = 0.25_r8 * ALPHAc
+ FLUX = ALP4 * SQRT(FVTHc*T)
+ CISAT = THOUBKc * PICE * T_1
+ A1 = ( FA1c * T_1 - FA2c ) * T_1
+ A2 = 1.0_r8/ CISAT
+ A3 = FA3c * T_1 / P
+ B1 = FLUX * SVOLc * CISAT * ( S-1.0_r8 )
+ B2 = FLUX * FDc * P * T_1**1.94_r8
+ DLOSS = FPIVOLc * C * B1 * R**2 / ( 1.0_r8+ B2 * R )
+ VICE = ( A2 + A3 * S ) * DLOSS / ( A1 * S ) ! 2006,(19)
+ V_out = VICE*1e-2_r8 ! cm/s => m/s
+
+END SUBROUTINE Vpreice
+
+subroutine frachom(Tmean,RHimean,detaT,fhom)
+ ! How much fraction of cirrus might reach Shom
+ ! base on "A cirrus cloud scheme for general circulation models",
+ ! B. Karcher and U. Burkhardt 2008
+
+ real(r8), intent(in) :: Tmean, RHimean, detaT
+ real(r8), intent(out) :: fhom
+
+ real(r8), parameter :: seta = 6132.9_r8 ! K
+ integer, parameter :: Nbin=200 ! (Tmean - 3*detaT, Tmean + 3*detaT)
+
+ real(r8) :: PDF_T(Nbin) ! temperature PDF; ! PDF_T=0 outside (Tmean-3*detaT, Tmean+3*detaT)
+ real(r8) :: Sbin(Nbin) ! the fluctuations of Si that are driven by the T variations
+ real(r8) :: Sihom, deta
+ integer :: i
+
+ Sihom = 2.349_r8-Tmean/259.0_r8 ! homogeneous freezing threshold, according to Ren & McKenzie, 2005
+ fhom = 0.0_r8
+
+ do i = Nbin, 1, -1
+
+ deta = (i - 0.5_r8 - Nbin/2)*6.0_r8/Nbin ! PDF_T=0 outside (Tmean-3*detaT, Tmean+3*detaT)
+ Sbin(i) = RHimean*exp(deta*detaT*seta/Tmean**2.0_r8)
+ PDF_T(i) = exp(-deta**2.0_r8/2.0_r8)*6.0_r8/(sqrt(2.0_r8*Pi)*Nbin)
+
+
+ if (Sbin(i).ge.Sihom) then
+ fhom = fhom + PDF_T(i)
+ else
+ exit
+ end if
+ end do
+
+ fhom=fhom/0.997_r8 ! accounting for the finite limits (-3 , 3)
+
+end subroutine frachom
+
end module nucleate_ice
diff --git a/models/atm/cam/src/physics/cam/nucleate_ice_cam.F90 b/models/atm/cam/src/physics/cam/nucleate_ice_cam.F90
new file mode 100644
index 000000000000..c456de01cf5e
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/nucleate_ice_cam.F90
@@ -0,0 +1,641 @@
+module nucleate_ice_cam
+
+!---------------------------------------------------------------------------------
+!
+! CAM Interfaces for nucleate_ice module.
+!
+! B. Eaton - Sept 2014
+!---------------------------------------------------------------------------------
+
+use shr_kind_mod, only: r8=>shr_kind_r8
+use spmd_utils, only: masterproc
+use ppgrid, only: pcols, pver
+use physconst, only: pi, rair, tmelt
+use constituents, only: cnst_get_ind
+use physics_types, only: physics_state
+use physics_buffer, only: physics_buffer_desc, pbuf_get_index, pbuf_old_tim_idx, pbuf_get_field
+use phys_control, only: use_hetfrz_classnuc
+use rad_constituents, only: rad_cnst_get_info, rad_cnst_get_aer_mmr, rad_cnst_get_aer_props, &
+ rad_cnst_get_mode_num, rad_cnst_get_mode_props
+
+use physics_buffer, only: pbuf_add_field, dtype_r8, pbuf_old_tim_idx, &
+ pbuf_get_index, pbuf_get_field
+use cam_history, only: addfld, phys_decomp, add_default, outfld
+
+use ref_pres, only: top_lev => trop_cloud_top_lev
+use wv_saturation, only: qsat_water
+use shr_spfn_mod, only: erf => shr_spfn_erf
+
+use cam_logfile, only: iulog
+use cam_abortutils, only: endrun
+
+use nucleate_ice, only: nucleati_init, nucleati
+
+
+implicit none
+private
+save
+
+public :: &
+ nucleate_ice_cam_readnl, &
+ nucleate_ice_cam_register, &
+ nucleate_ice_cam_init, &
+ nucleate_ice_cam_calc
+
+
+! Namelist variables
+logical, public, protected :: use_preexisting_ice = .false.
+logical :: hist_preexisting_ice = .false.
+real(r8) :: nucleate_ice_subgrid
+
+! Vars set via init method.
+real(r8) :: mincld ! minimum allowed cloud fraction
+real(r8) :: bulk_scale ! prescribed aerosol bulk sulfur scale factor
+
+! constituent indices
+integer :: &
+ cldliq_idx = -1, &
+ cldice_idx = -1, &
+ numice_idx = -1
+
+integer :: &
+ naai_idx, &
+ naai_hom_idx
+
+integer :: &
+ ast_idx = -1, &
+ dgnum_idx = -1
+
+! Bulk aerosols
+character(len=20), allocatable :: aername(:)
+real(r8), allocatable :: num_to_mass_aer(:)
+
+integer :: naer_all ! number of aerosols affecting climate
+integer :: idxsul = -1 ! index in aerosol list for sulfate
+integer :: idxdst1 = -1 ! index in aerosol list for dust1
+integer :: idxdst2 = -1 ! index in aerosol list for dust2
+integer :: idxdst3 = -1 ! index in aerosol list for dust3
+integer :: idxdst4 = -1 ! index in aerosol list for dust4
+integer :: idxbcphi = -1 ! index in aerosol list for Soot (BCPHIL)
+
+! modal aerosols
+logical :: clim_modal_aero
+
+integer :: nmodes = -1
+integer :: mode_accum_idx = -1 ! index of accumulation mode
+integer :: mode_aitken_idx = -1 ! index of aitken mode
+integer :: mode_coarse_idx = -1 ! index of coarse mode
+integer :: mode_coarse_dst_idx = -1 ! index of coarse dust mode
+integer :: mode_coarse_slt_idx = -1 ! index of coarse sea salt mode
+integer :: coarse_dust_idx = -1 ! index of dust in coarse mode
+integer :: coarse_nacl_idx = -1 ! index of nacl in coarse mode
+
+logical :: separate_dust = .false.
+real(r8) :: sigmag_aitken
+
+!===============================================================================
+contains
+!===============================================================================
+
+subroutine nucleate_ice_cam_readnl(nlfile)
+
+ use namelist_utils, only: find_group_name
+ use units, only: getunit, freeunit
+ use mpishorthand
+
+ character(len=*), intent(in) :: nlfile ! filepath for file containing namelist input
+
+ ! Local variables
+ integer :: unitn, ierr
+ character(len=*), parameter :: subname = 'nucleate_ice_cam_readnl'
+
+ namelist /nucleate_ice_nl/ use_preexisting_ice, hist_preexisting_ice, &
+ nucleate_ice_subgrid
+
+ !-----------------------------------------------------------------------------
+
+ if (masterproc) then
+ unitn = getunit()
+ open( unitn, file=trim(nlfile), status='old' )
+ call find_group_name(unitn, 'nucleate_ice_nl', status=ierr)
+ if (ierr == 0) then
+ read(unitn, nucleate_ice_nl, iostat=ierr)
+ if (ierr /= 0) then
+ call endrun(subname // ':: ERROR reading namelist')
+ end if
+ end if
+ close(unitn)
+ call freeunit(unitn)
+
+ end if
+
+#ifdef SPMD
+ ! Broadcast namelist variables
+ call mpibcast(use_preexisting_ice, 1, mpilog, 0, mpicom)
+ call mpibcast(hist_preexisting_ice, 1, mpilog, 0, mpicom)
+ call mpibcast(nucleate_ice_subgrid, 1, mpir8, 0, mpicom)
+#endif
+
+end subroutine nucleate_ice_cam_readnl
+
+!================================================================================================
+
+subroutine nucleate_ice_cam_register()
+
+ call pbuf_add_field('NAAI', 'physpkg', dtype_r8, (/pcols,pver/), naai_idx)
+ call pbuf_add_field('NAAI_HOM', 'physpkg', dtype_r8, (/pcols,pver/), naai_hom_idx)
+
+end subroutine nucleate_ice_cam_register
+
+!================================================================================================
+
+subroutine nucleate_ice_cam_init(mincld_in, bulk_scale_in)
+
+ real(r8), intent(in) :: mincld_in
+ real(r8), intent(in) :: bulk_scale_in
+
+ ! local variables
+ integer :: iaer
+ integer :: m, n, nspec
+
+ character(len=32) :: str32
+ character(len=*), parameter :: routine = 'nucleate_ice_cam_init'
+ !--------------------------------------------------------------------------------------------
+
+ mincld = mincld_in
+ bulk_scale = bulk_scale_in
+
+ call cnst_get_ind('CLDLIQ', cldliq_idx)
+ call cnst_get_ind('CLDICE', cldice_idx)
+ call cnst_get_ind('NUMICE', numice_idx)
+
+ call addfld('NIHF', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to homogenous freezing', phys_decomp)
+ call addfld('NIDEP', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to deposition nucleation',phys_decomp)
+ call addfld('NIIMM', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to immersion freezing', phys_decomp)
+ call addfld('NIMEY', '1/m3', pver, 'A', 'Activated Ice Number Concentation due to meyers deposition', phys_decomp)
+
+ if (use_preexisting_ice) then
+ call addfld('fhom ', 'fraction', pver, 'A', 'Fraction of cirrus where homogeneous freezing occur' ,phys_decomp)
+ call addfld ('WICE ', 'm/s ', pver, 'A','Vertical velocity Reduction caused by preexisting ice' ,phys_decomp)
+ call addfld ('WEFF ', 'm/s ', pver, 'A','Effective Vertical velocity for ice nucleation' ,phys_decomp)
+ call addfld ('INnso4 ','1/m3 ', pver, 'A','Number Concentation so4 used for ice_nucleation',phys_decomp)
+ call addfld ('INnbc ','1/m3 ', pver, 'A','Number Concentation bc used for ice_nucleation',phys_decomp)
+ call addfld ('INndust ','1/m3 ', pver, 'A','Number Concentation dustused for ice_nucleation',phys_decomp)
+ call addfld ('INhet ','1/m3 ', pver, 'A', &
+ 'contribution for in-cloud ice number density increase by het nucleation in ice cloud',phys_decomp)
+ call addfld ('INhom ','1/m3 ', pver, 'A', &
+ 'contribution for in-cloud ice number density increase by hom nucleation in ice cloud',phys_decomp)
+ call addfld ('INFrehom ','frequency',pver,'A','hom IN frequency ice cloud',phys_decomp)
+ call addfld ('INFreIN ','frequency',pver,'A','frequency of ice nucleation occur',phys_decomp)
+
+ if (hist_preexisting_ice) then
+ call add_default ('WSUBI ', 1, ' ') ! addfld/outfld calls are in microp_aero
+
+ call add_default ('fhom ', 1, ' ')
+ call add_default ('WICE ', 1, ' ')
+ call add_default ('WEFF ', 1, ' ')
+ call add_default ('INnso4 ', 1, ' ')
+ call add_default ('INnbc ', 1, ' ')
+ call add_default ('INndust ', 1, ' ')
+ call add_default ('INhet ', 1, ' ')
+ call add_default ('INhom ', 1, ' ')
+ call add_default ('INFrehom', 1, ' ')
+ call add_default ('INFreIN ', 1, ' ')
+ end if
+ end if
+
+ ! clim_modal_aero determines whether modal aerosols are used in the climate calculation.
+ ! The modal aerosols can be either prognostic or prescribed.
+ call rad_cnst_get_info(0, nmodes=nmodes)
+ clim_modal_aero = (nmodes > 0)
+
+ if (clim_modal_aero) then
+
+ dgnum_idx = pbuf_get_index('DGNUM' )
+
+ ! Init indices for specific modes/species
+
+ ! mode index for specified mode types
+ do m = 1, nmodes
+ call rad_cnst_get_info(0, m, mode_type=str32)
+ select case (trim(str32))
+ case ('accum')
+ mode_accum_idx = m
+ case ('aitken')
+ mode_aitken_idx = m
+ case ('coarse')
+ mode_coarse_idx = m
+ case ('coarse_dust')
+ mode_coarse_dst_idx = m
+ case ('coarse_seasalt')
+ mode_coarse_slt_idx = m
+ end select
+ end do
+
+ ! check if coarse dust is in separate mode
+ separate_dust = mode_coarse_dst_idx > 0
+
+ ! for 3-mode
+ if (mode_coarse_dst_idx < 0) mode_coarse_dst_idx = mode_coarse_idx
+ if (mode_coarse_slt_idx < 0) mode_coarse_slt_idx = mode_coarse_idx
+
+ ! Check that required mode types were found
+ if (mode_accum_idx == -1 .or. mode_aitken_idx == -1 .or. &
+ mode_coarse_dst_idx == -1.or. mode_coarse_slt_idx == -1) then
+ write(iulog,*) routine//': ERROR required mode type not found - mode idx:', &
+ mode_accum_idx, mode_aitken_idx, mode_coarse_dst_idx, mode_coarse_slt_idx
+ call endrun(routine//': ERROR required mode type not found')
+ end if
+
+ ! species indices for specified types
+ ! find indices for the dust and seasalt species in the coarse mode
+ call rad_cnst_get_info(0, mode_coarse_dst_idx, nspec=nspec)
+ do n = 1, nspec
+ call rad_cnst_get_info(0, mode_coarse_dst_idx, n, spec_type=str32)
+ select case (trim(str32))
+ case ('dust')
+ coarse_dust_idx = n
+ end select
+ end do
+ call rad_cnst_get_info(0, mode_coarse_slt_idx, nspec=nspec)
+ do n = 1, nspec
+ call rad_cnst_get_info(0, mode_coarse_slt_idx, n, spec_type=str32)
+ select case (trim(str32))
+ case ('seasalt')
+ coarse_nacl_idx = n
+ end select
+ end do
+
+ ! Check that required mode specie types were found
+ if ( coarse_dust_idx == -1 .or. coarse_nacl_idx == -1) then
+ write(iulog,*) routine//': ERROR required mode-species type not found - indicies:', &
+ coarse_dust_idx, coarse_nacl_idx
+ call endrun(routine//': ERROR required mode-species type not found')
+ end if
+
+ ! get specific mode properties
+ call rad_cnst_get_mode_props(0, mode_aitken_idx, sigmag=sigmag_aitken)
+
+ else
+
+ ! Props needed for BAM number concentration calcs.
+
+ call rad_cnst_get_info(0, naero=naer_all)
+ allocate( &
+ aername(naer_all), &
+ num_to_mass_aer(naer_all) )
+
+ do iaer = 1, naer_all
+ call rad_cnst_get_aer_props(0, iaer, &
+ aername = aername(iaer), &
+ num_to_mass_aer = num_to_mass_aer(iaer) )
+
+ ! Look for sulfate, dust, and soot in this list (Bulk aerosol only)
+ if (trim(aername(iaer)) == 'SULFATE') idxsul = iaer
+ if (trim(aername(iaer)) == 'DUST1') idxdst1 = iaer
+ if (trim(aername(iaer)) == 'DUST2') idxdst2 = iaer
+ if (trim(aername(iaer)) == 'DUST3') idxdst3 = iaer
+ if (trim(aername(iaer)) == 'DUST4') idxdst4 = iaer
+ if (trim(aername(iaer)) == 'BCPHIL') idxbcphi = iaer
+ end do
+ end if
+
+
+ call nucleati_init(use_preexisting_ice, use_hetfrz_classnuc, iulog, pi, &
+ mincld, nucleate_ice_subgrid)
+
+ ! get indices for fields in the physics buffer
+ ast_idx = pbuf_get_index('AST')
+
+end subroutine nucleate_ice_cam_init
+
+!================================================================================================
+
+subroutine nucleate_ice_cam_calc( &
+ state, wsubi, pbuf)
+
+ ! arguments
+ type(physics_state), target, intent(in) :: state
+ real(r8), intent(in) :: wsubi(:,:)
+ type(physics_buffer_desc), pointer :: pbuf(:)
+
+ ! local workspace
+
+ ! naai and naai_hom are the outputs shared with the microphysics
+ real(r8), pointer :: naai(:,:) ! number of activated aerosol for ice nucleation
+ real(r8), pointer :: naai_hom(:,:) ! number of activated aerosol for ice nucleation (homogeneous freezing only)
+
+ integer :: lchnk, ncol
+ integer :: itim_old
+ integer :: i, k, m
+
+ real(r8), pointer :: t(:,:) ! input temperature (K)
+ real(r8), pointer :: qn(:,:) ! input water vapor mixing ratio (kg/kg)
+ real(r8), pointer :: qc(:,:) ! cloud water mixing ratio (kg/kg)
+ real(r8), pointer :: qi(:,:) ! cloud ice mixing ratio (kg/kg)
+ real(r8), pointer :: ni(:,:) ! cloud ice number conc (1/kg)
+ real(r8), pointer :: pmid(:,:) ! pressure at layer midpoints (pa)
+
+ real(r8), pointer :: num_accum(:,:) ! number m.r. of accumulation mode
+ real(r8), pointer :: num_aitken(:,:) ! number m.r. of aitken mode
+ real(r8), pointer :: num_coarse(:,:) ! number m.r. of coarse mode
+ real(r8), pointer :: coarse_dust(:,:) ! mass m.r. of coarse dust
+ real(r8), pointer :: coarse_nacl(:,:) ! mass m.r. of coarse nacl
+ real(r8), pointer :: aer_mmr(:,:) ! aerosol mass mixing ratio
+ real(r8), pointer :: dgnum(:,:,:) ! mode dry radius
+
+ real(r8), pointer :: ast(:,:)
+ real(r8) :: icecldf(pcols,pver) ! ice cloud fraction
+
+ real(r8) :: rho(pcols,pver) ! air density (kg m-3)
+
+ real(r8), allocatable :: naer2(:,:,:) ! bulk aerosol number concentration (1/m3)
+ real(r8), allocatable :: maerosol(:,:,:) ! bulk aerosol mass conc (kg/m3)
+
+ real(r8) :: qs(pcols) ! liquid-ice weighted sat mixing rat (kg/kg)
+ real(r8) :: es(pcols) ! liquid-ice weighted sat vapor press (pa)
+ real(r8) :: gammas(pcols) ! parameter for cond/evap of cloud water
+
+ real(r8) :: relhum(pcols,pver) ! relative humidity
+ real(r8) :: icldm(pcols,pver) ! ice cloud fraction
+
+ real(r8) :: so4_num ! so4 aerosol number (#/cm^3)
+ real(r8) :: soot_num ! soot (hydrophilic) aerosol number (#/cm^3)
+ real(r8) :: dst1_num,dst2_num,dst3_num,dst4_num ! dust aerosol number (#/cm^3)
+ real(r8) :: dst_num ! total dust aerosol number (#/cm^3)
+ real(r8) :: wght
+ real(r8) :: dmc
+ real(r8) :: ssmc
+
+ ! For pre-existing ice
+ real(r8) :: fhom(pcols,pver) ! how much fraction of cloud can reach Shom
+ real(r8) :: wice(pcols,pver) ! diagnosed Vertical velocity Reduction caused by preexisting ice (m/s), at Shom
+ real(r8) :: weff(pcols,pver) ! effective Vertical velocity for ice nucleation (m/s); weff=wsubi-wice
+ real(r8) :: INnso4(pcols,pver) ! #/m3, so4 aerosol number used for ice nucleation
+ real(r8) :: INnbc(pcols,pver) ! #/m3, bc aerosol number used for ice nucleation
+ real(r8) :: INndust(pcols,pver) ! #/m3, dust aerosol number used for ice nucleation
+ real(r8) :: INhet(pcols,pver) ! #/m3, ice number from het freezing
+ real(r8) :: INhom(pcols,pver) ! #/m3, ice number from hom freezing
+ real(r8) :: INFrehom(pcols,pver) ! hom freezing occurence frequency. 1 occur, 0 not occur.
+ real(r8) :: INFreIN(pcols,pver) ! ice nucleation occerence frequency. 1 occur, 0 not occur.
+
+ ! history output for ice nucleation
+ real(r8) :: nihf(pcols,pver) !output number conc of ice nuclei due to heterogenous freezing (1/m3)
+ real(r8) :: niimm(pcols,pver) !output number conc of ice nuclei due to immersion freezing (hetero nuc) (1/m3)
+ real(r8) :: nidep(pcols,pver) !output number conc of ice nuclei due to deoposion nucleation (hetero nuc) (1/m3)
+ real(r8) :: nimey(pcols,pver) !output number conc of ice nuclei due to meyers deposition (1/m3)
+
+
+ !-------------------------------------------------------------------------------
+
+ lchnk = state%lchnk
+ ncol = state%ncol
+ t => state%t
+ qn => state%q(:,:,1)
+ qc => state%q(:,:,cldliq_idx)
+ qi => state%q(:,:,cldice_idx)
+ 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
+
+ if (clim_modal_aero) then
+ ! mode number mixing ratios
+ call rad_cnst_get_mode_num(0, mode_accum_idx, 'a', state, pbuf, num_accum)
+ call rad_cnst_get_mode_num(0, mode_aitken_idx, 'a', state, pbuf, num_aitken)
+ call rad_cnst_get_mode_num(0, mode_coarse_dst_idx, 'a', state, pbuf, num_coarse)
+
+ ! mode specie mass m.r.
+ call rad_cnst_get_aer_mmr(0, mode_coarse_dst_idx, coarse_dust_idx, 'a', state, pbuf, coarse_dust)
+ call rad_cnst_get_aer_mmr(0, mode_coarse_slt_idx, coarse_nacl_idx, 'a', state, pbuf, coarse_nacl)
+
+ else
+ ! init number/mass arrays for bulk aerosols
+ allocate( &
+ naer2(pcols,pver,naer_all), &
+ maerosol(pcols,pver,naer_all))
+
+ do m = 1, naer_all
+ call rad_cnst_get_aer_mmr(0, m, state, pbuf, aer_mmr)
+ maerosol(:ncol,:,m) = aer_mmr(:ncol,:)*rho(:ncol,:)
+
+ if (m .eq. idxsul) then
+ naer2(:ncol,:,m) = maerosol(:ncol,:,m)*num_to_mass_aer(m)*bulk_scale
+ else
+ naer2(:ncol,:,m) = maerosol(:ncol,:,m)*num_to_mass_aer(m)
+ end if
+ end do
+ end if
+
+ itim_old = pbuf_old_tim_idx()
+ call pbuf_get_field(pbuf, ast_idx, ast, start=(/1,1,itim_old/), kount=(/pcols,pver,1/))
+
+ icecldf(:ncol,:pver) = ast(:ncol,:pver)
+
+ if (clim_modal_aero) then
+ call pbuf_get_field(pbuf, dgnum_idx, dgnum)
+ end if
+
+ ! naai and naai_hom are the outputs from this parameterization
+ call pbuf_get_field(pbuf, naai_idx, naai)
+ call pbuf_get_field(pbuf, naai_hom_idx, naai_hom)
+ naai(1:ncol,1:pver) = 0._r8
+ naai_hom(1:ncol,1:pver) = 0._r8
+
+ ! initialize history output fields for ice nucleation
+ nihf(1:ncol,1:pver) = 0._r8
+ niimm(1:ncol,1:pver) = 0._r8
+ nidep(1:ncol,1:pver) = 0._r8
+ nimey(1:ncol,1:pver) = 0._r8
+
+ if (use_preexisting_ice) then
+ fhom(:,:) = 0.0_r8
+ wice(:,:) = 0.0_r8
+ weff(:,:) = 0.0_r8
+ INnso4(:,:) = 0.0_r8
+ INnbc(:,:) = 0.0_r8
+ INndust(:,:) = 0.0_r8
+ INhet(:,:) = 0.0_r8
+ INhom(:,:) = 0.0_r8
+ INFrehom(:,:) = 0.0_r8
+ INFreIN(:,:) = 0.0_r8
+ endif
+
+ do k = top_lev, pver
+
+ ! Get humidity and saturation vapor pressures
+ call qsat_water(t(:ncol,k), pmid(:ncol,k), &
+ es(:ncol), qs(:ncol), gam=gammas(:ncol))
+
+ do i = 1, ncol
+
+ relhum(i,k) = qn(i,k)/qs(i)
+
+ ! get cloud fraction, check for minimum
+ icldm(i,k) = max(icecldf(i,k), mincld)
+
+ end do
+ end do
+
+
+ do k = top_lev, pver
+ do i = 1, ncol
+
+ if (t(i,k) < tmelt - 5._r8) then
+
+ ! compute aerosol number for so4, soot, and dust with units #/cm^3
+ so4_num = 0._r8
+ soot_num = 0._r8
+ dst1_num = 0._r8
+ dst2_num = 0._r8
+ dst3_num = 0._r8
+ dst4_num = 0._r8
+ dst_num = 0._r8
+
+ if (clim_modal_aero) then
+ !For modal aerosols, assume for the upper troposphere:
+ ! soot = accumulation mode
+ ! sulfate = aiken mode
+ ! dust = coarse mode
+ ! since modal has internal mixtures.
+ soot_num = num_accum(i,k)*rho(i,k)*1.0e-6_r8
+ dmc = coarse_dust(i,k)*rho(i,k)
+ ssmc = coarse_nacl(i,k)*rho(i,k)
+
+ if (dmc > 0._r8) then
+ if ( separate_dust ) then
+ ! 7-mode -- has separate dust and seasalt mode types and
+ ! no need for weighting
+ wght = 1._r8
+ else
+ ! 3-mode -- needs weighting for dust since dust and seasalt
+ ! are combined in the "coarse" mode type
+ wght = dmc/(ssmc + dmc)
+ endif
+ dst_num = wght * num_coarse(i,k)*rho(i,k)*1.0e-6_r8
+ else
+ dst_num = 0.0_r8
+ end if
+
+ if (dgnum(i,k,mode_aitken_idx) > 0._r8) then
+ if (.not. use_preexisting_ice) then
+ ! only allow so4 with D>0.1 um in ice nucleation
+ so4_num = num_aitken(i,k)*rho(i,k)*1.0e-6_r8 &
+ * (0.5_r8 - 0.5_r8*erf(log(0.1e-6_r8/dgnum(i,k,mode_aitken_idx))/ &
+ (2._r8**0.5_r8*log(sigmag_aitken))))
+ else
+ ! all so4 from aitken
+ so4_num = num_aitken(i,k)*rho(i,k)*1.0e-6_r8
+ end if
+ else
+ so4_num = 0.0_r8
+ end if
+ so4_num = max(0.0_r8, so4_num)
+
+ else
+
+ if (idxsul > 0) then
+ so4_num = naer2(i,k,idxsul)/25._r8 *1.0e-6_r8
+ end if
+ if (idxbcphi > 0) then
+ soot_num = naer2(i,k,idxbcphi)/25._r8 *1.0e-6_r8
+ end if
+ if (idxdst1 > 0) then
+ dst1_num = naer2(i,k,idxdst1)/25._r8 *1.0e-6_r8
+ end if
+ if (idxdst2 > 0) then
+ dst2_num = naer2(i,k,idxdst2)/25._r8 *1.0e-6_r8
+ end if
+ if (idxdst3 > 0) then
+ dst3_num = naer2(i,k,idxdst3)/25._r8 *1.0e-6_r8
+ end if
+ if (idxdst4 > 0) then
+ dst4_num = naer2(i,k,idxdst4)/25._r8 *1.0e-6_r8
+ end if
+ dst_num = dst1_num + dst2_num + dst3_num + dst4_num
+
+ end if
+
+ ! *** Turn off soot nucleation ***
+ soot_num = 0.0_r8
+
+ call nucleati( &
+ wsubi(i,k), t(i,k), pmid(i,k), relhum(i,k), icldm(i,k), &
+ qc(i,k), qi(i,k), ni(i,k), rho(i,k), &
+ so4_num, dst_num, soot_num, &
+ naai(i,k), nihf(i,k), niimm(i,k), nidep(i,k), nimey(i,k), &
+ wice(i,k), weff(i,k), fhom(i,k))
+
+ naai_hom(i,k) = nihf(i,k)
+
+ ! output activated ice (convert from #/kg -> #/m3)
+ nihf(i,k) = nihf(i,k) *rho(i,k)
+ niimm(i,k) = niimm(i,k)*rho(i,k)
+ nidep(i,k) = nidep(i,k)*rho(i,k)
+ nimey(i,k) = nimey(i,k)*rho(i,k)
+
+ if (use_preexisting_ice) then
+ INnso4(i,k) =so4_num*1e6_r8 ! (convert from #/cm3 -> #/m3)
+ INnbc(i,k) =soot_num*1e6_r8
+ INndust(i,k)=dst_num*1e6_r8
+ INFreIN(i,k)=1.0_r8 ! 1,ice nucleation occur
+ INhet(i,k) = niimm(i,k) + nidep(i,k) ! #/m3, nimey not in cirrus
+ INhom(i,k) = nihf(i,k) ! #/m3
+ if (INhom(i,k).gt.1e3_r8) then ! > 1/L
+ INFrehom(i,k)=1.0_r8 ! 1, hom freezing occur
+ endif
+
+ ! exclude no ice nucleaton
+ if ((INFrehom(i,k) < 0.5_r8) .and. (INhet(i,k) < 1.0_r8)) then
+ INnso4(i,k) =0.0_r8
+ INnbc(i,k) =0.0_r8
+ INndust(i,k)=0.0_r8
+ INFreIN(i,k)=0.0_r8
+ INhet(i,k) = 0.0_r8
+ INhom(i,k) = 0.0_r8
+ INFrehom(i,k)=0.0_r8
+ wice(i,k) = 0.0_r8
+ weff(i,k) = 0.0_r8
+ fhom(i,k) = 0.0_r8
+ endif
+ end if
+
+ end if
+ end do
+ end do
+
+ if (.not. clim_modal_aero) then
+
+ deallocate( &
+ naer2, &
+ maerosol)
+
+ end if
+
+ call outfld('NIHF', nihf, pcols, lchnk)
+ call outfld('NIIMM', niimm, pcols, lchnk)
+ call outfld('NIDEP', nidep, pcols, lchnk)
+ call outfld('NIMEY', nimey, pcols, lchnk)
+
+ if (use_preexisting_ice) then
+ call outfld( 'fhom' , fhom, pcols, lchnk)
+ call outfld( 'WICE' , wice, pcols, lchnk)
+ call outfld( 'WEFF' , weff, pcols, lchnk)
+ call outfld('INnso4 ',INnso4 , pcols,lchnk)
+ call outfld('INnbc ',INnbc , pcols,lchnk)
+ call outfld('INndust ',INndust, pcols,lchnk)
+ call outfld('INhet ',INhet , pcols,lchnk)
+ call outfld('INhom ',INhom , pcols,lchnk)
+ call outfld('INFrehom',INFrehom,pcols,lchnk)
+ call outfld('INFreIN ',INFreIN, pcols,lchnk)
+ end if
+
+end subroutine nucleate_ice_cam_calc
+
+!================================================================================================
+
+end module nucleate_ice_cam
diff --git a/models/atm/cam/src/physics/cam/nudging.F90 b/models/atm/cam/src/physics/cam/nudging.F90
new file mode 100644
index 000000000000..96a1937c88b0
--- /dev/null
+++ b/models/atm/cam/src/physics/cam/nudging.F90
@@ -0,0 +1,1971 @@
+module nudging
+!=====================================================================
+!
+! Purpose: Implement Nudging of the model state of U,V,T,Q, and/or PS
+! toward specified values from analyses.
+!
+! Author: Patrick Callaghan
+!
+! Description:
+! This module assumes that the user has {U,V,T,Q,PS} analyses which
+! have been preprocessed onto the current model grid and are stored
+! in individual files which are indexed with respect to year, month,
+! day, and second of the day. When the model is inbetween the given
+! begining and ending times, forcing is added to nudge the model toward
+! the appropriate analyses values. After the model passes the ending
+! analyses time, the forcing discontinues.
+!
+! Revisions:
+! 01/14/13 - Modified to manage 'GAPS' in analyses data. For now the
+! approach is to coast through the gaps... If a given
+! analyses file is missing, nudging is turned off for
+! that interval of time. Once an analyses file is found,
+! the Nudging is switched back on.
+! 02/22/13 - Modified to add functionality for FV and EUL dynamical
+! cores.
+! 03/03/13 - For ne120 runs, the automatic arrays used for reading in
+! U,V,T,Q,PS values were putting too much of a burden on the
+! stack memory. Until Parallel I/O is implemented, the impact
+! on the stack was reduced by using only one automatic array
+! to read in and scatter the data.
+! 04/01/13 - Added Heaviside window function for localized nudging
+! 04/10/13 - Modified call to physics_ptend_init() to accomodate the
+! new interface (in CESM1_2_BETA05).
+! 05/06/13 - 'WRAP_NF' was modified from a generic interface so that
+! now it can only read in 1D arrays from netCDF files.
+! To eliminate errors from future meddling of this sort, all
+! refenences to the 'wrap_nf' module were removed and replaced
+! with direct nf90 calls.
+!
+! Input/Output Values:
+! Forcing contributions are available for history file output by
+! the names: {'Nudge_U','Nudge_V','Nudge_T',and 'Nudge_Q'}
+!
+! The nudging of the model toward the analyses data is controlled by
+! the 'nudging_nl' namelist in 'user_nl_cam'; whose variables control the
+! time interval over which nudging is applied, the strength of the nudging
+! tendencies, and its spatial distribution. The strength of the nudging is
+! specified as a fractional coeffcient between [0,1]. The spatial distribution
+! is specified with a profile index:
+!
+! (U,V,T,Q) Profiles: 0 == OFF (No Nudging of this variable)
+! ------------------- 1 == CONSTANT (Spatially Uniform Nudging)
+! 2 == HEAVISIDE WINDOW FUNCTION
+!
+! (PS) Profiles: 0 == OFF (Not Implemented)
+! ------------------- 1 == N/A (Not Implemented)
+!
+! The Heaviside window function is the product of separate horizonal and vertical
+! windows that are controled via 14 parameters:
+! Nudge_Hwin_lat0: Provide the horizontal center of the window in degrees.
+! Nudge_Hwin_lon0: The longitude must be in the range [0,360] and the
+! latitude should be [-90,+90].
+!
+! Nudge_Hwin_latWidth: Specify the lat and lon widths of the window as positive
+! Nudge_Hwin_lonWidth: values in degrees.Setting a width to a large value (e.g. 999)
+! renders the window a constant in that direction.
+!
+! Nudge_Hwin_latDelta: Controls the sharpness of the window transition with a
+! Nudge_Hwin_lonDelta: length in degrees. Small non-zero values yeild a step
+! function while a large value leads to a smoother transition.
+!
+! Nudge_Vwin_Lindex: In the vertical, the window is specified in terms of model
+! Nudge_Vwin_Ldelta: level indcies. The High and Low transition levels should
+! Nudge_Vwin_Hindex: range from [0,(NCOL+1)]. The transition lengths are also
+! Nudge_Vwin_Hdelta: specified in terms of model indices. For a window function
+! constant in the vertical, the Low index should be set to 0,
+! the High index should be set to (NCOL+1), and the transition
+! lengths should be set to 0.1
+!
+! Nudge_Hwin_lo: For a given set of spatial parameters, the raw window
+! Nudge_Hwin_hi: function may not span the range [0,1], so those values are
+! Nudge_Vwin_lo: mapped to the range of values specified in by the user.
+! Nudge_Vwin_hi: The 'hi' values are mapped to the maximum of the raw window
+! function and 'lo' values are mapped to its minimum.
+! Typically the 'hi' values will be set equal to 1, and the
+! 'lo' values set equal 0 or the desired window minimum.
+! Specifying the 'lo' value as 1 and the 'hi' value as 0 acts
+! to invert the window function. For a properly specified
+! window its maximum should be equal to 1: MAX('lo','hi')==1
+!
+! EXAMPLE: For a channel window function centered at the equator and independent
+! of the vertical (30 levels):
+! Nudge_Hwin_lo = 0. Nudge_Vwin_lo = 0.
+! Nudge_Hwin_hi = 1. Nudge_Vwin_hi = 1.
+! Nudge_Hwin_lat0 = 0. Nudge_Vwin_Lindex = 0.
+! Nudge_Hwin_latWidth = 30. Nudge_Vwin_Ldelta = 0.1
+! Nudge_Hwin_latDelta = 5.0 Nudge_Vwin_Hindex = 31.
+! Nudge_Hwin_lon0 = 180. Nudge_Vwin_Hdelta = 0.1
+! Nudge_Hwin_lonWidth = 999.
+! Nudge_Hwin_lonDelta = 1.0
+!
+! If on the other hand one desired to apply nudging at the poles and
+! not at the equator, the settings would be similar but with:
+! Nudge_Hwin_lo = 1.
+! Nudge_Hwin_hi = 0.
+!
+! &nudging_nl
+! Nudge_Model - LOGICAL toggle to activate nudging.
+! Nudge_Path - CHAR path to the analyses files.
+! Nudge_File_Template - CHAR Analyses filename with year, month, day, and second
+! values replaced by %y, %m, %d, and %s respectively.
+! Nudge_Times_Per_Day - INT Number of analyses files available per day.
+! Model_Times_Per_Day - INT Number of times to update the model state (used for nudging)
+! each day. The value is restricted to be longer than the
+! current model timestep and shorter than the analyses
+! timestep. As this number is increased, the nudging
+! force has the form of newtonian cooling.
+! Nudge_Uprof - INT index of profile structure to use for U. [0,1,2]
+! Nudge_Vprof - INT index of profile structure to use for V. [0,1,2]
+! Nudge_Tprof - INT index of profile structure to use for T. [0,1,2]
+! Nudge_Qprof - INT index of profile structure to use for Q. [0,1,2]
+! Nudge_PSprof - INT index of profile structure to use for PS. [0,N/A]
+! Nudge_Ucoef - REAL fractional nudging coeffcient for U.
+! Utau=(Nudge_Ucoef/analyses_timestep)
+! Nudge_Vcoef - REAL fractional nudging coeffcient for V.
+! Vtau=(Nudge_Vcoef/analyses_timestep)
+! Nudge_Tcoef - REAL fractional nudging coeffcient for T.
+! Ttau=(Nudge_Tcoef/analyses_timestep)
+! Nudge_Qcoef - REAL fractional nudging coeffcient for Q.
+! Qtau=(Nudge_Qcoef/analyses_timestep)
+! Nudge_PScoef - REAL fractional nudging coeffcient for PS.
+! PStau=(Nudge_PScoef/analyses_timestep)
+! Nudge_Beg_Year - INT nudging begining year.
+! Nudge_Beg_Month - INT nudging begining month.
+! Nudge_Beg_Day - INT nudging begining day.
+! Nudge_End_Year - INT nudging ending year.
+! Nudge_End_Month - INT nudging ending month.
+! Nudge_End_Day - INT nudging ending day.
+! Nudge_Hwin_lo - REAL value mapped to RAW horizontal window minimum. [0]
+! Nudge_Hwin_hi - REAL value mapped to RAW horizontal window maximum. [1]
+! Nudge_Vwin_lo - REAL value mapped to RAW vertical window minimum. [0]
+! Nudge_Vwin_hi - REAL value mapped to RAW vertical window maximum. [1]
+! Nudge_Hwin_lat0 - REAL latitudinal center of window in degrees.
+! Nudge_Hwin_lon0 - REAL longitudinal center of window in degrees.
+! Nudge_Hwin_latWidth - REAL latitudinal width of window in degrees.
+! Nudge_Hwin_lonWidth - REAL longitudinal width of window in degrees.
+! Nudge_Hwin_latDelta - REAL latitudinal transition length of window in degrees.
+! Nudge_Hwin_lonDelta - REAL longitudinal transition length of window in degrees.
+! Nudge_Vwin_Lindex - REAL LO model index of transition
+! Nudge_Vwin_Hindex - REAL HI model index of transition
+! Nudge_Vwin_Ldelta - REAL LO transition length
+! Nudge_Vwin_Hdelta - REAL HI transition length
+! /
+!
+!================
+! DIAG NOTE:
+!================
+! The interface for reading and using analyses data is not complete for the FV
+! dynamical core. Wind values stored in the available data set are the values
+! on the staggered grid US,VS rather than U,V. To test the implementation of
+! the nudging for this case, the US,VS values were read in a loaded as if they
+! were U,V. The implementation of this hack is tagged with 'DIAG' where code
+! changed are needed to undo and fix what I have done.
+!================
+!
+! TO DO:
+! -----------
+! ** Currently the surface pressure is read in, but there is no forcing
+! meachnism implemented.
+! ** Analyses data is read in and then distributed to processing elements
+! via 'scatted_field_to_chunk' calls. The SE's want this to be changed
+! to parallel I/O calls.
+! ** Possibly implement time variation to nudging coeffcients, so that
+! rather than just bashing the model with a sledge hammer, the user has the
+! option to ramp up the nudging coefs over a startup time frame via a
+! heavyside step function.
+!
+!=====================================================================
+ ! Useful modules
+ !------------------
+ use shr_kind_mod,only:r8=>SHR_KIND_R8,cs=>SHR_KIND_CS,cl=>SHR_KIND_CL
+ use time_manager,only:timemgr_time_ge,timemgr_time_inc,get_curr_date,dtime
+ use phys_grid ,only:scatter_field_to_chunk
+ use cam_abortutils ,only:endrun
+ use spmd_utils ,only:masterproc
+ use cam_logfile ,only:iulog
+#ifdef SPMD
+ use mpishorthand
+#endif
+
+ ! Set all Global values and routines to private by default
+ ! and then explicitly set their exposure.
+ !----------------------------------------------------------
+ implicit none
+ private
+
+ public:: Nudge_Model,Nudge_ON
+ public:: nudging_readnl
+ public:: nudging_init
+ public:: nudging_timestep_init
+ public:: nudging_timestep_tend
+ private::nudging_update_analyses_se
+ private::nudging_update_analyses_eul
+ private::nudging_update_analyses_fv
+ private::nudging_set_PSprofile
+ private::nudging_set_profile
+
+ ! Nudging Parameters
+ !--------------------
+ logical:: Nudge_Model =.false.
+ logical:: Nudge_ON =.false.
+ logical:: Nudge_File_Present=.false.
+ logical:: Nudge_Initialized =.false.
+ character(len=cl) Nudge_Path
+ character(len=cs) Nudge_File,Nudge_File_Template
+ integer Nudge_Times_Per_Day
+ integer Model_Times_Per_Day
+ real(r8) Nudge_Ucoef,Nudge_Vcoef
+ integer Nudge_Uprof,Nudge_Vprof
+ real(r8) Nudge_Qcoef,Nudge_Tcoef
+ integer Nudge_Qprof,Nudge_Tprof
+ real(r8) Nudge_PScoef
+ integer Nudge_PSprof
+ integer Nudge_Beg_Year ,Nudge_Beg_Month
+ integer Nudge_Beg_Day ,Nudge_Beg_Sec
+ integer Nudge_End_Year ,Nudge_End_Month
+ integer Nudge_End_Day ,Nudge_End_Sec
+ integer Nudge_Curr_Year,Nudge_Curr_Month
+ integer Nudge_Curr_Day ,Nudge_Curr_Sec
+ integer Nudge_Next_Year,Nudge_Next_Month
+ integer Nudge_Next_Day ,Nudge_Next_Sec
+ integer Nudge_Step
+ integer Model_Curr_Year,Model_Curr_Month
+ integer Model_Curr_Day ,Model_Curr_Sec
+ integer Model_Next_Year,Model_Next_Month
+ integer Model_Next_Day ,Model_Next_Sec
+ integer Model_Step
+ real(r8) Nudge_Hwin_lo
+ real(r8) Nudge_Hwin_hi
+ real(r8) Nudge_Hwin_lat0
+ real(r8) Nudge_Hwin_latWidth
+ real(r8) Nudge_Hwin_latDelta
+ real(r8) Nudge_Hwin_lon0
+ real(r8) Nudge_Hwin_lonWidth
+ real(r8) Nudge_Hwin_lonDelta
+ real(r8) Nudge_Vwin_lo
+ real(r8) Nudge_Vwin_hi
+ real(r8) Nudge_Vwin_Hindex
+ real(r8) Nudge_Vwin_Hdelta
+ real(r8) Nudge_Vwin_Lindex
+ real(r8) Nudge_Vwin_Ldelta
+ real(r8) Nudge_Hwin_latWidthH
+ real(r8) Nudge_Hwin_lonWidthH
+ real(r8) Nudge_Hwin_max
+ real(r8) Nudge_Hwin_min
+
+ ! Nudging State Arrays
+ !-----------------------
+ integer Nudge_nlon,Nudge_nlat,Nudge_ncol,Nudge_nlev
+!DIAG
+ integer Nudge_slat
+!DIAG
+ real(r8),allocatable::Target_U(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Target_V(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Target_T(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Target_Q(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Target_PS(:,:) !(pcols,begchunk:endchunk)
+ real(r8),allocatable::Model_U(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Model_V(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Model_T(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Model_Q(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Model_PS(:,:) !(pcols,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Utau(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Vtau(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Ttau(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Qtau(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_PStau(:,:) !(pcols,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Ustep(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Vstep(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Tstep(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_Qstep(:,:,:) !(pcols,pver,begchunk:endchunk)
+ real(r8),allocatable::Nudge_PSstep(:,:) !(pcols,begchunk:endchunk)
+
+contains
+ !================================================================
+ subroutine nudging_readnl(nlfile)
+ !
+ ! NUDGING_READNL: Initialize default values controlling the Nudging
+ ! process. Then read namelist values to override
+ ! them.
+ !===============================================================
+ use ppgrid ,only: pver
+ use namelist_utils,only:find_group_name
+ use units ,only:getunit,freeunit
+ !
+ ! Arguments
+ !-------------
+ character(len=*),intent(in)::nlfile
+ !
+ ! Local Values
+ !---------------
+ integer ierr,unitn
+
+ namelist /nudging_nl/ Nudge_Model,Nudge_Path, &
+ Nudge_File_Template,Nudge_Times_Per_Day, &
+ Model_Times_Per_Day, &
+ Nudge_Ucoef ,Nudge_Uprof, &
+ Nudge_Vcoef ,Nudge_Vprof, &
+ Nudge_Qcoef ,Nudge_Qprof, &
+ Nudge_Tcoef ,Nudge_Tprof, &
+ Nudge_PScoef,Nudge_PSprof, &
+ Nudge_Beg_Year,Nudge_Beg_Month,Nudge_Beg_Day, &
+ Nudge_End_Year,Nudge_End_Month,Nudge_End_Day, &
+ Nudge_Hwin_lo,Nudge_Hwin_hi, &
+ Nudge_Vwin_lo,Nudge_Vwin_hi, &
+ Nudge_Hwin_lat0,Nudge_Hwin_lon0, &
+ Nudge_Hwin_latWidth,Nudge_Hwin_lonWidth, &
+ Nudge_Hwin_latDelta,Nudge_Hwin_lonDelta, &
+ Nudge_Vwin_Lindex,Nudge_Vwin_Hindex, &
+ Nudge_Vwin_Ldelta,Nudge_Vwin_Hdelta
+
+ ! Nudging is NOT initialized yet, For now
+ ! Nudging will always begin/end at midnight.
+ !--------------------------------------------
+ Nudge_Initialized =.false.
+ Nudge_ON =.false.
+ Nudge_File_Present=.false.
+ Nudge_Beg_Sec=0
+ Nudge_End_Sec=0
+
+ ! Set Default Namelist values
+ !-----------------------------
+ Nudge_Model =.false.
+ Nudge_Path ='./Data/YOTC_ne30np4_001/'
+ Nudge_File_Template='YOTC_ne30np4_L30.cam2.i.%y-%m-%d-%s.nc'
+ Nudge_Times_Per_Day=4
+ Model_Times_Per_Day=4
+ Nudge_Ucoef =0._r8
+ Nudge_Vcoef =0._r8
+ Nudge_Qcoef =0._r8
+ Nudge_Tcoef =0._r8
+ Nudge_PScoef =0._r8
+ Nudge_Uprof =0
+ Nudge_Vprof =0
+ Nudge_Qprof =0
+ Nudge_Tprof =0
+ Nudge_PSprof =0
+ Nudge_Beg_Year =2008
+ Nudge_Beg_Month=5
+ Nudge_Beg_Day =1
+ Nudge_End_Year =2008
+ Nudge_End_Month=9
+ Nudge_End_Day =1
+ Nudge_Hwin_lo =0.0_r8
+ Nudge_Hwin_hi =1.0_r8
+ Nudge_Hwin_lat0 =0._r8
+ Nudge_Hwin_latWidth=9999._r8
+ Nudge_Hwin_latDelta=1.0_r8
+ Nudge_Hwin_lon0 =180._r8
+ Nudge_Hwin_lonWidth=9999._r8
+ Nudge_Hwin_lonDelta=1.0_r8
+ Nudge_Vwin_lo =0.0_r8
+ Nudge_Vwin_hi =1.0_r8
+ Nudge_Vwin_Hindex =float(pver+1)
+ Nudge_Vwin_Hdelta =0.1_r8
+ Nudge_Vwin_Lindex =0.0_r8
+ Nudge_Vwin_Ldelta =0.1_r8
+
+ ! Read in namelist values
+ !------------------------
+ if(masterproc) then
+ unitn = getunit()
+ open(unitn,file=trim(nlfile),status='old')
+ call find_group_name(unitn,'nudging_nl',status=ierr)
+ if(ierr.eq.0) then
+ read(unitn,nudging_nl,iostat=ierr)
+ if(ierr.ne.0) then
+ call endrun('nudging_readnl:: ERROR reading namelist')
+ endif
+ endif
+ close(unitn)
+ call freeunit(unitn)
+ endif
+
+ ! Check for valid namelist values
+ !----------------------------------
+ if((max(Nudge_Hwin_lo,Nudge_Hwin_hi).ne.1.0).or. &
+ (max(Nudge_Vwin_lo,Nudge_Vwin_hi).ne.1.0) ) then
+ write(iulog,*) 'NUDGING: The window function must have a maximum value of 1'
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lo=',Nudge_Hwin_lo
+ write(iulog,*) 'NUDGING: Nudge_Hwin_hi=',Nudge_Hwin_hi
+ write(iulog,*) 'NUDGING: Nudge_Vwin_lo=',Nudge_Vwin_lo
+ write(iulog,*) 'NUDGING: Nudge_Vwin_hi=',Nudge_Vwin_hi
+ call endrun('nudging_readnl:: ERROR in namelist')
+ endif
+
+ if((Nudge_Hwin_lat0.lt.-90.).or.(Nudge_Hwin_lat0.gt.+90.)) then
+ write(iulog,*) 'NUDGING: Window lat0 must be in [-90,+90]'
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lat0=',Nudge_Hwin_lat0
+ call endrun('nudging_readnl:: ERROR in namelist')
+ endif
+
+ if((Nudge_Hwin_lon0.lt.0.).or.(Nudge_Hwin_lon0.ge.360.)) then
+ write(iulog,*) 'NUDGING: Window lon0 must be in [0,+360)'
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lon0=',Nudge_Hwin_lon0
+ call endrun('nudging_readnl:: ERROR in namelist')
+ endif
+
+ if((Nudge_Vwin_Lindex.gt.Nudge_Vwin_Hindex) .or. &
+ (Nudge_Vwin_Hindex.gt.float(pver+1)).or.(Nudge_Vwin_Hindex.lt.0.).or. &
+ (Nudge_Vwin_Lindex.gt.float(pver+1)).or.(Nudge_Vwin_Lindex.lt.0.) ) then
+ write(iulog,*) 'NUDGING: Window Lindex must be in [0,pver+1]'
+ write(iulog,*) 'NUDGING: Window Hindex must be in [0,pver+1]'
+ write(iulog,*) 'NUDGING: Lindex must be LE than Hindex'
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Lindex=',Nudge_Vwin_Lindex
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Hindex=',Nudge_Vwin_Hindex
+ call endrun('nudging_readnl:: ERROR in namelist')
+ endif
+
+ if((Nudge_Hwin_latDelta.le.0.).or.(Nudge_Hwin_lonDelta.le.0.).or. &
+ (Nudge_Vwin_Hdelta .le.0.).or.(Nudge_Vwin_Ldelta .le.0.) ) then
+ write(iulog,*) 'NUDGING: Window Deltas must be positive'
+ write(iulog,*) 'NUDGING: Nudge_Hwin_latDelta=',Nudge_Hwin_latDelta
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lonDelta=',Nudge_Hwin_lonDelta
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Hdelta=',Nudge_Vwin_Hdelta
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Ldelta=',Nudge_Vwin_Ldelta
+ call endrun('nudging_readnl:: ERROR in namelist')
+
+ endif
+
+ if((Nudge_Hwin_latWidth.le.0.).or.(Nudge_Hwin_lonWidth.le.0.)) then
+ write(iulog,*) 'NUDGING: Window widths must be positive'
+ write(iulog,*) 'NUDGING: Nudge_Hwin_latWidth=',Nudge_Hwin_latWidth
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lonWidth=',Nudge_Hwin_lonWidth
+ call endrun('nudging_readnl:: ERROR in namelist')
+ endif
+
+ ! Broadcast namelist variables
+ !------------------------------
+#ifdef SPMD
+ call mpibcast(Nudge_Path ,len(Nudge_Path) ,mpichar,0,mpicom)
+ call mpibcast(Nudge_File_Template,len(Nudge_File_Template),mpichar,0,mpicom)
+ call mpibcast(Nudge_Model , 1, mpilog, 0, mpicom)
+ call mpibcast(Nudge_Initialized , 1, mpilog, 0, mpicom)
+ call mpibcast(Nudge_ON , 1, mpilog, 0, mpicom)
+ call mpibcast(Nudge_File_Present , 1, mpilog, 0, mpicom)
+ call mpibcast(Nudge_Times_Per_Day, 1, mpiint, 0, mpicom)
+ call mpibcast(Model_Times_Per_Day, 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Ucoef , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Vcoef , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Tcoef , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Qcoef , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_PScoef , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Uprof , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Vprof , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Tprof , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Qprof , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_PSprof , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Beg_Year , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Beg_Month, 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Beg_Day , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Beg_Sec , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_End_Year , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_End_Month, 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_End_Day , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_End_Sec , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Hwin_lo , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_hi , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_lat0 , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_latWidth, 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_latDelta, 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_lon0 , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_lonWidth, 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_lonDelta, 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Vwin_lo , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Vwin_hi , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Vwin_Hindex , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Vwin_Hdelta , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Vwin_Lindex , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Vwin_Ldelta , 1, mpir8 , 0, mpicom)
+#endif
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_readnl
+ !================================================================
+
+
+ !================================================================
+ subroutine nudging_init
+ !
+ ! NUDGING_INIT: Allocate space and initialize Nudging values
+ !===============================================================
+ use ppgrid ,only: pver,pcols,begchunk,endchunk
+ use error_messages,only: alloc_err
+ use dycore ,only: dycore_is
+ use dyn_grid ,only: get_horiz_grid_dim_d
+ use phys_grid ,only: get_rlat_p,get_rlon_p,get_ncols_p
+ use cam_history ,only: addfld,phys_decomp
+ use shr_const_mod ,only: SHR_CONST_PI
+
+ ! Local values
+ !----------------
+ integer Year,Month,Day,Sec
+ integer YMD1,YMD
+ logical After_Beg,Before_End
+ integer istat,lchnk,ncol,icol,ilev
+ integer hdim1_d,hdim2_d
+ real(r8) rlat,rlon
+ real(r8) Wprof(pver)
+ real(r8) lonp,lon0,lonn,latp,lat0,latn
+ real(r8) Val1_p,Val2_p,Val3_p,Val4_p
+ real(r8) Val1_0,Val2_0,Val3_0,Val4_0
+ real(r8) Val1_n,Val2_n,Val3_n,Val4_n
+
+ ! Allocate Space for Nudging data arrays
+ !-----------------------------------------
+ allocate(Target_U(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Target_U',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Target_V(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Target_V',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Target_T(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Target_T',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Target_Q(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Target_Q',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Target_PS(pcols,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Target_PS',pcols*((endchunk-begchunk)+1))
+
+ allocate(Model_U(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Model_U',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Model_V(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Model_V',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Model_T(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Model_T',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Model_Q(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Model_Q',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Model_PS(pcols,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Model_PS',pcols*((endchunk-begchunk)+1))
+
+ ! Allocate Space for spatial dependence of
+ ! Nudging Coefs and Nudging Forcing.
+ !-------------------------------------------
+ allocate(Nudge_Utau(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Utau',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_Vtau(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Vtau',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_Ttau(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Ttau',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_Qtau(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Qtau',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_PStau(pcols,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_PStau',pcols*((endchunk-begchunk)+1))
+
+ allocate(Nudge_Ustep(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Ustep',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_Vstep(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Vstep',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_Tstep(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Tstep',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_Qstep(pcols,pver,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_Qstep',pcols*pver*((endchunk-begchunk)+1))
+ allocate(Nudge_PSstep(pcols,begchunk:endchunk),stat=istat)
+ call alloc_err(istat,'nudging_init','Nudge_PSstep',pcols*((endchunk-begchunk)+1))
+
+ ! Register output fields with the cam history module
+ !-----------------------------------------------------
+ call addfld('Nudge_U','m/s/s' ,pver,'A','U Nudging Tendency',phys_decomp)
+ call addfld('Nudge_V','m/s/s' ,pver,'A','V Nudging Tendency',phys_decomp)
+ call addfld('Nudge_T','cp*K/s' ,pver,'A','T Nudging Tendency',phys_decomp)
+ call addfld('Nudge_Q','kg/kg/s',pver,'A','Q Nudging Tendency',phys_decomp)
+
+ !-----------------------------------------
+ ! Values initialized only by masterproc
+ !-----------------------------------------
+ if(masterproc) then
+
+ ! Set the Stepping intervals for Model and Nudging values
+ ! Ensure that the Model_Step is not smaller then one timestep
+ ! and not larger then the Nudge_Step.
+ !--------------------------------------------------------
+ Model_Step=86400/Model_Times_Per_Day
+ Nudge_Step=86400/Nudge_Times_Per_Day
+ if(Model_Step.lt.dtime) then
+ write(iulog,*) ' '
+ write(iulog,*) 'NUDGING: Model_Step cannot be less than a model timestep'
+ write(iulog,*) 'NUDGING: Setting Model_Step=dtime , dtime=',dtime
+ write(iulog,*) ' '
+ Model_Step=dtime
+ endif
+ if(Model_Step.gt.Nudge_Step) then
+ write(iulog,*) ' '
+ write(iulog,*) 'NUDGING: Model_Step cannot be more than Nudge_Step'
+ write(iulog,*) 'NUDGING: Setting Model_Step=Nudge_Step, Nudge_Step=',Nudge_Step
+ write(iulog,*) ' '
+ Model_Step=Nudge_Step
+ endif
+
+ ! Initialize column and level dimensions
+ !--------------------------------------------------------
+ call get_horiz_grid_dim_d(hdim1_d,hdim2_d)
+ Nudge_nlon=hdim1_d
+ Nudge_nlat=hdim2_d
+ Nudge_ncol=hdim1_d*hdim2_d
+ Nudge_nlev=pver
+!DIAG
+ Nudge_slat=Nudge_nlat-1
+!DIAG
+
+ ! Check the time relative to the nudging window
+ !------------------------------------------------
+ call get_curr_date(Year,Month,Day,Sec)
+ YMD=(Year*10000) + (Month*100) + Day
+ YMD1=(Nudge_Beg_Year*10000) + (Nudge_Beg_Month*100) + Nudge_Beg_Day
+ call timemgr_time_ge(YMD1,Nudge_Beg_Sec, &
+ YMD ,Sec ,After_Beg)
+ YMD1=(Nudge_End_Year*10000) + (Nudge_End_Month*100) + Nudge_End_Day
+ call timemgr_time_ge(YMD ,Sec , &
+ YMD1,Nudge_End_Sec,Before_End)
+
+ if((After_Beg).and.(Before_End)) then
+ ! Set Time indicies so that the next call to
+ ! timestep_init will initialize the data arrays.
+ !--------------------------------------------
+ Model_Next_Year =Year
+ Model_Next_Month=Month
+ Model_Next_Day =Day
+ Model_Next_Sec =(Sec/Model_Step)*Model_Step
+ Nudge_Next_Year =Year
+ Nudge_Next_Month=Month
+ Nudge_Next_Day =Day
+ Nudge_Next_Sec =(Sec/Nudge_Step)*Nudge_Step
+ elseif(.not.After_Beg) then
+ ! Set Time indicies to Nudging start,
+ ! timestep_init will initialize the data arrays.
+ !--------------------------------------------
+ Model_Next_Year =Nudge_Beg_Year
+ Model_Next_Month=Nudge_Beg_Month
+ Model_Next_Day =Nudge_Beg_Day
+ Model_Next_Sec =Nudge_Beg_Sec
+ Nudge_Next_Year =Nudge_Beg_Year
+ Nudge_Next_Month=Nudge_Beg_Month
+ Nudge_Next_Day =Nudge_Beg_Day
+ Nudge_Next_Sec =Nudge_Beg_Sec
+ elseif(.not.Before_End) then
+ ! Nudging will never occur, so switch it off
+ !--------------------------------------------
+ Nudge_Model=.false.
+ Nudge_ON =.false.
+ write(iulog,*) ' '
+ write(iulog,*) 'NUDGING: WARNING - Nudging has been requested by it will'
+ write(iulog,*) 'NUDGING: never occur for the given time values'
+ write(iulog,*) ' '
+ endif
+
+ ! Initialize values for window function
+ !----------------------------------------
+ lonp= 180.
+ lon0= 0.
+ lonn=-180.
+ latp= 90.-Nudge_Hwin_lat0
+ lat0= 0.
+ latn= -90.-Nudge_Hwin_lat0
+
+ Nudge_Hwin_lonWidthH=Nudge_Hwin_lonWidth/2.
+ Nudge_Hwin_latWidthH=Nudge_Hwin_latWidth/2.
+
+ Val1_p=(1.+tanh((Nudge_Hwin_lonWidthH+lonp)/Nudge_Hwin_lonDelta))/2.
+ Val2_p=(1.+tanh((Nudge_Hwin_lonWidthH-lonp)/Nudge_Hwin_lonDelta))/2.
+ Val3_p=(1.+tanh((Nudge_Hwin_latWidthH+latp)/Nudge_Hwin_latDelta))/2.
+ Val4_p=(1.+tanh((Nudge_Hwin_latWidthH-latp)/Nudge_Hwin_latDelta))/2.
+
+ Val1_0=(1.+tanh((Nudge_Hwin_lonWidthH+lon0)/Nudge_Hwin_lonDelta))/2.
+ Val2_0=(1.+tanh((Nudge_Hwin_lonWidthH-lon0)/Nudge_Hwin_lonDelta))/2.
+ Val3_0=(1.+tanh((Nudge_Hwin_latWidthH+lat0)/Nudge_Hwin_latDelta))/2.
+ Val4_0=(1.+tanh((Nudge_Hwin_latWidthH-lat0)/Nudge_Hwin_latDelta))/2.
+
+ Val1_n=(1.+tanh((Nudge_Hwin_lonWidthH+lonn)/Nudge_Hwin_lonDelta))/2.
+ Val2_n=(1.+tanh((Nudge_Hwin_lonWidthH-lonn)/Nudge_Hwin_lonDelta))/2.
+ Val3_n=(1.+tanh((Nudge_Hwin_latWidthH+latn)/Nudge_Hwin_latDelta))/2.
+ Val4_n=(1.+tanh((Nudge_Hwin_latWidthH-latn)/Nudge_Hwin_latDelta))/2.
+
+ Nudge_Hwin_max= Val1_0*Val2_0*Val3_0*Val4_0
+ Nudge_Hwin_min=min((Val1_p*Val2_p*Val3_n*Val4_n), &
+ (Val1_p*Val2_p*Val3_p*Val4_p), &
+ (Val1_n*Val2_n*Val3_n*Val4_n), &
+ (Val1_n*Val2_n*Val3_p*Val4_p))
+
+ ! Initialization is done,
+ !--------------------------
+ Nudge_Initialized=.true.
+
+ ! Check that this is a valid DYCORE model
+ !------------------------------------------
+ if((.not.dycore_is('UNSTRUCTURED')).and. &
+ (.not.dycore_is('EUL') ).and. &
+ (.not.dycore_is('LR') ) ) then
+ call endrun('NUDGING IS CURRENTLY ONLY CONFIGURED FOR CAM-SE, FV, or EUL')
+ endif
+
+ ! Informational Output
+ !---------------------------
+ write(iulog,*) ' '
+ write(iulog,*) '---------------------------------------------------------'
+ write(iulog,*) ' MODEL NUDGING INITIALIZED WITH THE FOLLOWING SETTINGS: '
+ write(iulog,*) '---------------------------------------------------------'
+ write(iulog,*) 'NUDGING: Nudge_Model=',Nudge_Model
+ write(iulog,*) 'NUDGING: Nudge_Path=',Nudge_Path
+ write(iulog,*) 'NUDGING: Nudge_File_Template=',Nudge_File_Template
+ write(iulog,*) 'NUDGING: Nudge_Times_Per_Day=',Nudge_Times_Per_Day
+ write(iulog,*) 'NUDGING: Model_Times_Per_Day=',Model_Times_Per_Day
+ write(iulog,*) 'NUDGING: Nudge_Step=',Nudge_Step
+ write(iulog,*) 'NUDGING: Model_Step=',Model_Step
+ write(iulog,*) 'NUDGING: Nudge_Ucoef =',Nudge_Ucoef
+ write(iulog,*) 'NUDGING: Nudge_Vcoef =',Nudge_Vcoef
+ write(iulog,*) 'NUDGING: Nudge_Qcoef =',Nudge_Qcoef
+ write(iulog,*) 'NUDGING: Nudge_Tcoef =',Nudge_Tcoef
+ write(iulog,*) 'NUDGING: Nudge_PScoef =',Nudge_PScoef
+ write(iulog,*) 'NUDGING: Nudge_Uprof =',Nudge_Uprof
+ write(iulog,*) 'NUDGING: Nudge_Vprof =',Nudge_Vprof
+ write(iulog,*) 'NUDGING: Nudge_Qprof =',Nudge_Qprof
+ write(iulog,*) 'NUDGING: Nudge_Tprof =',Nudge_Tprof
+ write(iulog,*) 'NUDGING: Nudge_PSprof =',Nudge_PSprof
+ write(iulog,*) 'NUDGING: Nudge_Beg_Year =',Nudge_Beg_Year
+ write(iulog,*) 'NUDGING: Nudge_Beg_Month=',Nudge_Beg_Month
+ write(iulog,*) 'NUDGING: Nudge_Beg_Day =',Nudge_Beg_Day
+ write(iulog,*) 'NUDGING: Nudge_End_Year =',Nudge_End_Year
+ write(iulog,*) 'NUDGING: Nudge_End_Month=',Nudge_End_Month
+ write(iulog,*) 'NUDGING: Nudge_End_Day =',Nudge_End_Day
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lo =',Nudge_Hwin_lo
+ write(iulog,*) 'NUDGING: Nudge_Hwin_hi =',Nudge_Hwin_hi
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lat0 =',Nudge_Hwin_lat0
+ write(iulog,*) 'NUDGING: Nudge_Hwin_latWidth =',Nudge_Hwin_latWidth
+ write(iulog,*) 'NUDGING: Nudge_Hwin_latDelta =',Nudge_Hwin_latDelta
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lon0 =',Nudge_Hwin_lon0
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lonWidth =',Nudge_Hwin_lonWidth
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lonDelta =',Nudge_Hwin_lonDelta
+ write(iulog,*) 'NUDGING: Nudge_Vwin_lo =',Nudge_Vwin_lo
+ write(iulog,*) 'NUDGING: Nudge_Vwin_hi =',Nudge_Vwin_hi
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Hindex =',Nudge_Vwin_Hindex
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Hdelta =',Nudge_Vwin_Hdelta
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Lindex =',Nudge_Vwin_Lindex
+ write(iulog,*) 'NUDGING: Nudge_Vwin_Ldelta =',Nudge_Vwin_Ldelta
+ write(iulog,*) 'NUDGING: Nudge_Hwin_latWidthH=',Nudge_Hwin_latWidthH
+ write(iulog,*) 'NUDGING: Nudge_Hwin_lonWidthH=',Nudge_Hwin_lonWidthH
+ write(iulog,*) 'NUDGING: Nudge_Hwin_max =',Nudge_Hwin_max
+ write(iulog,*) 'NUDGING: Nudge_Hwin_min =',Nudge_Hwin_min
+ write(iulog,*) 'NUDGING: Nudge_Initialized =',Nudge_Initialized
+ write(iulog,*) ' '
+ write(iulog,*) ' '
+
+ endif ! (masterproc) then
+
+ ! Broadcast other variables that have changed
+ !---------------------------------------------
+#ifdef SPMD
+ call mpibcast(Model_Step , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Step , 1, mpir8 , 0, mpicom)
+ call mpibcast(Model_Next_Year , 1, mpiint, 0, mpicom)
+ call mpibcast(Model_Next_Month , 1, mpiint, 0, mpicom)
+ call mpibcast(Model_Next_Day , 1, mpiint, 0, mpicom)
+ call mpibcast(Model_Next_Sec , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Next_Year , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Next_Month , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Next_Day , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Next_Sec , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Model , 1, mpilog, 0, mpicom)
+ call mpibcast(Nudge_ON , 1, mpilog, 0, mpicom)
+ call mpibcast(Nudge_Initialized , 1, mpilog, 0, mpicom)
+ call mpibcast(Nudge_ncol , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_nlev , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_nlon , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_nlat , 1, mpiint, 0, mpicom)
+ call mpibcast(Nudge_Hwin_max , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_min , 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_lonWidthH, 1, mpir8 , 0, mpicom)
+ call mpibcast(Nudge_Hwin_latWidthH, 1, mpir8 , 0, mpicom)
+!DIAG
+ call mpibcast(Nudge_slat , 1, mpiint, 0, mpicom)
+!DIAG
+#endif
+
+ ! Initialize Nudging Coeffcient profiles in local arrays
+ ! Load zeros into nudging arrays
+ !------------------------------------------------------
+ do lchnk=begchunk,endchunk
+ ncol=get_ncols_p(lchnk)
+ do icol=1,ncol
+ rlat=get_rlat_p(lchnk,icol)*180._r8/SHR_CONST_PI
+ rlon=get_rlon_p(lchnk,icol)*180._r8/SHR_CONST_PI
+
+ call nudging_set_profile(rlat,rlon,Nudge_Uprof,Wprof,pver)
+ Nudge_Utau(icol,:,lchnk)=Wprof(:)
+ call nudging_set_profile(rlat,rlon,Nudge_Vprof,Wprof,pver)
+ Nudge_Vtau(icol,:,lchnk)=Wprof(:)
+ call nudging_set_profile(rlat,rlon,Nudge_Tprof,Wprof,pver)
+ Nudge_Ttau(icol,:,lchnk)=Wprof(:)
+ call nudging_set_profile(rlat,rlon,Nudge_Qprof,Wprof,pver)
+ Nudge_Qtau(icol,:,lchnk)=Wprof(:)
+
+ Nudge_PStau(icol,lchnk)=nudging_set_PSprofile(rlat,rlon,Nudge_PSprof)
+ end do
+ Nudge_Utau(:ncol,:pver,lchnk) = &
+ Nudge_Utau(:ncol,:pver,lchnk) * Nudge_Ucoef/float(Nudge_Step)
+ Nudge_Vtau(:ncol,:pver,lchnk) = &
+ Nudge_Vtau(:ncol,:pver,lchnk) * Nudge_Vcoef/float(Nudge_Step)
+ Nudge_Ttau(:ncol,:pver,lchnk) = &
+ Nudge_Ttau(:ncol,:pver,lchnk) * Nudge_Tcoef/float(Nudge_Step)
+ Nudge_Qtau(:ncol,:pver,lchnk) = &
+ Nudge_Qtau(:ncol,:pver,lchnk) * Nudge_Qcoef/float(Nudge_Step)
+ Nudge_PStau(:ncol,lchnk)= &
+ Nudge_PStau(:ncol,lchnk)* Nudge_PScoef/float(Nudge_Step)
+
+ Nudge_Ustep(:pcols,:pver,lchnk)=0._r8
+ Nudge_Vstep(:pcols,:pver,lchnk)=0._r8
+ Nudge_Tstep(:pcols,:pver,lchnk)=0._r8
+ Nudge_Qstep(:pcols,:pver,lchnk)=0._r8
+ Nudge_PSstep(:pcols,lchnk)=0._r8
+ Target_U(:pcols,:pver,lchnk)=0._r8
+ Target_V(:pcols,:pver,lchnk)=0._r8
+ Target_T(:pcols,:pver,lchnk)=0._r8
+ Target_Q(:pcols,:pver,lchnk)=0._r8
+ Target_PS(:pcols,lchnk)=0._r8
+ end do
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_init
+ !================================================================
+
+
+ !================================================================
+ subroutine nudging_timestep_init(phys_state)
+ !
+ ! NUDGING_TIMESTEP_INIT:
+ ! Check the current time and update Model/Nudging
+ ! arrays when necessary. Toggle the Nudging flag
+ ! when the time is withing the nudging window.
+ !===============================================================
+ use physics_types,only: physics_state
+ use constituents ,only: cnst_get_ind
+ use dycore ,only: dycore_is
+ use ppgrid ,only: pver,pcols,begchunk,endchunk
+ use filenames ,only: interpret_filename_spec
+ use physconst ,only: cpair
+
+ ! Arguments
+ !-----------
+ type(physics_state),intent(in):: phys_state(begchunk:endchunk)
+
+ ! Local values
+ !----------------
+ integer Year,Month,Day,Sec
+ integer YMD1,YMD2,YMD
+ logical Update_Model,Update_Nudge,Sync_Error
+ logical After_Beg ,Before_End
+ integer lchnk,ncol,indw
+
+ ! Check if Nudging is initialized
+ !---------------------------------
+ if(.not.Nudge_Initialized) then
+ call endrun('nudging_timestep_init:: Nudging NOT Initialized')
+ endif
+
+ ! Get Current time
+ !--------------------
+ call get_curr_date(Year,Month,Day,Sec)
+ YMD=(Year*10000) + (Month*100) + Day
+
+ !-------------------------------------------------------
+ ! Determine if the current time is AFTER the begining time
+ ! and if it is BEFORE the ending time.
+ !-------------------------------------------------------
+ YMD1=(Nudge_Beg_Year*10000) + (Nudge_Beg_Month*100) + Nudge_Beg_Day
+ call timemgr_time_ge(YMD1,Nudge_Beg_Sec, &
+ YMD ,Sec ,After_Beg)
+
+ YMD1=(Nudge_End_Year*10000) + (Nudge_End_Month*100) + Nudge_End_Day
+ call timemgr_time_ge(YMD ,Sec, &
+ YMD1,Nudge_End_Sec,Before_End)
+
+ !--------------------------------------------------------------
+ ! When past the NEXT time, Update Model Arrays and time indices
+ !--------------------------------------------------------------
+ YMD1=(Model_Next_Year*10000) + (Model_Next_Month*100) + Model_Next_Day
+ call timemgr_time_ge(YMD1,Model_Next_Sec, &
+ YMD ,Sec ,Update_Model)
+
+ if((Before_End).and.(Update_Model)) then
+ ! Increment the Model times by the current interval
+ !---------------------------------------------------
+ Model_Curr_Year =Model_Next_Year
+ Model_Curr_Month=Model_Next_Month
+ Model_Curr_Day =Model_Next_Day
+ Model_Curr_Sec =Model_Next_Sec
+ YMD1=(Model_Curr_Year*10000) + (Model_Curr_Month*100) + Model_Curr_Day
+ call timemgr_time_inc(YMD1,Model_Curr_Sec, &
+ YMD2,Model_Next_Sec,Model_Step,0,0)
+
+ ! Check for Sync Error where NEXT model time after the update
+ ! is before the current time. If so, reset the next model
+ ! time to a Model_Step after the current time.
+ !--------------------------------------------------------------
+ call timemgr_time_ge(YMD2,Model_Next_Sec, &
+ YMD ,Sec ,Sync_Error)
+ if(Sync_Error) then
+ Model_Curr_Year =Year
+ Model_Curr_Month=Month
+ Model_Curr_Day =Day
+ Model_Curr_Sec =Sec
+ call timemgr_time_inc(YMD ,Model_Curr_Sec, &
+ YMD2,Model_Next_Sec,Model_Step,0,0)
+ write(iulog,*) 'NUDGING: WARNING - Model_Time Sync ERROR... CORRECTED'
+ endif
+ Model_Next_Year =(YMD2/10000)
+ YMD2 = YMD2-(Model_Next_Year*10000)
+ Model_Next_Month=(YMD2/100)
+ Model_Next_Day = YMD2-(Model_Next_Month*100)
+
+ ! Load values at Current into the Model arrays
+ !-----------------------------------------------
+ call cnst_get_ind('Q',indw)
+ do lchnk=begchunk,endchunk
+ ncol=phys_state(lchnk)%ncol
+ Model_U(:ncol,:pver,lchnk)=phys_state(lchnk)%u(:ncol,:pver)
+ Model_V(:ncol,:pver,lchnk)=phys_state(lchnk)%v(:ncol,:pver)
+ Model_T(:ncol,:pver,lchnk)=phys_state(lchnk)%t(:ncol,:pver)
+ Model_Q(:ncol,:pver,lchnk)=phys_state(lchnk)%q(:ncol,:pver,indw)
+ Model_PS(:ncol,lchnk)=phys_state(lchnk)%ps(:ncol)
+ end do
+ endif
+
+ !----------------------------------------------------------------
+ ! When past the NEXT time, Update Nudging Arrays and time indices
+ !----------------------------------------------------------------
+ YMD1=(Nudge_Next_Year*10000) + (Nudge_Next_Month*100) + Nudge_Next_Day
+ call timemgr_time_ge(YMD1,Nudge_Next_Sec, &
+ YMD ,Sec ,Update_Nudge)
+
+ if((Before_End).and.(Update_Nudge)) then
+ ! Increment the Nudge times by the current interval
+ !---------------------------------------------------
+ Nudge_Curr_Year =Nudge_Next_Year
+ Nudge_Curr_Month=Nudge_Next_Month
+ Nudge_Curr_Day =Nudge_Next_Day
+ Nudge_Curr_Sec =Nudge_Next_Sec
+ YMD1=(Nudge_Curr_Year*10000) + (Nudge_Curr_Month*100) + Nudge_Curr_Day
+ call timemgr_time_inc(YMD1,Nudge_Curr_Sec, &
+ YMD2,Nudge_Next_Sec,Nudge_Step,0,0)
+ Nudge_Next_Year =(YMD2/10000)
+ YMD2 = YMD2-(Nudge_Next_Year*10000)
+ Nudge_Next_Month=(YMD2/100)
+ Nudge_Next_Day = YMD2-(Nudge_Next_Month*100)
+
+ ! Update the Nudge arrays with analysis
+ ! data at the NEXT time
+ !-----------------------------------------------
+ Nudge_File=interpret_filename_spec(Nudge_File_Template , &
+ yr_spec=Nudge_Next_Year , &
+ mon_spec=Nudge_Next_Month, &
+ day_spec=Nudge_Next_Day , &
+ sec_spec=Nudge_Next_Sec )
+ if(masterproc) then
+ write(iulog,*) 'NUDGING: Reading analyses:',trim(Nudge_Path)//trim(Nudge_File)
+ endif
+
+ ! How to manage MISSING values when there are 'Gaps' in the analyses data?
+ ! Check for analyses file existence. If it is there, then read data.
+ ! If it is not, then issue a warning and switch off nudging to 'coast'
+ ! thru the gap.
+ !------------------------------------------------------------------------
+ if(dycore_is('UNSTRUCTURED')) then
+ call nudging_update_analyses_se(trim(Nudge_Path)//trim(Nudge_File))
+ elseif(dycore_is('EUL')) then
+ call nudging_update_analyses_eul(trim(Nudge_Path)//trim(Nudge_File))
+ else !if(dycore_is('LR')) then
+ call nudging_update_analyses_fv(trim(Nudge_Path)//trim(Nudge_File))
+ endif
+ endif
+
+ !-------------------------------------------------------
+ ! Toggle Nudging flag when the time interval is between
+ ! beginning and ending times, and the analyses file exists.
+ !-------------------------------------------------------
+ if((After_Beg).and.(Before_End)) then
+ if(Nudge_File_Present) then
+ Nudge_ON=.true.
+ else
+ Nudge_ON=.false.
+ if(masterproc) then
+ write(iulog,*) 'NUDGING: WARNING - analyses file NOT FOUND. Switching '
+ write(iulog,*) 'NUDGING: nudging OFF to coast thru the gap. '
+ endif
+ endif
+ else
+ Nudge_ON=.false.
+ endif
+
+ !-------------------------------------------------------
+ ! HERE Implement time dependence of Nudging Coefs HERE
+ !-------------------------------------------------------
+
+
+
+ !---------------------------------------------------
+ ! If Data arrays have changed update stepping arrays
+ !---------------------------------------------------
+ if((Before_End).and.((Update_Nudge).or.(Update_Model))) then
+ do lchnk=begchunk,endchunk
+ ncol=phys_state(lchnk)%ncol
+ Nudge_Ustep(:ncol,:pver,lchnk)=( Target_U(:ncol,:pver,lchnk) &
+ -Model_U(:ncol,:pver,lchnk)) &
+ *Nudge_Utau(:ncol,:pver,lchnk)
+ Nudge_Vstep(:ncol,:pver,lchnk)=( Target_V(:ncol,:pver,lchnk) &
+ -Model_V(:ncol,:pver,lchnk)) &
+ *Nudge_Vtau(:ncol,:pver,lchnk)
+ Nudge_Tstep(:ncol,:pver,lchnk)=( Target_T(:ncol,:pver,lchnk) &
+ -Model_T(:ncol,:pver,lchnk)) &
+ *Nudge_Ttau(:ncol,:pver,lchnk)*cpair
+ Nudge_Qstep(:ncol,:pver,lchnk)=( Target_Q(:ncol,:pver,lchnk) &
+ -Model_Q(:ncol,:pver,lchnk)) &
+ *Nudge_Qtau(:ncol,:pver,lchnk)
+ Nudge_PSstep(:ncol, lchnk)=( Target_PS(:ncol,lchnk) &
+ -Model_PS(:ncol,lchnk)) &
+ *Nudge_PStau(:ncol,lchnk)
+ end do
+
+ !******************
+ ! DIAG
+ !******************
+! if(masterproc) then
+! write(iulog,*) 'PFC: Target_T(1,:pver,begchunk)=',Target_T(1,:pver,begchunk)
+! write(iulog,*) 'PFC: Model_T(1,:pver,begchunk)=',Model_T(1,:pver,begchunk)
+! write(iulog,*) 'PFC: Nudge_Tstep(1,:pver,begchunk)=',Nudge_Tstep(1,:pver,begchunk)
+! write(iulog,*) 'PFC: Nudge_Xstep arrays updated:'
+! endif
+ endif
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_timestep_init
+ !================================================================
+
+
+ !================================================================
+ subroutine nudging_timestep_tend(phys_state,phys_tend)
+ !
+ ! NUDGING_TIMESTEP_TEND:
+ ! If Nudging is ON, return the Nudging contributions
+ ! to forcing using the current contents of the Nudge
+ ! arrays. Send output to the cam history module as well.
+ !===============================================================
+ use physics_types,only: physics_state,physics_ptend,physics_ptend_init
+ use constituents ,only: cnst_get_ind,pcnst
+ use ppgrid ,only: pver,pcols,begchunk,endchunk
+ use cam_history ,only: outfld
+
+ ! Arguments
+ !-------------
+ type(physics_state), intent(in) :: phys_state
+ type(physics_ptend), intent(out):: phys_tend
+
+ ! Local values
+ !--------------------
+ integer indw,ncol,lchnk
+ logical lq(pcnst)
+
+ call cnst_get_ind('Q',indw)
+ lq(:) =.false.
+ lq(indw)=.true.
+ call physics_ptend_init(phys_tend,phys_state%psetcols,'nudging',lu=.true.,lv=.true.,ls=.true.,lq=lq)
+
+ if(Nudge_ON) then
+ lchnk=phys_state%lchnk
+ ncol =phys_state%ncol
+ phys_tend%u(:ncol,:pver) =Nudge_Ustep(:ncol,:pver,lchnk)
+ phys_tend%v(:ncol,:pver) =Nudge_Vstep(:ncol,:pver,lchnk)
+ phys_tend%s(:ncol,:pver) =Nudge_Tstep(:ncol,:pver,lchnk)
+ phys_tend%q(:ncol,:pver,indw)=Nudge_Qstep(:ncol,:pver,lchnk)
+
+ call outfld('Nudge_U',phys_tend%u ,pcols,lchnk)
+ call outfld('Nudge_V',phys_tend%v ,pcols,lchnk)
+ call outfld('Nudge_T',phys_tend%s ,pcols,lchnk)
+ call outfld('Nudge_Q',phys_tend%q(1,1,indw),pcols,lchnk)
+ endif
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_timestep_tend
+ !================================================================
+
+
+ !================================================================
+ subroutine nudging_update_analyses_se(anal_file)
+ !
+ ! NUDGING_UPDATE_ANALYSES_SE:
+ ! Open the given analyses data file, read in
+ ! U,V,T,Q, and PS values and then distribute
+ ! the values to all of the chunks.
+ !===============================================================
+! use wrap_nf
+ use ppgrid ,only: pver
+ use netcdf
+
+ ! Arguments
+ !-------------
+ character(len=*),intent(in):: anal_file
+
+ ! Local values
+ !-------------
+ integer lev
+ integer ncol,plev,istat
+ integer ncid,varid
+ real(r8) Xanal(Nudge_ncol,Nudge_nlev)
+ real(r8) PSanal(Nudge_ncol)
+ real(r8) Lat_anal(Nudge_ncol)
+ real(r8) Lon_anal(Nudge_ncol)
+
+ ! Check the existence of the analyses file; broadcast the file status to
+ ! all the other MPI nodes. If the file is not there, then just return.
+ !------------------------------------------------------------------------
+ if(masterproc) then
+ inquire(FILE=trim(anal_file),EXIST=Nudge_File_Present)
+ endif
+#ifdef SPMD
+ call mpibcast(Nudge_File_Present, 1, mpilog, 0, mpicom)
+#endif
+ if(.not.Nudge_File_Present) return
+
+ ! masterporc does all of the work here
+ !-----------------------------------------
+ if(masterproc) then
+
+ ! Open the given file
+ !-----------------------
+ istat=nf90_open(trim(anal_file),NF90_NOWRITE,ncid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*)'NF90_OPEN: failed for file ',trim(anal_file)
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+
+ ! Read in Dimensions
+ !--------------------
+! call wrap_inq_dimid (ncid,'ncol',varid)
+! call wrap_inq_dimlen(ncid,varid,ncol)
+ istat=nf90_inq_dimid(ncid,'ncol',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=ncol)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+
+! call wrap_inq_dimid (ncid,'lev',varid)
+! call wrap_inq_dimlen(ncid,varid,plev)
+ istat=nf90_inq_dimid(ncid,'lev',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=plev)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+
+! call wrap_inq_varid(ncid,'lon',varid)
+! call wrap_get_var_realx(ncid,varid,Lon_anal)
+ istat=nf90_inq_varid(ncid,'lon',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_get_var(ncid,varid,Lon_anal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+
+! call wrap_inq_varid(ncid,'lat',varid)
+! call wrap_get_var_realx(ncid,varid,Lat_anal)
+ istat=nf90_inq_varid(ncid,'lat',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_get_var(ncid,varid,Lat_anal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+
+ if((Nudge_ncol.ne.ncol).or.(plev.ne.pver)) then
+ write(iulog,*) 'ERROR: nudging_update_analyses_se: ncol=',ncol,' Nudge_ncol=',Nudge_ncol
+ write(iulog,*) 'ERROR: nudging_update_analyses_se: plev=',plev,' pver=',pver
+ call endrun('nudging_update_analyses_se: analyses dimension mismatch')
+ endif
+
+ ! Read in and scatter data arrays
+ !----------------------------------
+! call wrap_inq_varid (ncid,'U',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'U',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_ncol,Xanal ,Target_U)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'V',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'V',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_ncol,Xanal ,Target_V)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'T',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'T',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_ncol,Xanal ,Target_T)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'Q',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'Q',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_ncol,Xanal ,Target_Q)
+
+ if(masterproc) then
+!! call wrap_inq_varid (ncid,'PS',varid)
+!! call wrap_get_var_realx(ncid,varid,PSanal)
+! istat=nf90_inq_varid(ncid,'PS',varid)
+! if(istat.ne.NF90_NOERR) then
+! write(iulog,*) nf90_strerror(istat)
+! call endrun ('UPDATE_ANALYSES_SE')
+! endif
+! istat=nf90_get_var(ncid,varid,PSanal)
+! if(istat.ne.NF90_NOERR) then
+! write(iulog,*) nf90_strerror(istat)
+! call endrun ('UPDATE_ANALYSES_SE')
+! endif
+
+ ! Close the analyses file
+ !-----------------------
+! call wrap_close(ncid)
+ istat=nf90_close(ncid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_SE')
+ endif
+ endif ! (masterproc) then
+! call scatter_field_to_chunk(1, 1,1,Nudge_ncol,PSanal,Target_PS)
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_update_analyses_se
+ !================================================================
+
+
+ !================================================================
+ subroutine nudging_update_analyses_eul(anal_file)
+ !
+ ! NUDGING_UPDATE_ANALYSES_EUL:
+ ! Open the given analyses data file, read in
+ ! U,V,T,Q, and PS values and then distribute
+ ! the values to all of the chunks.
+ !===============================================================
+! use wrap_nf
+ use ppgrid ,only: pver
+ use netcdf
+
+ ! Arguments
+ !-------------
+ character(len=*),intent(in):: anal_file
+
+ ! Local values
+ !-------------
+ integer lev
+ integer nlon,nlat,plev,istat
+ integer ncid,varid
+ integer ilat,ilon,ilev
+ real(r8) Xanal(Nudge_nlon,Nudge_nlat,Nudge_nlev)
+ real(r8) PSanal(Nudge_nlon,Nudge_nlat)
+ real(r8) Lat_anal(Nudge_nlat)
+ real(r8) Lon_anal(Nudge_nlon)
+ real(r8) Xtrans(Nudge_nlon,Nudge_nlev,Nudge_nlat)
+
+ ! Check the existence of the analyses file; broadcast the file status to
+ ! all the other MPI nodes. If the file is not there, then just return.
+ !------------------------------------------------------------------------
+ if(masterproc) then
+ inquire(FILE=trim(anal_file),EXIST=Nudge_File_Present)
+ endif
+#ifdef SPMD
+ call mpibcast(Nudge_File_Present, 1, mpilog, 0, mpicom)
+#endif
+ if(.not.Nudge_File_Present) return
+
+ ! masterporc does all of the work here
+ !-----------------------------------------
+ if(masterproc) then
+
+ ! Open the given file
+ !-----------------------
+ istat=nf90_open(trim(anal_file),NF90_NOWRITE,ncid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*)'NF90_OPEN: failed for file ',trim(anal_file)
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+
+ ! Read in Dimensions
+ !--------------------
+! call wrap_inq_dimid (ncid,'lon',varid)
+! call wrap_inq_dimlen(ncid,varid,nlon)
+ istat=nf90_inq_dimid(ncid,'lon',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=nlon)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+
+! call wrap_inq_dimid (ncid,'lat',varid)
+! call wrap_inq_dimlen(ncid,varid,nlat)
+ istat=nf90_inq_dimid(ncid,'lat',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=nlat)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+
+! call wrap_inq_dimid (ncid,'lev',varid)
+! call wrap_inq_dimlen(ncid,varid,plev)
+ istat=nf90_inq_dimid(ncid,'lev',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=plev)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+
+! call wrap_inq_varid(ncid,'lon',varid)
+! call wrap_get_var_realx(ncid,varid,Lon_anal)
+ istat=nf90_inq_varid(ncid,'lon',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_get_var(ncid,varid,Lon_anal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+
+! call wrap_inq_varid(ncid,'lat',varid)
+! call wrap_get_var_realx(ncid,varid,Lat_anal)
+ istat=nf90_inq_varid(ncid,'lat',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_get_var(ncid,varid,Lat_anal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+
+ if((Nudge_nlon.ne.nlon).or.(Nudge_nlat.ne.nlat).or.(plev.ne.pver)) then
+ write(iulog,*) 'ERROR: nudging_update_analyses_eul: nlon=',nlon,' Nudge_nlon=',Nudge_nlon
+ write(iulog,*) 'ERROR: nudging_update_analyses_eul: nlat=',nlat,' Nudge_nlat=',Nudge_nlat
+ write(iulog,*) 'ERROR: nudging_update_analyses_eul: plev=',plev,' pver=',pver
+ call endrun('nudging_update_analyses_eul: analyses dimension mismatch')
+ endif
+
+ ! Read in, transpose lat/lev indices,
+ ! and scatter data arrays
+ !----------------------------------
+! call wrap_inq_varid (ncid,'U',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'U',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ do ilat=1,nlat
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_U)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'V',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'V',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ do ilat=1,nlat
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_V)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'T',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'T',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ do ilat=1,nlat
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_T)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'Q',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'Q',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ do ilat=1,nlat
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_Q)
+
+ if(masterproc) then
+!! call wrap_inq_varid (ncid,'PS',varid)
+!! call wrap_get_var_realx(ncid,varid,PSanal)
+! istat=nf90_inq_varid(ncid,'PS',varid)
+! if(istat.ne.NF90_NOERR) then
+! write(iulog,*) nf90_strerror(istat)
+! call endrun ('UPDATE_ANALYSES_SE')
+! endif
+! istat=nf90_get_var(ncid,varid,PSanal)
+! if(istat.ne.NF90_NOERR) then
+! write(iulog,*) nf90_strerror(istat)
+! call endrun ('UPDATE_ANALYSES_SE')
+! endif
+
+ ! Close the analyses file
+ !-----------------------
+! call wrap_close(ncid)
+ istat=nf90_close(ncid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ endif ! (masterproc) then
+! call scatter_field_to_chunk(1, 1,1,Nudge_nlon,PSanal,Target_PS)
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_update_analyses_eul
+ !================================================================
+
+
+ !================================================================
+ subroutine nudging_update_analyses_fv(anal_file)
+ !
+ ! NUDGING_UPDATE_ANALYSES_FV:
+ ! Open the given analyses data file, read in
+ ! U,V,T,Q, and PS values and then distribute
+ ! the values to all of the chunks.
+ !===============================================================
+! use wrap_nf
+ use ppgrid ,only: pver
+ use netcdf
+
+ ! Arguments
+ !-------------
+ character(len=*),intent(in):: anal_file
+
+ ! Local values
+ !-------------
+ integer lev
+ integer nlon,nlat,plev,istat
+ integer ncid,varid
+ integer ilat,ilon,ilev
+ real(r8) Xanal(Nudge_nlon,Nudge_nlat,Nudge_nlev)
+ real(r8) PSanal(Nudge_nlon,Nudge_nlat)
+ real(r8) Lat_anal(Nudge_nlat)
+ real(r8) Lon_anal(Nudge_nlon)
+ real(r8) Xtrans(Nudge_nlon,Nudge_nlev,Nudge_nlat)
+!DIAG
+ real(r8) Uanal(Nudge_nlon,Nudge_slat,Nudge_nlev)
+!DIAG
+
+ ! Check the existence of the analyses file; broadcast the file status to
+ ! all the other MPI nodes. If the file is not there, then just return.
+ !------------------------------------------------------------------------
+ if(masterproc) then
+ inquire(FILE=trim(anal_file),EXIST=Nudge_File_Present)
+ endif
+#ifdef SPMD
+ call mpibcast(Nudge_File_Present, 1, mpilog, 0, mpicom)
+#endif
+ if(.not.Nudge_File_Present) return
+
+ ! masterporc does all of the work here
+ !-----------------------------------------
+ if(masterproc) then
+
+ ! Open the given file
+ !-----------------------
+ istat=nf90_open(trim(anal_file),NF90_NOWRITE,ncid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*)'NF90_OPEN: failed for file ',trim(anal_file)
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+
+ ! Read in Dimensions
+ !--------------------
+! call wrap_inq_dimid (ncid,'lon',varid)
+! call wrap_inq_dimlen(ncid,varid,nlon)
+ istat=nf90_inq_dimid(ncid,'lon',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=nlon)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+
+! call wrap_inq_dimid (ncid,'lat',varid)
+! call wrap_inq_dimlen(ncid,varid,nlat)
+ istat=nf90_inq_dimid(ncid,'lat',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=nlat)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+
+! call wrap_inq_dimid (ncid,'lev',varid)
+! call wrap_inq_dimlen(ncid,varid,plev)
+ istat=nf90_inq_dimid(ncid,'lev',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_inquire_dimension(ncid,varid,len=plev)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+
+! call wrap_inq_varid(ncid,'lon',varid)
+! call wrap_get_var_realx(ncid,varid,Lon_anal)
+ istat=nf90_inq_varid(ncid,'lon',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_get_var(ncid,varid,Lon_anal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+
+! call wrap_inq_varid(ncid,'lat',varid)
+! call wrap_get_var_realx(ncid,varid,Lat_anal)
+ istat=nf90_inq_varid(ncid,'lat',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_get_var(ncid,varid,Lat_anal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+
+ if((Nudge_nlon.ne.nlon).or.(Nudge_nlat.ne.nlat).or.(plev.ne.pver)) then
+ write(iulog,*) 'ERROR: nudging_update_analyses_fv: nlon=',nlon,' Nudge_nlon=',Nudge_nlon
+ write(iulog,*) 'ERROR: nudging_update_analyses_fv: nlat=',nlat,' Nudge_nlat=',Nudge_nlat
+ write(iulog,*) 'ERROR: nudging_update_analyses_fv: plev=',plev,' pver=',pver
+ call endrun('nudging_update_analyses_fv: analyses dimension mismatch')
+ endif
+
+ ! Read in, transpose lat/lev indices,
+ ! and scatter data arrays
+ !----------------------------------
+!DIAG: Dont have U, so jam US into U so tests can proceed:
+!DIAG call wrap_inq_varid (ncid,'U',varid)
+!DIAG call wrap_get_var_realx(ncid,varid,Xanal)
+!DIAG do ilat=1,nlat
+!DIAG do ilev=1,plev
+!DIAG do ilon=1,nlon
+!DIAG Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+!DIAG end do
+!DIAG end do
+!DIAG end do
+! call wrap_inq_varid (ncid,'US',varid)
+! call wrap_get_var_realx(ncid,varid,Uanal)
+ istat=nf90_inq_varid(ncid,'US',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_get_var(ncid,varid,Uanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ do ilat=1,(nlat-1)
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Uanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ Xtrans(:,:,ilat)=Xtrans(:,:,ilat-1)
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_U)
+
+ if(masterproc) then
+!DIAG: Dont have V, so jam VS into V so tests can proceed:
+!DIAG call wrap_inq_varid (ncid,'V',varid)
+!DIAG call wrap_get_var_realx(ncid,varid,Xanal)
+!DIAG do ilat=1,nlat
+!DIAG do ilev=1,plev
+!DIAG do ilon=1,nlon
+!DIAG Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+!DIAG end do
+!DIAG end do
+!DIAG end do
+! call wrap_inq_varid (ncid,'VS',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'VS',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ do ilat=1,nlat
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_V)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'T',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'T',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ do ilat=1,nlat
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_T)
+
+ if(masterproc) then
+! call wrap_inq_varid (ncid,'Q',varid)
+! call wrap_get_var_realx(ncid,varid,Xanal)
+ istat=nf90_inq_varid(ncid,'Q',varid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ istat=nf90_get_var(ncid,varid,Xanal)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_FV')
+ endif
+ do ilat=1,nlat
+ do ilev=1,plev
+ do ilon=1,nlon
+ Xtrans(ilon,ilev,ilat)=Xanal(ilon,ilat,ilev)
+ end do
+ end do
+ end do
+ endif ! (masterproc) then
+ call scatter_field_to_chunk(1,Nudge_nlev,1,Nudge_nlon,Xtrans ,Target_Q)
+
+ if(masterproc) then
+!! call wrap_inq_varid (ncid,'PS',varid)
+!! call wrap_get_var_realx(ncid,varid,PSanal)
+! istat=nf90_inq_varid(ncid,'PS',varid)
+! if(istat.ne.NF90_NOERR) then
+! write(iulog,*) nf90_strerror(istat)
+! call endrun ('UPDATE_ANALYSES_SE')
+! endif
+! istat=nf90_get_var(ncid,varid,PSanal)
+! if(istat.ne.NF90_NOERR) then
+! write(iulog,*) nf90_strerror(istat)
+! call endrun ('UPDATE_ANALYSES_SE')
+! endif
+
+ ! Close the analyses file
+ !-----------------------
+! call wrap_close(ncid)
+ istat=nf90_close(ncid)
+ if(istat.ne.NF90_NOERR) then
+ write(iulog,*) nf90_strerror(istat)
+ call endrun ('UPDATE_ANALYSES_EUL')
+ endif
+ endif ! (masterproc) then
+! call scatter_field_to_chunk(1, 1,1,Nudge_nlon,PSanal,Target_PS)
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_update_analyses_fv
+ !================================================================
+
+
+ !================================================================
+ subroutine nudging_set_profile(rlat,rlon,Nudge_prof,Wprof,nlev)
+ !
+ ! NUDGING_SET_PROFILE: for the given lat,lon, and Nudging_prof, set
+ ! the verical profile of window coeffcients.
+ ! Values range from 0. to 1. to affect spatial
+ ! variations on nudging strength.
+ !===============================================================
+
+ ! Arguments
+ !--------------
+ integer nlev,Nudge_prof
+ real(r8) rlat,rlon
+ real(r8) Wprof(nlev)
+
+ ! Local values
+ !----------------
+ integer ilev
+ real(r8) Hcoef,latx,lonx,Vmax,Vmin
+ real(r8) lon_lo,lon_hi,lat_lo,lat_hi,lev_lo,lev_hi
+
+ !---------------
+ ! set coeffcient
+ !---------------
+ if(Nudge_prof.eq.0) then
+ ! No Nudging
+ !-------------
+ Wprof(:)=0.0
+ elseif(Nudge_prof.eq.1) then
+ ! Uniform Nudging
+ !-----------------
+ Wprof(:)=1.0
+ elseif(Nudge_prof.eq.2) then
+ ! Localized Nudging with specified Heaviside window function
+ !------------------------------------------------------------
+ if(Nudge_Hwin_max.le.Nudge_Hwin_min) then
+ ! For a constant Horizontal window function,
+ ! just set Hcoef to the maximum of Hlo/Hhi.
+ !--------------------------------------------
+ Hcoef=max(Nudge_Hwin_lo,Nudge_Hwin_hi)
+ else
+ ! get lat/lon relative to window center
+ !------------------------------------------
+ latx=rlat-Nudge_Hwin_lat0
+ lonx=rlon-Nudge_Hwin_lon0
+ if(lonx.gt. 180.) lonx=lonx-360.
+ if(lonx.le.-180.) lonx=lonx+360.
+
+ ! Calcualte RAW window value
+ !-------------------------------
+ lon_lo=(Nudge_Hwin_lonWidthH+lonx)/Nudge_Hwin_lonDelta
+ lon_hi=(Nudge_Hwin_lonWidthH-lonx)/Nudge_Hwin_lonDelta
+ lat_lo=(Nudge_Hwin_latWidthH+latx)/Nudge_Hwin_latDelta
+ lat_hi=(Nudge_Hwin_latWidthH-latx)/Nudge_Hwin_latDelta
+ Hcoef=((1.+tanh(lon_lo))/2.)*((1.+tanh(lon_hi))/2.) &
+ *((1.+tanh(lat_lo))/2.)*((1.+tanh(lat_hi))/2.)
+
+ ! Scale the horizontal window coef for specfied range of values.
+ !--------------------------------------------------------
+ Hcoef=(Hcoef-Nudge_Hwin_min)/(Nudge_Hwin_max-Nudge_Hwin_min)
+ Hcoef=(1.-Hcoef)*Nudge_Hwin_lo + Hcoef*Nudge_Hwin_hi
+ endif
+
+ ! Load the RAW vertical window
+ !------------------------------
+ do ilev=1,nlev
+ lev_lo=(float(ilev)-Nudge_Vwin_Lindex)/Nudge_Vwin_Ldelta
+ lev_hi=(Nudge_Vwin_Hindex-float(ilev))/Nudge_Vwin_Hdelta
+ Wprof(ilev)=((1.+tanh(lev_lo))/2.)*((1.+tanh(lev_hi))/2.)
+ end do
+
+ ! Scale the Window function to span the values between Vlo and Vhi:
+ !-----------------------------------------------------------------
+ Vmax=maxval(Wprof)
+ Vmin=minval(Wprof)
+ if(Vmax.le.Vmin) then
+ ! For a constant Vertical window function,
+ ! load maximum of Vlo/Vhi into Wprof()
+ !--------------------------------------------
+ Vmax=max(Nudge_Vwin_lo,Nudge_Vwin_hi)
+ Wprof(:)=Vmax
+ else
+ ! Scale the RAW vertical window for specfied range of values.
+ !--------------------------------------------------------
+ Wprof(:)=(Wprof(:)-Vmin)/(Vmax-Vmin)
+ Wprof(:)=Nudge_Vwin_lo + Wprof(:)*(Nudge_Vwin_hi-Nudge_Vwin_lo)
+ endif
+
+ ! The desired result is the product of the vertical profile
+ ! and the horizontal window coeffcient.
+ !----------------------------------------------------
+ Wprof(:)=Hcoef*Wprof(:)
+ else
+ call endrun('nudging_set_profile:: Unknown Nudge_prof value')
+ endif
+
+ ! End Routine
+ !------------
+ return
+ end subroutine ! nudging_set_profile
+ !================================================================
+
+ !================================================================
+ real(r8) function nudging_set_PSprofile(rlat,rlon,Nudge_PSprof)
+ !
+ ! NUDGING_SET_PSPROFILE: for the given lat and lon set the surface
+ ! pressure profile value for the specified index.
+ ! Values range from 0. to 1. to affect spatial
+ ! variations on nudging strength.
+ !===============================================================
+
+ ! Arguments
+ !--------------
+ real(r8) rlat,rlon
+ integer Nudge_PSprof
+
+ ! Local values
+ !----------------
+
+ !---------------
+ ! set coeffcient
+ !---------------
+ if(Nudge_PSprof.eq.0) then
+ ! No Nudging
+ !-------------
+ nudging_set_PSprofile=0.0
+ elseif(Nudge_PSprof.eq.1) then
+ ! Uniform Nudging
+ !-----------------
+ nudging_set_PSprofile=1.0
+ else
+ call endrun('nudging_set_PSprofile:: Unknown Nudge_prof value')
+ endif
+
+ ! End Routine
+ !------------
+ return
+ end function ! nudging_set_PSprofile
+ !================================================================
+
+end module nudging
diff --git a/models/atm/cam/src/physics/cam/phys_control.F90 b/models/atm/cam/src/physics/cam/phys_control.F90
index 5cf12c1b6393..065e255d61bf 100644
--- a/models/atm/cam/src/physics/cam/phys_control.F90
+++ b/models/atm/cam/src/physics/cam/phys_control.F90
@@ -66,13 +66,20 @@ module phys_control
! liquid budgets.
integer :: history_budget_histfile_num = 1 ! output history file number for budget fields
logical :: history_waccm = .true. ! output variables of interest for WACCM runs
+logical :: history_clubb = .true. ! output default CLUBB-related variables
logical :: do_clubb_sgs
logical :: do_tms
+logical :: micro_do_icesupersat
logical :: state_debug_checks = .false. ! Extra checks for validity of physics_state objects
! in physics_update.
+! Macro/micro-physics co-substeps
+integer :: cld_macmic_num_steps = 1
logical :: prog_modal_aero ! determines whether prognostic modal aerosols are present in the run.
+! Option to use heterogeneous freezing
+logical, public, protected :: use_hetfrz_classnuc = .false.
+
! Which gravity wave sources are used?
! Orographic
logical, public, protected :: use_gw_oro = .true.
@@ -101,8 +108,9 @@ subroutine phys_ctl_readnl(nlfile)
eddy_scheme, microp_scheme, macrop_scheme, radiation_scheme, srf_flux_avg, &
use_subcol_microp, atm_dep_flux, history_amwg, history_vdiag, history_aerosol, history_aero_optics, &
history_eddy, history_budget, history_budget_histfile_num, history_waccm, &
- conv_water_in_rad, do_clubb_sgs, do_tms, state_debug_checks, &
- use_gw_oro, use_gw_front, use_gw_convect
+ conv_water_in_rad, history_clubb, do_clubb_sgs, do_tms, state_debug_checks, &
+ use_hetfrz_classnuc, use_gw_oro, use_gw_front, use_gw_convect, &
+ cld_macmic_num_steps, micro_do_icesupersat
!-----------------------------------------------------------------------------
if (masterproc) then
@@ -141,13 +149,17 @@ subroutine phys_ctl_readnl(nlfile)
call mpibcast(history_budget, 1 , mpilog, 0, mpicom)
call mpibcast(history_budget_histfile_num, 1 , mpiint, 0, mpicom)
call mpibcast(history_waccm, 1 , mpilog, 0, mpicom)
+ call mpibcast(history_clubb, 1 , mpilog, 0, mpicom)
call mpibcast(do_clubb_sgs, 1 , mpilog, 0, mpicom)
call mpibcast(conv_water_in_rad, 1 , mpiint, 0, mpicom)
call mpibcast(do_tms, 1 , mpilog, 0, mpicom)
+ call mpibcast(micro_do_icesupersat, 1 , mpilog, 0, mpicom)
call mpibcast(state_debug_checks, 1 , mpilog, 0, mpicom)
+ call mpibcast(use_hetfrz_classnuc, 1 , mpilog, 0, mpicom)
call mpibcast(use_gw_oro, 1 , mpilog, 0, mpicom)
call mpibcast(use_gw_front, 1 , mpilog, 0, mpicom)
call mpibcast(use_gw_convect, 1 , mpilog, 0, mpicom)
+ call mpibcast(cld_macmic_num_steps, 1 , mpiint, 0, mpicom)
#endif
! Error checking:
@@ -204,8 +216,14 @@ subroutine phys_ctl_readnl(nlfile)
call endrun('CLUBB and eddy, macrop or shallow schemes incompatible')
endif
endif
-
+ ! Macro/micro co-substepping support.
+ if (cld_macmic_num_steps > 1) then
+ if (microp_scheme /= "MG" .or. (macrop_scheme /= "park" .and. macrop_scheme /= "CLUBB_SGS")) then
+ call endrun ("Setting cld_macmic_num_steps > 1 is only &
+ &supported with Park or CLUBB macrophysics and MG microphysics.")
+ end if
+ end if
! prog_modal_aero determines whether prognostic modal aerosols are present in the run.
prog_modal_aero = ( cam_chempkg_is('trop_mam3') &
@@ -256,8 +274,9 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, mi
radiation_scheme_out, use_subcol_microp_out, atm_dep_flux_out, &
history_amwg_out, history_vdiag_out, history_aerosol_out, history_aero_optics_out, history_eddy_out, &
history_budget_out, history_budget_histfile_num_out, history_waccm_out, &
- conv_water_in_rad_out, cam_chempkg_out, prog_modal_aero_out, macrop_scheme_out, &
- do_clubb_sgs_out, do_tms_out, state_debug_checks_out )
+ history_clubb_out, conv_water_in_rad_out, cam_chempkg_out, prog_modal_aero_out, macrop_scheme_out, &
+ do_clubb_sgs_out, do_tms_out, state_debug_checks_out, &
+ cld_macmic_num_steps_out, micro_do_icesupersat_out)
!-----------------------------------------------------------------------
! Purpose: Return runtime settings
! deep_scheme_out : deep convection scheme
@@ -283,12 +302,15 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, mi
logical, intent(out), optional :: history_budget_out
integer, intent(out), optional :: history_budget_histfile_num_out
logical, intent(out), optional :: history_waccm_out
+ logical, intent(out), optional :: history_clubb_out
logical, intent(out), optional :: do_clubb_sgs_out
+ logical, intent(out), optional :: micro_do_icesupersat_out
integer, intent(out), optional :: conv_water_in_rad_out
character(len=32), intent(out), optional :: cam_chempkg_out
logical, intent(out), optional :: prog_modal_aero_out
logical, intent(out), optional :: do_tms_out
logical, intent(out), optional :: state_debug_checks_out
+ integer, intent(out), optional :: cld_macmic_num_steps_out
if ( present(deep_scheme_out ) ) deep_scheme_out = deep_scheme
if ( present(shallow_scheme_out ) ) shallow_scheme_out = shallow_scheme
@@ -307,12 +329,15 @@ subroutine phys_getopts(deep_scheme_out, shallow_scheme_out, eddy_scheme_out, mi
if ( present(history_eddy_out ) ) history_eddy_out = history_eddy
if ( present(history_budget_histfile_num_out ) ) history_budget_histfile_num_out = history_budget_histfile_num
if ( present(history_waccm_out ) ) history_waccm_out = history_waccm
+ if ( present(history_clubb_out ) ) history_clubb_out = history_clubb
if ( present(do_clubb_sgs_out ) ) do_clubb_sgs_out = do_clubb_sgs
+ if ( present(micro_do_icesupersat_out )) micro_do_icesupersat_out = micro_do_icesupersat
if ( present(conv_water_in_rad_out ) ) conv_water_in_rad_out = conv_water_in_rad
if ( present(cam_chempkg_out ) ) cam_chempkg_out = cam_chempkg
if ( present(prog_modal_aero_out ) ) prog_modal_aero_out = prog_modal_aero
if ( present(do_tms_out ) ) do_tms_out = do_tms
if ( present(state_debug_checks_out ) ) state_debug_checks_out = state_debug_checks
+ if ( present(cld_macmic_num_steps_out) ) cld_macmic_num_steps_out = cld_macmic_num_steps
end subroutine phys_getopts
diff --git a/models/atm/cam/src/physics/cam/physics_types.F90 b/models/atm/cam/src/physics/cam/physics_types.F90
index 4d0eea0806fd..22dcfc50b6df 100644
--- a/models/atm/cam/src/physics/cam/physics_types.F90
+++ b/models/atm/cam/src/physics/cam/physics_types.F90
@@ -38,6 +38,7 @@ module physics_types
public physics_state_copy ! copy a physics_state object
public physics_ptend_copy ! copy a physics_ptend object
public physics_ptend_sum ! accumulate physics_ptend objects
+ public physics_ptend_scale ! Multiply physics_ptend objects by a constant factor.
public physics_tend_init ! initialize a physics_tend object
public set_state_pdry ! calculate dry air masses in state variable
@@ -224,6 +225,7 @@ subroutine physics_update(state, ptend, dt, tend)
integer :: i,k,m ! column,level,constituent indices
integer :: ixcldice, ixcldliq ! indices for CLDICE and CLDLIQ
integer :: ixnumice, ixnumliq
+ integer :: ixnumsnow, ixnumrain
integer :: ncol ! number of columns
character*40 :: name ! param and tracer name for qneg3
@@ -325,6 +327,8 @@ subroutine physics_update(state, ptend, dt, tend)
! the indices will be set to -1)
call cnst_get_ind('NUMICE', ixnumice, abort=.false.)
call cnst_get_ind('NUMLIQ', ixnumliq, abort=.false.)
+ call cnst_get_ind('NUMRAI', ixnumrain, abort=.false.)
+ call cnst_get_ind('NUMSNO', ixnumsnow, abort=.false.)
do m = 1, pcnst
if(ptend%lq(m)) then
@@ -334,7 +338,8 @@ subroutine physics_update(state, ptend, dt, tend)
! now test for mixing ratios which are too small
! don't call qneg3 for number concentration variables
- if (m /= ixnumice .and. m /= ixnumliq) then
+ if (m /= ixnumice .and. m /= ixnumliq .and. &
+ m /= ixnumrain .and. m /= ixnumsnow ) then
name = trim(ptend%name) // '/' // trim(cnst_name(m))
call qneg3(trim(name), state%lchnk, ncol, state%psetcols, pver, m, m, qmin(m), state%q(1,1,m))
else
@@ -817,6 +822,69 @@ subroutine physics_ptend_sum(ptend, ptend_sum, ncol)
end subroutine physics_ptend_sum
+!===============================================================================
+
+ subroutine physics_ptend_scale(ptend, fac, ncol)
+!-----------------------------------------------------------------------
+! Scale ptend fields for ptend logical flags = .true.
+! Where ptend logical flags = .false, don't change ptend.
+!
+! Assumes that input ptend is valid (e.g. that
+! ptend%lu .eqv. allocated(ptend%u)), and therefore
+! does not check allocation status of individual arrays.
+!-----------------------------------------------------------------------
+
+!------------------------------Arguments--------------------------------
+ type(physics_ptend), intent(inout) :: ptend ! Incoming ptend
+ real(r8), intent(in) :: fac ! Factor to multiply ptend by.
+ integer, intent(in) :: ncol ! number of columns
+
+!---------------------------Local storage-------------------------------
+ integer :: m ! constituent index
+
+!-----------------------------------------------------------------------
+
+! Update u,v fields
+ if (ptend%lu) &
+ call multiply_tendency(ptend%u, &
+ ptend%taux_srf, ptend%taux_top)
+
+ if (ptend%lv) &
+ call multiply_tendency(ptend%v, &
+ ptend%tauy_srf, ptend%tauy_top)
+
+! Heat
+ if (ptend%ls) &
+ call multiply_tendency(ptend%s, &
+ ptend%hflux_srf, ptend%hflux_top)
+
+! Update constituents
+ do m = 1, pcnst
+ if (ptend%lq(m)) &
+ call multiply_tendency(ptend%q(:,:,m), &
+ ptend%cflx_srf(:,m), ptend%cflx_top(:,m))
+ end do
+
+
+ contains
+
+ subroutine multiply_tendency(tend_arr, flx_srf, flx_top)
+ real(r8), intent(inout) :: tend_arr(:,:) ! Tendency array (pcols, plev)
+ real(r8), intent(inout) :: flx_srf(:) ! Surface flux (or stress)
+ real(r8), intent(inout) :: flx_top(:) ! Top-of-model flux (or stress)
+
+ integer :: k
+
+ do k = ptend%top_level, ptend%bot_level
+ tend_arr(:ncol,k) = tend_arr(:ncol,k) * fac
+ end do
+ flx_srf(:ncol) = flx_srf(:ncol) * fac
+ flx_top(:ncol) = flx_top(:ncol) * fac
+
+ end subroutine multiply_tendency
+
+ end subroutine physics_ptend_scale
+
!===============================================================================
subroutine physics_ptend_copy(ptend, ptend_cp)
@@ -1666,6 +1734,9 @@ subroutine physics_state_dealloc(state)
deallocate(state%lonmapback, stat=ierr)
if ( ierr /= 0 ) call endrun('physics_state_dealloc error: deallocation error for state%lonmapback')
+ deallocate(state%cid, stat=ierr)
+ if ( ierr /= 0 ) call endrun('physics_state_dealloc error: deallocation error for state%cid')
+
end subroutine physics_state_dealloc
!===============================================================================
diff --git a/models/atm/cam/src/physics/cam/physpkg.F90 b/models/atm/cam/src/physics/cam/physpkg.F90
index 728f0b558c97..dff74353705b 100644
--- a/models/atm/cam/src/physics/cam/physpkg.F90
+++ b/models/atm/cam/src/physics/cam/physpkg.F90
@@ -26,7 +26,8 @@ module physpkg
use camsrfexch, only: cam_out_t, cam_in_t
use cam_control_mod, only: ideal_phys, adiabatic
- use phys_control, only: phys_do_flux_avg, waccmx_is
+ use phys_control, only: phys_do_flux_avg, phys_getopts, waccmx_is
+ use zm_conv, only: trigmem
use scamMod, only: single_column, scm_crm_mode
use flux_avg, only: flux_avg_init
use infnan, only: posinf, assignment(=)
@@ -73,8 +74,17 @@ module physpkg
!
! Private module data
!
- logical :: clim_modal_aero ! climate controled by prognostic or prescribed modal aerosols
- logical :: prog_modal_aero ! Prognostic modal aerosols present
+ ! Physics package options
+ character(len=16) :: shallow_scheme
+ character(len=16) :: macrop_scheme
+ character(len=16) :: microp_scheme
+ integer :: cld_macmic_num_steps ! Number of macro/micro substeps
+ logical :: do_clubb_sgs
+ logical :: use_subcol_microp ! if true, use subcolumns in microphysics
+ logical :: state_debug_checks ! Debug physics_state.
+ logical :: clim_modal_aero ! climate controled by prognostic or prescribed modal aerosols
+ logical :: prog_modal_aero ! Prognostic modal aerosols present
+ logical :: micro_do_icesupersat
!=======================================================================
contains
@@ -96,7 +106,6 @@ subroutine phys_register
use constituents, only: pcnst, cnst_add, cnst_chk_dim, cnst_name
use cam_control_mod, only: moist_physics
- use phys_control, only: phys_do_flux_avg, phys_getopts, waccmx_is
use chemistry, only: chem_register
use cloud_fraction, only: cldfrc_register
use stratiform, only: stratiform_register
@@ -134,21 +143,22 @@ subroutine phys_register
use subcol, only: subcol_register
use subcol_utils, only: is_subcol_on
-
- implicit none
!---------------------------Local variables-----------------------------
!
integer :: m ! loop index
integer :: mm ! constituent index
!-----------------------------------------------------------------------
- character(len=16) :: microp_scheme
- logical :: do_clubb_sgs
-
integer :: nmodes
- call phys_getopts( microp_scheme_out = microp_scheme )
- call phys_getopts( do_clubb_sgs_out = do_clubb_sgs )
+ call phys_getopts(shallow_scheme_out = shallow_scheme, &
+ macrop_scheme_out = macrop_scheme, &
+ microp_scheme_out = microp_scheme, &
+ cld_macmic_num_steps_out = cld_macmic_num_steps, &
+ do_clubb_sgs_out = do_clubb_sgs, &
+ use_subcol_microp_out = use_subcol_microp, &
+ state_debug_checks_out = state_debug_checks, &
+ micro_do_icesupersat_out = micro_do_icesupersat)
! Initialize dyn_time_lvls
call pbuf_init_time()
@@ -641,6 +651,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_out )
use aircraft_emit, only: aircraft_emit_init
use prescribed_volcaero,only: prescribed_volcaero_init
use cloud_fraction, only: cldfrc_init
+ use cldfrc2m, only: cldfrc2m_init
use co2_cycle, only: co2_init, co2_transport
use convect_deep, only: convect_deep_init
use convect_shallow, only: convect_shallow_init
@@ -652,7 +663,6 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_out )
use radiation, only: radiation_init
use cloud_diagnostics, only: cloud_diagnostics_init
use stratiform, only: stratiform_init
- use phys_control, only: phys_getopts, waccmx_is
use wv_saturation, only: wv_sat_init
use microp_driver, only: microp_driver_init
use microp_aero, only: microp_aero_init
@@ -680,6 +690,7 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_out )
use tropopause, only: tropopause_init
use solar_data, only: solar_data_init
use rad_solar_var, only: rad_solar_var_init
+ use nudging, only: Nudge_Model,nudging_init
! Input/output arguments
type(physics_state), pointer :: phys_state(:)
@@ -691,15 +702,8 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_out )
! local variables
integer :: lchnk
- character(len=16) :: microp_scheme
- logical :: do_clubb_sgs
-
!-----------------------------------------------------------------------
- ! Get microphysics option
- call phys_getopts(microp_scheme_out = microp_scheme)
- call phys_getopts(do_clubb_sgs_out = do_clubb_sgs )
-
call physics_type_alloc(phys_state, phys_tend, begchunk, endchunk, pcols)
do lchnk = begchunk, endchunk
@@ -804,14 +808,15 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_out )
call convect_shallow_init(pref_edge)
- call cldfrc_init
+ call cldfrc_init()
+ call cldfrc2m_init()
call convect_deep_init(pref_edge)
if( microp_scheme == 'RK' ) then
call stratiform_init()
elseif( microp_scheme == 'MG' ) then
- if (.not. do_clubb_sgs) call macrop_driver_init()
+ if (.not. do_clubb_sgs) call macrop_driver_init(pbuf2d)
call microp_aero_init()
call microp_driver_init(pbuf2d)
call conv_water_init
@@ -852,6 +857,10 @@ subroutine phys_init( phys_state, phys_tend, pbuf2d, cam_out )
end if
+ ! Initialize Nudging Parameters
+ !--------------------------------
+ if(Nudge_Model) call nudging_init
+
end subroutine phys_init
!
@@ -1249,7 +1258,6 @@ subroutine tphysac (ztodt, cam_in, &
physics_dme_adjust, set_dry_to_wet, physics_state_check
use majorsp_diffusion, only: mspd_intr ! WACCM-X major diffusion
use ionosphere, only: ionos_intr ! WACCM-X ionosphere
- use phys_control, only: phys_getopts
use tracers, only: tracers_timestep_tend
use aoa_tracers, only: aoa_tracers_timestep_tend
use physconst, only: rhoh2o, latvap,latice
@@ -1269,10 +1277,8 @@ subroutine tphysac (ztodt, cam_in, &
use iondrag, only: iondrag_calc, do_waccm_ions
use clubb_intr, only: clubb_surface
use perf_mod
- use phys_control, only: phys_do_flux_avg, waccmx_is
use flux_avg, only: flux_avg_run
-
- implicit none
+ use nudging, only: Nudge_Model,Nudge_ON,nudging_timestep_tend
!
! Arguments
@@ -1328,10 +1334,6 @@ subroutine tphysac (ztodt, cam_in, &
real(r8), pointer, dimension(:,:) :: dtcore
real(r8), pointer, dimension(:,:) :: ast ! relative humidity cloud fraction
- logical :: do_clubb_sgs
-
- ! Debug physics_state.
- logical :: state_debug_checks
!
!-----------------------------------------------------------------------
!
@@ -1340,9 +1342,6 @@ subroutine tphysac (ztodt, cam_in, &
nstep = get_nstep()
- call phys_getopts( do_clubb_sgs_out = do_clubb_sgs, &
- state_debug_checks_out = state_debug_checks)
-
! Adjust the surface fluxes to reduce instabilities in near sfc layer
if (phys_do_flux_avg()) then
call flux_avg_run(state, cam_in, pbuf, nstep, ztodt)
@@ -1595,6 +1594,13 @@ subroutine tphysac (ztodt, cam_in, &
endif
endif
+ !===================================================
+ ! Update Nudging values, if needed
+ !===================================================
+ if((Nudge_Model).and.(Nudge_ON)) then
+ call nudging_timestep_tend(state,ptend)
+ call physics_update(state,ptend,ztodt,tend)
+ endif
call diag_phys_tend_writeout (state, pbuf, tend, ztodt, tmp_q, tmp_cldliq, tmp_cldice, &
tmp_t, qini, cldliqini, cldiceini)
@@ -1639,12 +1645,11 @@ subroutine tphysbc (ztodt, &
use shr_kind_mod, only: r8 => shr_kind_r8
use stratiform, only: stratiform_tend
- use phys_control, only: phys_getopts
use microp_driver, only: microp_driver_tend
use microp_aero, only: microp_aero_run
use macrop_driver, only: macrop_driver_tend
use physics_types, only: physics_state, physics_tend, physics_ptend, physics_update, &
- physics_ptend_init, physics_ptend_sum, physics_state_check
+ physics_ptend_init, physics_ptend_sum, physics_state_check, physics_ptend_scale
use cam_diagnostics, only: diag_conv_tend_ini, diag_phys_writeout, diag_conv, diag_export, diag_state_b4_phys_write
use cam_history, only: outfld
use physconst, only: cpair, latvap
@@ -1723,11 +1728,19 @@ subroutine tphysbc (ztodt, &
integer i,k,m ! Longitude, level, constituent indices
integer :: ixcldice, ixcldliq ! constituent indices for cloud liquid and ice water.
+ ! for macro/micro co-substepping
+ integer :: macmic_it ! iteration variables
+ real(r8) :: cld_macmic_ztodt ! modified timestep
! physics buffer fields to compute tendencies for stratiform package
integer itim_old, ifld
real(r8), pointer, dimension(:,:) :: cld ! cloud fraction
+!songxl 2011-09-20----------------------------
! physics buffer fields for total energy and mass adjustment
real(r8), pointer, dimension(: ) :: teout
@@ -1759,6 +1772,12 @@ subroutine tphysbc (ztodt, &
real(r8),pointer :: prec_sed(:) ! total precip from cloud sedimentation
real(r8),pointer :: snow_sed(:) ! snow from cloud ice sedimentation
+ ! Local copies for substepping
+ real(r8) :: prec_pcw_macmic(pcols)
+ real(r8) :: snow_pcw_macmic(pcols)
+ real(r8) :: prec_sed_macmic(pcols)
+ real(r8) :: snow_sed_macmic(pcols)
+
! energy checking variables
real(r8) :: zero(pcols) ! array of zeros
real(r8) :: zero_sc(pcols*psubcols) ! array of zeros
@@ -1772,20 +1791,7 @@ subroutine tphysbc (ztodt, &
real(r8) :: zero_tracers(pcols,pcnst)
logical :: lq(pcnst)
- logical :: use_subcol_microp ! if true, use subcolumns in microphysics
-
- ! pass macro to micro
- character(len=16) :: microp_scheme
- character(len=16) :: macrop_scheme
-
- ! Debug physics_state.
- logical :: state_debug_checks
- call phys_getopts( microp_scheme_out = microp_scheme, &
- macrop_scheme_out = macrop_scheme, &
- use_subcol_microp_out = use_subcol_microp, &
- state_debug_checks_out = state_debug_checks)
-
!-----------------------------------------------------------------------
call t_startf('bc_init')
@@ -1806,6 +1812,15 @@ subroutine tphysbc (ztodt, &
ifld = pbuf_get_index('CLD')
call pbuf_get_field(pbuf, ifld, cld, (/1,1,itim_old/),(/pcols,pver,1/))
+!songxl 2011-09-20---------------------------
+
call pbuf_get_field(pbuf, teout_idx, teout, (/1,itim_old/), (/pcols,1/))
call pbuf_get_field(pbuf, tini_idx, tini)
@@ -1944,6 +1959,8 @@ subroutine tphysbc (ztodt, &
call pbuf_get_field(pbuf, snow_str_idx, snow_str)
call pbuf_get_field(pbuf, prec_sed_idx, prec_sed)
call pbuf_get_field(pbuf, snow_sed_idx, snow_sed)
+ call pbuf_get_field(pbuf, prec_pcw_idx, prec_pcw )
+ call pbuf_get_field(pbuf, snow_pcw_idx, snow_pcw )
if (use_subcol_microp) then
call pbuf_get_field(pbuf, prec_str_idx, prec_str_sc, col_type=col_type_subcol)
@@ -2028,107 +2045,179 @@ subroutine tphysbc (ztodt, &
call t_stopf('stratiform_tend')
elseif( microp_scheme == 'MG' ) then
-
- !===================================================
- ! Calculate macrophysical tendency (sedimentation, detrain, cloud fraction)
- !===================================================
-
- call t_startf('macrop_tend')
-
- ! don't call Park macrophysics if CLUBB is called
- if (macrop_scheme .ne. 'CLUBB_SGS') then
-
- call macrop_driver_tend(state, ptend, ztodt, &
- cam_in%landfrac, cam_in%ocnfrac, &
- cam_in%snowhland, & ! sediment
- dlf, dlf2, & ! detrain
- cmfmc, cmfmc2, &
- cam_in%ts, cam_in%sst, zdu, pbuf, &
- det_s, det_ice)
-
- ! Since we "added" the reserved liquid back in this routine, we need
- ! to account for it in the energy checker
- flx_cnd(:ncol) = -1._r8*rliq(:ncol)
- flx_heat(:ncol) = det_s(:ncol)
-
- call physics_update(state, ptend, ztodt, tend)
- call check_energy_chng(state, tend, "macrop_tend", nstep, ztodt, zero, flx_cnd, det_ice, flx_heat)
+ ! Start co-substepping of macrophysics and microphysics
+ cld_macmic_ztodt = ztodt/cld_macmic_num_steps
+
+ ! Clear precip fields that should accumulate.
+ prec_sed_macmic = 0._r8
+ snow_sed_macmic = 0._r8
+ prec_pcw_macmic = 0._r8
+ snow_pcw_macmic = 0._r8
+
+ do macmic_it = 1, cld_macmic_num_steps
+
+ if (micro_do_icesupersat) then
+
+ !===================================================
+ ! Aerosol Activation
+ !===================================================
+ call t_startf('microp_aero_run')
+ call microp_aero_run(state, ptend, cld_macmic_ztodt, pbuf)
+ call t_stopf('microp_aero_run')
+
+ call physics_ptend_scale(ptend, 1._r8/cld_macmic_num_steps, ncol)
+
+ call physics_update(state, ptend, ztodt, tend)
+ call check_energy_chng(state, tend, "mp_aero_tend", nstep, ztodt, zero, zero, zero, zero)
+
+ endif
+ !===================================================
+ ! Calculate macrophysical tendency (sedimentation, detrain, cloud fraction)
+ !===================================================
+
+ call t_startf('macrop_tend')
+
+ ! don't call Park macrophysics if CLUBB is called
+ if (macrop_scheme .ne. 'CLUBB_SGS') then
+
+ call macrop_driver_tend( &
+ state, ptend, cld_macmic_ztodt, &
+ cam_in%landfrac, cam_in%ocnfrac, cam_in%snowhland, & ! sediment
+ dlf, dlf2, & ! detrain
+ cmfmc, cmfmc2, &
+ cam_in%ts, cam_in%sst, zdu, &
+ pbuf, det_s, det_ice)
+
+ ! Since we "added" the reserved liquid back in this routine, we need
+ ! to account for it in the energy checker
+ flx_cnd(:ncol) = -1._r8*rliq(:ncol)
+ flx_heat(:ncol) = det_s(:ncol)
+
+ ! Unfortunately, physics_update does not know what time period
+ ! "tend" is supposed to cover, and therefore can't update it
+ ! with substeps correctly. For now, work around this by scaling
+ ! ptend down by the number of substeps, then applying it for
+ ! the full time (ztodt).
+ call physics_ptend_scale(ptend, 1._r8/cld_macmic_num_steps, ncol)
+ call physics_update(state, ptend, ztodt, tend)
+ call check_energy_chng(state, tend, "macrop_tend", nstep, ztodt, &
+ zero, flx_cnd/cld_macmic_num_steps, &
+ det_ice/cld_macmic_num_steps, flx_heat/cld_macmic_num_steps)
- else ! Calculate CLUBB macrophysics
+ else ! Calculate CLUBB macrophysics
- ! =====================================================
- ! CLUBB call (PBL, shallow convection, macrophysics)
- ! =====================================================
+ ! =====================================================
+ ! CLUBB call (PBL, shallow convection, macrophysics)
+ ! =====================================================
- call clubb_tend_cam(state,ptend,pbuf,1.0_r8*ztodt,&
- cmfmc, cmfmc2, cam_in, sgh30, dlf, det_s, det_ice)
-
- ! Since we "added" the reserved liquid back in this routine, we need
- ! to account for it in the energy checker
- flx_cnd(:ncol) = -1._r8*rliq(:ncol)
- flx_heat(:ncol) = cam_in%shf(:ncol) + det_s(:ncol)
-
- ! Update physics tendencies and copy state to state_eq, because that is
- ! input for microphysics
- call physics_update(state, ptend, ztodt, tend)
- call check_energy_chng(state, tend, "clubb_tend", nstep, ztodt, cam_in%lhf/latvap, flx_cnd, det_ice, flx_heat)
+ call clubb_tend_cam(state,ptend,pbuf,cld_macmic_ztodt,&
+ cmfmc, cam_in, sgh30, macmic_it, cld_macmic_num_steps, &
+ dlf, det_s, det_ice)
+
+ ! Since we "added" the reserved liquid back in this routine, we need
+ ! to account for it in the energy checker
+ flx_cnd(:ncol) = -1._r8*rliq(:ncol)
+ flx_heat(:ncol) = cam_in%shf(:ncol) + det_s(:ncol)
+
+ ! Unfortunately, physics_update does not know what time period
+ ! "tend" is supposed to cover, and therefore can't update it
+ ! with substeps correctly. For now, work around this by scaling
+ ! ptend down by the number of substeps, then applying it for
+ ! the full time (ztodt).
+ call physics_ptend_scale(ptend, 1._r8/cld_macmic_num_steps, ncol)
+ ! Update physics tendencies and copy state to state_eq, because that is
+ ! input for microphysics
+ call physics_update(state, ptend, ztodt, tend)
+ call check_energy_chng(state, tend, "clubb_tend", nstep, ztodt, &
+ cam_in%lhf/latvap/cld_macmic_num_steps, flx_cnd/cld_macmic_num_steps, &
+ det_ice/cld_macmic_num_steps, flx_heat/cld_macmic_num_steps)
- endif
+ endif
- call t_stopf('macrop_tend')
+ call t_stopf('macrop_tend')
- !===================================================
- ! Calculate cloud microphysics
- !===================================================
+ !===================================================
+ ! Calculate cloud microphysics
+ !===================================================
- if (is_subcol_on()) then
- ! Allocate sub-column structures.
- call physics_state_alloc(state_sc, lchnk, psubcols*pcols)
- call physics_tend_alloc(tend_sc, psubcols*pcols)
+ if (is_subcol_on()) then
+ ! Allocate sub-column structures.
+ call physics_state_alloc(state_sc, lchnk, psubcols*pcols)
+ call physics_tend_alloc(tend_sc, psubcols*pcols)
- ! Generate sub-columns using the requested scheme
- call subcol_gen(state, tend, state_sc, tend_sc, pbuf)
+ ! Generate sub-columns using the requested scheme
+ call subcol_gen(state, tend, state_sc, tend_sc, pbuf)
- !Initialize check energy for subcolumns
- call check_energy_timestep_init(state_sc, tend_sc, pbuf, col_type_subcol)
- end if
+ !Initialize check energy for subcolumns
+ call check_energy_timestep_init(state_sc, tend_sc, pbuf, col_type_subcol)
+ end if
- call t_startf('microp_aero_run')
- call microp_aero_run(state, ptend_aero, ztodt, pbuf)
- call t_stopf('microp_aero_run')
+ if (.not. micro_do_icesupersat) then
- call t_startf('microp_tend')
+ call t_startf('microp_aero_run')
+ call microp_aero_run(state, ptend_aero, cld_macmic_ztodt, pbuf)
+ call t_stopf('microp_aero_run')
- if (use_subcol_microp) then
+ endif
- call microp_driver_tend(state_sc, ptend_sc, ztodt, pbuf)
+ call t_startf('microp_tend')
- ! Average the sub-column ptend for use in gridded update - will not contain ptend_aero
- call subcol_ptend_avg(ptend_sc, state_sc%ngrdcol, lchnk, ptend)
-
- ! Copy ptend_aero field to one dimensioned by sub-columns before summing with ptend
- call subcol_ptend_copy(ptend_aero, state_sc, ptend_aero_sc)
- call physics_ptend_sum(ptend_aero_sc, ptend_sc, state_sc%ncol)
+ if (use_subcol_microp) then
+ call microp_driver_tend(state_sc, ptend_sc, cld_macmic_ztodt, pbuf)
- call physics_update (state_sc, ptend_sc, ztodt, tend_sc)
- call check_energy_chng(state_sc, tend_sc, "microp_tend_subcol", nstep, ztodt, zero_sc, prec_str_sc, snow_str_sc, zero_sc)
+ ! Average the sub-column ptend for use in gridded update - will not contain ptend_aero
+ call subcol_ptend_avg(ptend_sc, state_sc%ngrdcol, lchnk, ptend)
- call physics_state_dealloc(state_sc)
- call physics_tend_dealloc(tend_sc)
- call physics_ptend_dealloc(ptend_sc)
+ ! Copy ptend_aero field to one dimensioned by sub-columns before summing with ptend
+ call subcol_ptend_copy(ptend_aero, state_sc, ptend_aero_sc)
+ call physics_ptend_sum(ptend_aero_sc, ptend_sc, state_sc%ncol)
+ call physics_ptend_dealloc(ptend_aero_sc)
- else
- call microp_driver_tend(state, ptend, ztodt, pbuf)
- end if
+ ! Have to scale and apply for full timestep to get tend right
+ ! (see above note for macrophysics).
+ call physics_ptend_scale(ptend_sc, 1._r8/cld_macmic_num_steps, ncol)
- ! combine aero and micro tendencies for the grid
- call physics_ptend_sum(ptend_aero, ptend, ncol)
- call physics_update(state, ptend, ztodt, tend)
- call check_energy_chng(state, tend, "microp_tend", nstep, ztodt, zero, prec_str, snow_str, zero)
+ call physics_update (state_sc, ptend_sc, ztodt, tend_sc)
+ call check_energy_chng(state_sc, tend_sc, "microp_tend_subcol", &
+ nstep, ztodt, zero_sc, prec_str_sc/cld_macmic_num_steps, &
+ snow_str_sc/cld_macmic_num_steps, zero_sc)
- call physics_ptend_dealloc(ptend_aero)
- call t_stopf('microp_tend')
+ call physics_state_dealloc(state_sc)
+ call physics_tend_dealloc(tend_sc)
+ call physics_ptend_dealloc(ptend_sc)
+ else
+ call microp_driver_tend(state, ptend, cld_macmic_ztodt, pbuf)
+ end if
+ ! combine aero and micro tendencies for the grid
+ if (.not. micro_do_icesupersat) then
+ call physics_ptend_sum(ptend_aero, ptend, ncol)
+ call physics_ptend_dealloc(ptend_aero)
+ endif
+
+ ! Have to scale and apply for full timestep to get tend right
+ ! (see above note for macrophysics).
+ call physics_ptend_scale(ptend, 1._r8/cld_macmic_num_steps, ncol)
+
+ call physics_update (state, ptend, ztodt, tend)
+ call check_energy_chng(state, tend, "microp_tend", nstep, ztodt, &
+ zero, prec_str/cld_macmic_num_steps, &
+ snow_str/cld_macmic_num_steps, zero)
+
+ call t_stopf('microp_tend')
+ prec_sed_macmic(:ncol) = prec_sed_macmic(:ncol) + prec_sed(:ncol)
+ snow_sed_macmic(:ncol) = snow_sed_macmic(:ncol) + snow_sed(:ncol)
+ prec_pcw_macmic(:ncol) = prec_pcw_macmic(:ncol) + prec_pcw(:ncol)
+ snow_pcw_macmic(:ncol) = snow_pcw_macmic(:ncol) + snow_pcw(:ncol)
+
+ end do ! end substepping over macrophysics/microphysics
+
+ prec_sed(:ncol) = prec_sed_macmic(:ncol)/cld_macmic_num_steps
+ snow_sed(:ncol) = snow_sed_macmic(:ncol)/cld_macmic_num_steps
+ prec_pcw(:ncol) = prec_pcw_macmic(:ncol)/cld_macmic_num_steps
+ snow_pcw(:ncol) = snow_pcw_macmic(:ncol)/cld_macmic_num_steps
+ prec_str(:ncol) = prec_pcw(:ncol) + prec_sed(:ncol)
+ snow_str(:ncol) = snow_pcw(:ncol) + snow_sed(:ncol)
endif
@@ -2183,6 +2272,15 @@ subroutine tphysbc (ztodt, &
endif
+!songxl 2011-09-20---------------------------------
+
!===================================================
! Moist physical parameteriztions complete:
! send dynamical variables, and derived variables to history file
@@ -2276,6 +2374,7 @@ subroutine phys_timestep_init(phys_state, cam_out, pbuf2d)
use aerodep_flx, only: aerodep_flx_adv
use aircraft_emit, only: aircraft_emit_adv
use prescribed_volcaero, only: prescribed_volcaero_adv
+ use nudging, only: Nudge_Model,nudging_timestep_init
implicit none
@@ -2341,6 +2440,10 @@ subroutine phys_timestep_init(phys_state, cam_out, pbuf2d)
! age of air tracers
call aoa_tracers_timestep_init(phys_state)
+ ! Update Nudging values, if needed
+ !----------------------------------
+ if(Nudge_Model) call nudging_timestep_init(phys_state)
+
end subroutine phys_timestep_init
end module physpkg
diff --git a/models/atm/cam/src/physics/cam/rad_constituents.F90 b/models/atm/cam/src/physics/cam/rad_constituents.F90
index 42ff792eaa02..ea35f1881b17 100644
--- a/models/atm/cam/src/physics/cam/rad_constituents.F90
+++ b/models/atm/cam/src/physics/cam/rad_constituents.F90
@@ -37,6 +37,8 @@ module rad_constituents
rad_cnst_readnl, &! read namelist values and parse
rad_cnst_init, &! find optics files and all constituents
rad_cnst_get_info, &! return info about climate/diagnostic lists
+ rad_cnst_get_mode_idx, &! return mode index of specified mode type
+ rad_cnst_get_spec_idx, &! return specie index of specified specie type
rad_cnst_get_gas, &! return pointer to mmr for gasses
rad_cnst_get_aer_mmr, &! return pointer to mmr for aerosols
rad_cnst_get_mam_mmr_idx, &! get constituent index of mam specie mmr (climate list only)
@@ -759,6 +761,102 @@ end subroutine rad_cnst_get_info_by_spectype
!================================================================================================
+function rad_cnst_get_mode_idx(list_idx, mode_type) result(mode_idx)
+
+ ! Return mode index of the specified type in the specified climate/diagnostics list.
+ ! Return -1 if not found.
+
+ ! Arguments
+ integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
+ character(len=*), intent(in) :: mode_type ! mode type
+
+ ! Return value
+ integer :: mode_idx ! mode index
+
+ ! Local variables
+ type(modelist_t), pointer :: m_list
+
+ integer :: i, nmodes, m_idx
+
+ character(len=*), parameter :: subname = 'rad_cnst_get_mode_idx'
+ !-----------------------------------------------------------------------------
+
+ ! if mode type not found return -1
+ mode_idx = -1
+
+ ! specified mode list
+ m_list => ma_list(list_idx)
+
+ ! number of modes in specified list
+ nmodes = m_list%nmodes
+
+ ! loop through modes in specified climate/diagnostic list
+ do i = 1, nmodes
+
+ ! get index of the mode in the definition object
+ m_idx = m_list%idx(i)
+
+ ! look in mode definition object (modes) for the mode types
+ if (trim(modes%types(m_idx)) == trim(mode_type)) then
+ mode_idx = i
+ exit
+ end if
+ end do
+
+end function rad_cnst_get_mode_idx
+
+!================================================================================================
+
+function rad_cnst_get_spec_idx(list_idx, mode_idx, spec_type) result(spec_idx)
+
+ ! Return specie index of the specified type in the specified mode of the specified
+ ! climate/diagnostics list. Return -1 if not found.
+
+ ! Arguments
+ integer, intent(in) :: list_idx ! index of the climate or a diagnostic list
+ integer, intent(in) :: mode_idx ! mode index
+ character(len=*), intent(in) :: spec_type ! specie type
+
+ ! Return value
+ integer :: spec_idx ! specie index
+
+ ! Local variables
+ type(modelist_t), pointer :: m_list
+ type(mode_component_t), pointer :: mode_comps
+
+ integer :: i, m_idx, nspec
+
+ character(len=*), parameter :: subname = 'rad_cnst_get_spec_idx'
+ !-----------------------------------------------------------------------------
+
+ ! if specie type not found return -1
+ spec_idx = -1
+
+ ! modes in specified list
+ m_list => ma_list(list_idx)
+
+ ! get index of the specified mode in the definition object
+ m_idx = m_list%idx(mode_idx)
+
+ ! object containing the components of the mode
+ mode_comps => modes%comps(m_idx)
+
+ ! number of species in specified mode
+ nspec = mode_comps%nspec
+
+ ! loop through species in specified mode
+ do i = 1, nspec
+
+ ! look in mode definition object (modes) for the mode types
+ if (trim(mode_comps%type(i)) == trim(spec_type)) then
+ spec_idx = i
+ exit
+ end if
+ end do
+
+end function rad_cnst_get_spec_idx
+!================================================================================================
+
subroutine rad_cnst_get_call_list(call_list)
! Return info about which climate/diagnostic calculations are requested
diff --git a/models/atm/cam/src/physics/cam/zm_conv.F90 b/models/atm/cam/src/physics/cam/zm_conv.F90
index 7bfd1ee34f2c..b91730edc3d8 100644
--- a/models/atm/cam/src/physics/cam/zm_conv.F90
+++ b/models/atm/cam/src/physics/cam/zm_conv.F90
@@ -35,6 +35,7 @@ module zm_conv
public zm_conv_evap ! evaporation of precip from ZM schemea
public convtran ! convective transport
public momtran ! convective momentum transport
+ public trigmem ! true if convective memory
!
! Private data
@@ -42,15 +43,20 @@ module zm_conv
real(r8), parameter :: unset_r8 = huge(1.0_r8)
real(r8) :: zmconv_c0_lnd = unset_r8
real(r8) :: zmconv_c0_ocn = unset_r8
- real(r8) :: zmconv_ke = unset_r8
- real(r8) :: zmconv_tau = unset_r8
+ real(r8) :: zmconv_ke = unset_r8
+ real(r8) :: zmconv_tau = unset_r8
+ logical :: zmconv_trigmem= .false.
real(r8) rl ! wg latent heat of vaporization.
real(r8) cpres ! specific heat at constant pressure in j/kg-degk.
real(r8), parameter :: capelmt = 70._r8 ! threshold value for cape for deep convection.
+!songxl 2014-05-20------------------
real(r8) :: ke ! Tunable evaporation efficiency set from namelist input zmconv_ke
real(r8) :: c0_lnd ! set from namelist input zmconv_c0_lnd
real(r8) :: c0_ocn ! set from namelist input zmconv_c0_ocn
+ logical :: trigmem ! set from namelist input zmconv_trigmem
real(r8) tau ! convective time scale
real(r8),parameter :: c1 = 6.112_r8
real(r8),parameter :: c2 = 17.67_r8
@@ -87,11 +93,10 @@ subroutine zmconv_readnl(nlfile)
integer :: unitn, ierr
character(len=*), parameter :: subname = 'zmconv_readnl'
- namelist /zmconv_nl/ zmconv_c0_lnd, zmconv_c0_ocn, zmconv_ke, zmconv_tau
+ namelist /zmconv_nl/ zmconv_c0_lnd, zmconv_c0_ocn, zmconv_ke, zmconv_tau, zmconv_trigmem
!-----------------------------------------------------------------------------
- ! defaut:
- zmconv_tau = 3600._r8
+ zmconv_tau = 3600._r8
if (masterproc) then
unitn = getunit()
open( unitn, file=trim(nlfile), status='old' )
@@ -110,6 +115,7 @@ subroutine zmconv_readnl(nlfile)
c0_ocn = zmconv_c0_ocn
ke = zmconv_ke
tau = zmconv_tau
+ trigmem = zmconv_trigmem
end if
@@ -119,6 +125,7 @@ subroutine zmconv_readnl(nlfile)
call mpibcast(c0_ocn, 1, mpir8, 0, mpicom)
call mpibcast(ke, 1, mpir8, 0, mpicom)
call mpibcast(tau, 1, mpir8, 0, mpicom)
+ call mpibcast(trigmem, 1, mpir8, 0, mpicom)
#endif
end subroutine zmconv_readnl
@@ -155,7 +162,7 @@ subroutine zm_convi(limcnv_in, no_deep_pbl_in)
! convection is too weak, thus adjusted to 2400.
hgrid = get_resolution()
- !tau = 3600._r8
+ if(trigmem)tau = 3600._r8
if ( masterproc ) then
write(iulog,*) 'tuning parameters zm_convi: tau',tau
@@ -178,7 +185,8 @@ subroutine zm_convr(lchnk ,ncol , &
tpert ,dlf ,pflx ,zdu ,rprd , &
mu ,md ,du ,eu ,ed , &
dp ,dsubcld ,jt ,maxg ,ideep , &
- lengath ,ql ,rliq ,landfrac)
+ lengath ,ql ,rliq ,landfrac,hu_nm1 , &
+ cnv_nm1 ,tm1 ,qm1 ) !songxl 2014-05-20
!-----------------------------------------------------------------------
!
! Purpose:
@@ -198,7 +206,7 @@ subroutine zm_convr(lchnk ,ncol , &
!
!-----------------------------------------------------------------------
use phys_control, only: cam_physpkg_is
-
+ use time_manager, only: is_first_step, is_first_restart_step !songxl 2014-05-20
!
! ************************ index of variables **********************
!
@@ -310,6 +318,10 @@ subroutine zm_convr(lchnk ,ncol , &
real(r8), intent(in) :: pblh(pcols)
real(r8), intent(in) :: tpert(pcols)
real(r8), intent(in) :: landfrac(pcols) ! RBN Landfrac
+!songxl 2014-05-20------------------
!
! output arguments
!
@@ -336,6 +348,11 @@ subroutine zm_convr(lchnk ,ncol , &
real(r8), intent(out) :: prec(pcols)
real(r8), intent(out) :: rliq(pcols) ! reserved liquid (not yet in cldliq) for energy integrals
+!songxl 2014-05-20------------------
+
real(r8) zs(pcols)
real(r8) dlg(pcols,pver) ! gathrd version of the detraining cld h2o tend
real(r8) pflxg(pcols,pverp) ! gather precip flux at each level
@@ -369,9 +386,21 @@ subroutine zm_convr(lchnk ,ncol , &
real(r8) qstp(pcols,pver) ! w grid slice of parcel temp. saturation mixing ratio.
real(r8) tl(pcols) ! w row of parcel temperature at lcl.
+!songxl 2014-05-20-----------------
integer lcl(pcols) ! w base level index of deep cumulus convection.
integer lel(pcols) ! w index of highest theoretical convective plume.
+
integer lon(pcols) ! w index of onset level for deep convection.
integer maxi(pcols) ! w index of level with largest moist static energy.
integer index(pcols)
@@ -391,6 +420,8 @@ subroutine zm_convr(lchnk ,ncol , &
real(r8) vg(pcols,pver) ! wg grid slice of gathered values of v.
real(r8) cmeg(pcols,pver)
+ real(r8) hu_nm1g(pcols,pver) !songxl 2014-05-20
+
real(r8) rprdg(pcols,pver) ! wg gathered rain production rate
real(r8) capeg(pcols) ! wg gathered convective available potential energy.
real(r8) tlg(pcols) ! wg grid slice of gathered values of tl.
@@ -481,7 +512,7 @@ subroutine zm_convr(lchnk ,ncol , &
jctop(i) = pver
jcbot(i) = 1
-
+ if(trigmem)dcape(i) = 0._r8 !songxl 2014-05-20
end do
!
! calculate local pressure (mbs) and height (m) for both interface
@@ -516,11 +547,22 @@ subroutine zm_convr(lchnk ,ncol , &
q(i,k) = qh(i,k)
s(i,k) = t(i,k) + (grav/cpres)*z(i,k)
tp(i,k)=0.0_r8
+ if(trigmem)tpm1(i,k) = 0.0_r8 !songxl 2014-05-20
shat(i,k) = s(i,k)
qhat(i,k) = q(i,k)
end do
end do
+!songxl 2014-05-20---------------------
+
do i = 1,ncol
capeg(i) = 0._r8
lclg(i) = 1
@@ -544,13 +586,27 @@ subroutine zm_convr(lchnk ,ncol , &
! Evaluate Tparcel, qs(Tparcel), buoyancy and CAPE,
! lcl, lel, parcel launch level at index maxi()=hmax
-
- call buoyan_dilute(lchnk ,ncol , &
+!songxl 2014-05-20------------------
end if
!
@@ -560,10 +616,26 @@ subroutine zm_convr(lchnk ,ncol , &
!
lengath = 0
do i=1,ncol
+! capelmt) then
+ lengath = lengath + 1
+ index(lengath) = i
+ end if
+ else
+ if (dcape(i) > dcapelmt) then
+ lengath = lengath + 1
+ index(lengath) = i
+ end if
+ end if
+ else
if (cape(i) > capelmt) then
lengath = lengath + 1
index(lengath) = i
end if
+ end if
+!>songxl 2014-05-20----------------
end do
if (lengath.eq.0) return
@@ -587,6 +659,7 @@ subroutine zm_convr(lchnk ,ncol , &
qstpg(i,k) = qstp(ideep(i),k)
ug(i,k) = 0._r8
vg(i,k) = 0._r8
+ if(trigmem)hu_nm1g(i,k) = hu_nm1(ideep(i),k) !songxl 2014-05-20
end do
end do
!
@@ -651,7 +724,8 @@ subroutine zm_convr(lchnk ,ncol , &
cmeg ,maxg ,lelg ,jt ,jlcl , &
maxg ,j0 ,jd ,rl ,lengath , &
rgas ,grav ,cpres ,msg , &
- pflxg ,evpg ,cug ,rprdg ,limcnv ,landfracg)
+ pflxg ,evpg ,cug ,rprdg ,limcnv , &
+ landfracg, hu_nm1g ) !songxl 2014-05-20
!
! convert detrainment from units of "1/m" to "1/mb".
!
@@ -731,6 +805,17 @@ subroutine zm_convr(lchnk ,ncol , &
cpres ,rl ,msg , &
dlg ,evpg ,cug )
!
+!songxl 2014-05-20-----------------
+
! gather back temperature and mixing ratio.
!
do k = msg + 1,pver
@@ -749,6 +834,12 @@ subroutine zm_convr(lchnk ,ncol , &
dlf (ideep(i),k) = dlg (i,k)
pflx(ideep(i),k) = pflxg(i,k)
ql (ideep(i),k) = qlg (i,k)
+!songxl 2014-05-20
end do
end do
!
@@ -1994,7 +2085,11 @@ subroutine cldprp(lchnk , &
cmeg ,jb ,lel ,jt ,jlcl , &
mx ,j0 ,jd ,rl ,il2g , &
rd ,grav ,cp ,msg , &
- pflx ,evp ,cu ,rprd ,limcnv ,landfrac)
+!songxl 2014-05-20-------
!-----------------------------------------------------------------------
!
! Purpose:
@@ -2067,6 +2162,9 @@ subroutine cldprp(lchnk , &
real(r8), intent(out) :: sd(pcols,pver) ! normalized dry stat energy of downdraft
real(r8), intent(out) :: su(pcols,pver) ! normalized dry stat energy of updraft
+!songxl 2014-05-20----------------
real(r8) rd ! gas constant for dry air
real(r8) grav ! gravity
@@ -2127,6 +2225,11 @@ subroutine cldprp(lchnk , &
logical doit(pcols)
logical done(pcols)
+
+!songxl 2014-05-20----------------
!
!------------------------------------------------------------------------------
!
@@ -2390,6 +2493,20 @@ subroutine cldprp(lchnk , &
khighest = min(khighest,lel(i))
klowest = max(klowest,jb(i))
end do
+
+!songxl 2014-05-20--------------
+
do k = klowest-1,khighest,-1
do i = 1,il2g
if (k <= jb(i)-1 .and. k >= lel(i) .and. eps0(i) > 0._r8) then
@@ -2399,13 +2516,21 @@ subroutine cldprp(lchnk , &
eu(i,k) = 0._r8
du(i,k) = mu(i,k+1)/dz(i,k)
else
- hu(i,k) = mu(i,k+1)/mu(i,k)*hu(i,k+1) + &
- dz(i,k)/mu(i,k)* (eu(i,k)*hmn(i,k)- du(i,k)*hsat(i,k))
+!songxl 2014-05-20--------------
end if
end if
end do
end do
!
+!
! reset cloud top index beginning from two layers above the
! cloud base (i.e. if cloud is only one layer thick, top is not reset
!
@@ -2415,7 +2540,8 @@ subroutine cldprp(lchnk , &
do k=klowest-2,khighest-1,-1
do i=1,il2g
if (doit(i) .and. k <= jb(i)-2 .and. k >= lel(i)-1) then
- if (hu(i,k) <= hsthat(i,k) .and. hu(i,k+1) > hsthat(i,k+1) &
+ if(trigmem)then
+ if (hu(i,k) <= hsthat(i,k) .and. hu(i,k+1) > hsthat(i,k+1) &
.and. mu(i,k) >= 0.02_r8) then
if (hu(i,k)-hsthat(i,k) < -2000._r8) then
jt(i) = k + 1
@@ -2424,10 +2550,35 @@ subroutine cldprp(lchnk , &
jt(i) = k
doit(i) = .false.
end if
- else if (hu(i,k) > hu(i,jb(i)) .or. mu(i,k) < 0.02_r8) then
+ else
+ if (hu_tot(i).eq.hmn_tot(i)) then
+ if (hu(i,k) > hu(i,jb(i)) .or. mu(i,k) < 0.02_r8) then
+ jt(i) = k + 1
+ doit(i) = .false.
+ end if
+ else
+ if ( mu(i,k) < 0.02_r8) then
+ jt(i) = k + 1
+ doit(i) = .false.
+ end if
+ end if
+ end if
+ else ! not trigmem
+ if (hu(i,k) <= hsthat(i,k) .and. hu(i,k+1) > hsthat(i,k+1) &
+ .and. mu(i,k) >= 0.02_r8) then
+ if (hu(i,k)-hsthat(i,k) < -2000._r8) then
+ jt(i) = k + 1
+ doit(i) = .false.
+ else
+ jt(i) = k
+ doit(i) = .false.
+ end if
+ else if (hu(i,k) > hu(i,jb(i)) .or. mu(i,k) < 0.02_r8) then
jt(i) = k + 1
doit(i) = .false.
- end if
+ end if
+ end if ! end trigmem
+!>songxl 2014-06-20------------------------
end if
end do
end do
@@ -2447,6 +2598,10 @@ subroutine cldprp(lchnk , &
end do
end do
!
+!songxl 2014-05-20-----------------
+
! specify downdraft properties (no downdrafts if jd.ge.jb).
! scale down downward mass flux profile so that net flux
! (up-down) at cloud base in not negative.
@@ -3039,7 +3194,6 @@ subroutine buoyan_dilute(lchnk ,ncol , &
real(r8), intent(in) :: pf(pcols,pver+1) ! pressure at interfaces
real(r8), intent(in) :: pblt(pcols) ! index of pbl depth
real(r8), intent(in) :: tpert(pcols) ! perturbation temperature by pbl processes
-
!
! output arguments
!
@@ -3164,7 +3318,6 @@ subroutine buoyan_dilute(lchnk ,ncol , &
call parcel_dilute(lchnk, ncol, msg, mx, p, t, q, tpert, tp, tpv, qstp, pl, tl, lcl)
-
! If lcl is above the nominal level of non-divergence (600 mbs),
! no deep convection is permitted (ensuing calculations
! skipped and cape retains initialized value of zero).
@@ -3244,7 +3397,6 @@ subroutine buoyan_dilute(lchnk ,ncol , &
end subroutine buoyan_dilute
subroutine parcel_dilute (lchnk, ncol, msg, klaunch, p, t, q, tpert, tp, tpv, qstp, pl, tl, lcl)
-
! Routine to determine
! 1. Tp - Parcel temperature
! 2. qstp - Saturated mixing ratio at the parcel temperature.
diff --git a/models/atm/cam/src/physics/cam/zm_conv_intr.F90 b/models/atm/cam/src/physics/cam/zm_conv_intr.F90
index 181407d0b82d..b4d8562487dc 100644
--- a/models/atm/cam/src/physics/cam/zm_conv_intr.F90
+++ b/models/atm/cam/src/physics/cam/zm_conv_intr.F90
@@ -11,8 +11,9 @@ module zm_conv_intr
!---------------------------------------------------------------------------------
use shr_kind_mod, only: r8=>shr_kind_r8
use physconst, only: cpair
+ use physconst, only: latvap, gravit !songxl 2014-05-20
use ppgrid, only: pver, pcols, pverp, begchunk, endchunk
- use zm_conv, only: zm_conv_evap, zm_convr, convtran, momtran
+ use zm_conv, only: zm_conv_evap, zm_convr, convtran, momtran, trigmem
use cam_history, only: outfld, addfld, add_default, phys_decomp
use perf_mod
use cam_logfile, only: iulog
@@ -58,6 +59,13 @@ module zm_conv_intr
prec_dp_idx, &
snow_dp_idx
+!songxl 2014-05-20------------------
+
! indices for fields in the physics buffer
integer :: cld_idx = 0
integer :: icwmrdp_idx = 0
@@ -93,6 +101,19 @@ subroutine zm_conv_register
! deep gbm cloud liquid water (kg/kg)
call pbuf_add_field('DP_CLDICE','global',dtype_r8,(/pcols,pver/), dp_cldice_idx)
+!songxl 2014-05-20-------------
+
end subroutine zm_conv_register
!=========================================================================================
@@ -279,6 +300,7 @@ subroutine zm_conv_tend(pblh ,mcon ,cme , &
use phys_grid, only: get_lat_p, get_lon_p
use time_manager, only: get_nstep, is_first_step
+ use time_manager, only: is_first_restart_step !songxl 2011-09-20
use physics_buffer, only : pbuf_get_field, physics_buffer_desc, pbuf_old_tim_idx
use constituents, only: pcnst, cnst_get_ind, cnst_is_convtran1
use check_energy, only: check_energy_chng
@@ -339,6 +361,13 @@ subroutine zm_conv_tend(pblh ,mcon ,cme , &
real(r8), pointer, dimension(:,:) :: flxsnow ! Convective-scale flux of snow at interfaces (kg/m2/s)
real(r8), pointer, dimension(:,:) :: dp_cldliq
real(r8), pointer, dimension(:,:) :: dp_cldice
+!songxl 2014-05-20---------
+
real(r8) :: jctop(pcols) ! o row of top-of-deep-convection indices passed out.
real(r8) :: jcbot(pcols) ! o row of base of cloud indices passed out.
@@ -394,6 +423,23 @@ subroutine zm_conv_tend(pblh ,mcon ,cme , &
call pbuf_get_field(pbuf, prec_dp_idx, prec )
call pbuf_get_field(pbuf, snow_dp_idx, snow )
+!
+ ! | | Start of CLUBB main time step loop
+ ! | |
+ ! | | advance_clubb_core
+ ! | |
+ ! | |
+ ! | |\
+ ! | | \
+ ! | | (intent in)-------setup_pdf_parameters-------->calc. Ncnm (local)
+ ! | | |
+ ! | | \ /
+ ! | | mu_Ncn_i, sigma_Ncn_i,
+ ! | | corr_xNcn_i
+ ! | | |
+ ! | | \ /
+ ! | | PDF param. arrays:
+ ! | | mu_x_i_n, sigma_x_i_n,
+ ! | | corr_array_i_n
+ ! | | (intent out)
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | |--(intent in)-------microphys_schemes-------------(intent in)
+ ! | | |
+ ! | | |
+ ! | | call a microphysics scheme
+ ! | | |
+ ! | | Local micro. scheme-----------Latin Hypercube-----------Upscaled KK
+ ! | | | | |
+ ! | | Ncm/Nc-in-cloud: Populate sample points Use PDF params.
+ ! | | used to find micro. using PDF params (Ncn). of Ncn
+ ! | | tendencies. At every sample point: (mu_Ncn_i, etc.)
+ ! | | | Nc = Ncn * H(chi). to find micro.
+ ! | | | Use sample-point Nc to tendencies.
+ ! | | | find micro. tendencies |
+ ! | | | when calling micro. scheme. |
+ ! | | | | |
+ ! | | hydromet_mc/-----------------hydromet_mc/-------------hydromet_mc
+ ! | | Ncm_mc (intent out) | Ncm_mc (intent out) (intent out)
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | |
+ ! | | (intent in)
+ ! | | |
+ ! | |--(intent inout)----advance_microphys
+ ! | |
+ ! | |
+ ! | | advance microphysics variables (hydromet, Nc_in_cloud/Ncm) one timestep
+ ! | |
+ ! | | l_predict_Nc = true:
+ ! | | Nc_in_cloud/Ncm necessary for starting
+ ! | | value of Nc_in_cloud/Ncm when advancing
+ ! | | one timestep using predictive equation.
+ ! | |
+ ! | |
+ ! | | End of CLUBB main time step loop
+ ! <---
+
+ ! References:
+ !-------------------------------------------------------------------------
+
+ implicit none
+
+ private ! default scope
+
+ public :: Ncnm_to_Nc_in_cloud, &
+ Nc_in_cloud_to_Ncnm, &
+ Ncnm_to_Ncm, &
+ Ncm_to_Ncnm
+
+ private :: bivar_NL_chi_Ncn_mean, &
+ bivar_Ncnm_eqn_comp
+
+contains
+
+ !=============================================================================
+ function Ncnm_to_Nc_in_cloud( mu_chi_1, mu_chi_2, mu_Ncn_1, mu_Ncn_2, &
+ sigma_chi_1, sigma_chi_2, sigma_Ncn_1, &
+ sigma_Ncn_2, sigma_Ncn_1_n, sigma_Ncn_2_n, &
+ corr_chi_Ncn_1_n, corr_chi_Ncn_2_n, mixt_frac, &
+ cloud_frac_1, cloud_frac_2 ) &
+ result( Nc_in_cloud )
+
+ ! Description:
+ ! The in-cloud mean of cloud droplet concentration is calculated from the
+ ! PDF parameters involving simplified cloud nuclei concentration, Ncn, and
+ ! cloud fraction. At any point, cloud droplet concentration, Nc, is given
+ ! by:
+ !
+ ! Nc = Ncn * H(chi);
+ !
+ ! where extended liquid water mixing ratio, chi, is equal to cloud water
+ ! ratio, rc, when positive. When the atmosphere is saturated at this point,
+ ! cloud water is found, and Nc = Ncn. Otherwise, only clear air is found,
+ ! and Nc = 0.
+ !
+ ! The overall mean of cloud droplet concentration, , is calculated from
+ ! the PDF parameters involving Ncn. The in-cloud mean of cloud droplet
+ ! concentration is calculated from and cloud fraction.
+
+ ! References:
+ !-----------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ one, & ! Constant(s)
+ cloud_frac_min
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in) :: &
+ mu_chi_1, & ! Mean of chi (old s) (1st PDF component) [kg/kg]
+ mu_chi_2, & ! Mean of chi (old s) (2nd PDF component) [kg/kg]
+ mu_Ncn_1, & ! Mean of Ncn (1st PDF component) [num/kg]
+ mu_Ncn_2, & ! Mean of Ncn (2nd PDF component) [num/kg]
+ sigma_chi_1, & ! Standard deviation of chi (1st PDF comp.) [kg/kg]
+ sigma_chi_2, & ! Standard deviation of chi (2nd PDF comp.) [kg/kg]
+ sigma_Ncn_1, & ! Standard deviation of Ncn (1st PDF comp.) [num/kg]
+ sigma_Ncn_2, & ! Standard deviation of Ncn (2nd PDF comp.) [num/kg]
+ sigma_Ncn_1_n, & ! Standard deviation of ln Ncn (1st PDF component) [-]
+ sigma_Ncn_2_n, & ! Standard deviation of ln Ncn (2nd PDF component) [-]
+ corr_chi_Ncn_1_n, & ! Correlation of chi and ln Ncn (1st PDF comp.) [-]
+ corr_chi_Ncn_2_n, & ! Correlation of chi and ln Ncn (2nd PDF comp.) [-]
+ mixt_frac, & ! Mixture fraction [-]
+ cloud_frac_1, & ! Cloud fraction (1st PDF component) [-]
+ cloud_frac_2 ! Cloud fraction (2nd PDF component) [-]
+
+ ! Return Variable
+ real( kind = core_rknd ) :: &
+ Nc_in_cloud ! Mean cloud droplet concentration (in-cloud) [num/kg]
+
+ ! Local Variable
+ real( kind = core_rknd ) :: &
+ Ncm, & ! Mean cloud droplet concentration (overall) [num/kg]
+ cloud_frac ! Cloud fraction [-]
+
+
+ ! Calculate overall cloud fraction as calculated by the PDF.
+ ! The variable cloud_frac is not used here because it is altered by factors
+ ! such as the trapezoidal rule calculation.
+ ! Cloud fraction can be recalculated here from cloud_frac_1 and cloud_frac_2
+ ! as long neither of these variables are altered by any factor. They can
+ ! only be calculated from PDF.
+ cloud_frac = mixt_frac * cloud_frac_1 + ( one - mixt_frac ) * cloud_frac_2
+
+ if ( cloud_frac > cloud_frac_min ) then
+
+ ! There is cloud found at this grid level. Calculate Nc_in_cloud.
+ Ncm = Ncnm_to_Ncm( mu_chi_1, mu_chi_2, mu_Ncn_1, mu_Ncn_2, &
+ sigma_chi_1, sigma_chi_2, sigma_Ncn_1, &
+ sigma_Ncn_2, sigma_Ncn_1_n, sigma_Ncn_2_n, &
+ corr_chi_Ncn_1_n, corr_chi_Ncn_2_n, mixt_frac )
+
+ Nc_in_cloud = Ncm / cloud_frac
+
+ else ! cloud_frac <= cloud_frac_min
+
+ ! This level is entirely clear. Set Nc_in_cloud to .
+ ! Since = mu_Ncn_1 = mu_Ncn_2, use mu_Ncn_1 here.
+ Nc_in_cloud = mu_Ncn_1
+
+ endif
+
+
+ return
+
+ end function Ncnm_to_Nc_in_cloud
+
+ !=============================================================================
+ function Nc_in_cloud_to_Ncnm( mu_chi_1, mu_chi_2, sigma_chi_1, &
+ sigma_chi_2, mixt_frac, Nc_in_cloud, &
+ cloud_frac_1, cloud_frac_2, &
+ const_Ncnp2_on_Ncnm2, const_corr_chi_Ncn ) &
+ result( Ncnm )
+
+ ! Description:
+ ! The overall mean of simplified cloud nuclei concentration, , is
+ ! calculated from the in-cloud mean of cloud droplet concentration, ,
+ ! cloud fraction, and some of the PDF parameters.
+ !
+ ! At any point, cloud droplet concentration, Nc, is given by:
+ !
+ ! Nc = Ncn * H(chi);
+ !
+ ! where extended liquid water mixing ratio, chi, is equal to cloud water
+ ! ratio, rc, when positive. When the atmosphere is saturated at this point,
+ ! cloud water is found, and Nc = Ncn. Otherwise, only clear air is found,
+ ! and Nc = 0.
+ !
+ ! The overall mean of cloud droplet concentration, , is calculated from
+ ! Nc_in_cloud and cloud fraction. The value of is calculated from
+ ! and PDF parameters.
+
+ ! References:
+ !-----------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ one, & ! Constant(s)
+ zero, &
+ cloud_frac_min
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in) :: &
+ mu_chi_1, & ! Mean of chi (old s) (1st PDF component) [kg/kg]
+ mu_chi_2, & ! Mean of chi (old s) (2nd PDF component) [kg/kg]
+ sigma_chi_1, & ! Standard deviation of chi (1st PDF component) [kg/kg]
+ sigma_chi_2, & ! Standard deviation of chi (2nd PDF component) [kg/kg]
+ mixt_frac ! Mixture fraction [-]
+
+ real( kind = core_rknd ), intent(in) :: &
+ Nc_in_cloud, & ! Mean cloud droplet conc. (in-cloud) [num/kg]
+ cloud_frac_1, & ! Cloud fraction (1st PDF component) [-]
+ cloud_frac_2, & ! Cloud fraction (2nd PDF component) [-]
+ const_Ncnp2_on_Ncnm2, & ! Prescribed ratio of to ^2 [-]
+ const_corr_chi_Ncn ! Prescribed correlation of chi and Ncn [-]
+
+ ! Return Variable
+ real( kind = core_rknd ) :: &
+ Ncnm ! Mean simplified cloud nuclei concentration (overall) [num/kg]
+
+ ! Local Variable
+ real( kind = core_rknd ) :: &
+ Ncm, & ! Mean cloud droplet concentration (overall) [num/kg]
+ cloud_frac ! Cloud fraction [-]
+
+
+ ! Calculate overall cloud fraction as calculated by the PDF.
+ ! The variable cloud_frac is not used here because it is altered by factors
+ ! such as the trapezoidal rule calculation.
+ ! Cloud fraction can be recalculated here from cloud_frac_1 and cloud_frac_2
+ ! as long neither of these variables are altered by any factor. They can
+ ! only be calculated from the PDF.
+ cloud_frac = mixt_frac * cloud_frac_1 + ( one - mixt_frac ) * cloud_frac_2
+
+ if ( cloud_frac > cloud_frac_min &
+ .and. const_corr_chi_Ncn * const_Ncnp2_on_Ncnm2 /= zero ) then
+
+ ! There is cloud found at this grid level. Additionally, Ncn varies.
+ ! Calculate Nc_in_cloud.
+ Ncm = Nc_in_cloud * cloud_frac
+
+ Ncnm = Ncm_to_Ncnm( mu_chi_1, mu_chi_2, sigma_chi_1, sigma_chi_2, &
+ mixt_frac, Ncm, const_Ncnp2_on_Ncnm2, &
+ const_corr_chi_Ncn, Nc_in_cloud )
+
+ else ! cloud_frac <= cloud_frac_min .or. const_Ncnp2_on_Ncnm2 = 0
+
+ ! When Ncn is constant a a grid level, it is equal to Nc_in_cloud.
+ ! Additionally, when a level is entirely clear, , which is based on
+ ! Nc_in_cloud, here, must be set to something. Set to Nc_in_cloud.
+ Ncnm = Nc_in_cloud
+
+ endif
+
+
+ return
+
+ end function Nc_in_cloud_to_Ncnm
+
+ !=============================================================================
+ function Ncnm_to_Ncm( mu_chi_1, mu_chi_2, mu_Ncn_1, mu_Ncn_2, &
+ sigma_chi_1, sigma_chi_2, sigma_Ncn_1, &
+ sigma_Ncn_2, sigma_Ncn_1_n, sigma_Ncn_2_n, &
+ corr_chi_Ncn_1_n, corr_chi_Ncn_2_n, mixt_frac ) &
+ result( Ncm )
+
+ ! Description:
+ ! The overall mean of cloud droplet concentration, , is calculated from
+ ! the PDF parameters involving the simplified cloud nuclei concentration,
+ ! Ncn. At any point, cloud droplet concentration, Nc, is given by:
+ !
+ ! Nc = Ncn * H(chi);
+ !
+ ! where extended liquid water mixing ratio, chi, is equal to cloud water
+ ! ratio, rc, when positive. When the atmosphere is saturated at this point,
+ ! cloud water is found, and Nc = Ncn. Otherwise, only clear air is found,
+ ! and Nc = 0.
+ !
+ ! The overall mean of cloud droplet concentration, , is found by
+ ! integrating over the PDF of chi and Ncn, such that:
+ !
+ ! = INT(-inf:inf) INT(0:inf) Ncn * H(chi) * P(chi,Ncn) dNcn dchi;
+ !
+ ! which can also be written as:
+ !
+ ! = SUM(i=1,n) mixt_frac_i
+ ! * INT(-inf:inf) INT(0:inf) Ncn * H(chi) * P_i(chi,Ncn) dNcn dchi;
+ !
+ ! where n is the number of multivariate joint PDF components, mixt_frac_i is
+ ! the weight of the ith PDF component, and P_i is the functional form of the
+ ! multivariate joint PDF in the ith PDF component.
+ !
+ ! This equation is rewritten as:
+ !
+ ! = SUM(i=1,n) mixt_frac_i
+ ! * INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi.
+ !
+ ! When both chi and Ncn vary in the ith PDF component, the integral is
+ ! evaluated and the result is:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = (1/2) * exp{ mu_Ncn_i_n + (1/2) * sigma_Ncn_i_n^2 }
+ ! * erfc( - ( 1 / sqrt(2) ) * ( ( mu_chi_i / sigma_chi_i )
+ ! + rho_chi_Ncn_i_n * sigma_Ncn_i_n ) );
+ !
+ ! which can be reduced to:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = (1/2) * mu_Ncn_i
+ ! * erfc( - ( 1 / sqrt(2) ) * ( ( mu_chi_i / sigma_chi_i )
+ ! + rho_chi_Ncn_i_n * sigma_Ncn_i_n ) ).
+ !
+ ! When chi is constant, but Ncn varies, in the ith PDF component, the
+ ! integral is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = mu_Ncn_i;
+ !
+ ! when mu_chi_i > 0; and
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = 0;
+ !
+ ! when mu_chi_i <= 0.
+ !
+ ! When chi varies, but Ncn is constant, in the ith PDF component, the
+ ! integral is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = mu_Ncn_i * (1/2) * erfc( - ( mu_chi_i / ( sqrt(2) * sigma_chi_i ) ) ).
+ !
+ ! When both chi and Ncn are constant in the ith PDF component, the integral
+ ! is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = mu_Ncn_i;
+ !
+ ! when mu_chi_i > 0; and
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = 0;
+ !
+ ! when mu_chi_i <= 0.
+
+ ! References:
+ !-----------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ one ! Constant(s)
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in) :: &
+ mu_chi_1, & ! Mean of chi (old s) (1st PDF component) [kg/kg]
+ mu_chi_2, & ! Mean of chi (old s) (2nd PDF component) [kg/kg]
+ mu_Ncn_1, & ! Mean of Ncn (1st PDF component) [num/kg]
+ mu_Ncn_2, & ! Mean of Ncn (2nd PDF component) [num/kg]
+ sigma_chi_1, & ! Standard deviation of chi (1st PDF comp.) [kg/kg]
+ sigma_chi_2, & ! Standard deviation of chi (2nd PDF comp.) [kg/kg]
+ sigma_Ncn_1, & ! Standard deviation of Ncn (1st PDF comp.) [num/kg]
+ sigma_Ncn_2, & ! Standard deviation of Ncn (2nd PDF comp.) [num/kg]
+ sigma_Ncn_1_n, & ! Standard deviation of ln Ncn (1st PDF component) [-]
+ sigma_Ncn_2_n, & ! Standard deviation of ln Ncn (2nd PDF component) [-]
+ corr_chi_Ncn_1_n, & ! Correlation of chi and ln Ncn (1st PDF comp.) [-]
+ corr_chi_Ncn_2_n, & ! Correlation of chi and ln Ncn (2nd PDF comp.) [-]
+ mixt_frac ! Mixture fraction [-]
+
+ ! Return Variable
+ real( kind = core_rknd ) :: &
+ Ncm ! Mean cloud droplet concentration (overall) [num/kg]
+
+
+ ! Calculate mean cloud droplet concentration (overall), .
+ Ncm &
+ = mixt_frac &
+ * bivar_NL_chi_Ncn_mean( mu_chi_1, mu_Ncn_1, sigma_chi_1, &
+ sigma_Ncn_1, sigma_Ncn_1_n, corr_chi_Ncn_1_n ) &
+ + ( one - mixt_frac ) &
+ * bivar_NL_chi_Ncn_mean( mu_chi_2, mu_Ncn_2, sigma_chi_2, &
+ sigma_Ncn_2, sigma_Ncn_2_n, corr_chi_Ncn_2_n )
+
+
+ return
+
+ end function Ncnm_to_Ncm
+
+ !=============================================================================
+ function Ncm_to_Ncnm( mu_chi_1, mu_chi_2, sigma_chi_1, sigma_chi_2, &
+ mixt_frac, Ncm, const_Ncnp2_on_Ncnm2, &
+ const_corr_chi_Ncn, Ncnm_val_denom_0 ) &
+ result( Ncnm )
+
+ ! Description:
+ ! The overall mean of simplified cloud nuclei concentration, , is
+ ! calculated from the overall mean of cloud droplet concentration, , and
+ ! some of the PDF parameters.
+ !
+ ! At any point, cloud droplet concentration, Nc, is given by:
+ !
+ ! Nc = Ncn * H(chi);
+ !
+ ! where extended liquid water mixing ratio, chi, is equal to cloud water
+ ! ratio, rc, when positive. When the atmosphere is saturated at this point,
+ ! cloud water is found, and Nc = Ncn. Otherwise, only clear air is found,
+ ! and Nc = 0.
+ !
+ ! The overall mean of cloud droplet concentration, , is found by
+ ! integrating over the PDF of chi and Ncn, such that:
+ !
+ ! = INT(-inf:inf) INT(0:inf) Ncn * H(chi) * P(chi,Ncn) dNcn dchi;
+ !
+ ! which can also be written as:
+ !
+ ! = SUM(i=1,n) mixt_frac_i
+ ! * INT(-inf:inf) INT(0:inf) Ncn * H(chi) * P_i(chi,Ncn) dNcn dchi;
+ !
+ ! where n is the number of multivariate joint PDF components, mixt_frac_i is
+ ! the weight of the ith PDF component, and P_i is the functional form of the
+ ! multivariate joint PDF in the ith PDF component.
+ !
+ ! This equation is rewritten as:
+ !
+ ! = SUM(i=1,n) mixt_frac_i
+ ! * INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi.
+ !
+ ! When both chi and Ncn vary in the ith PDF component, the integral is
+ ! evaluated and the result is:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = (1/2) * exp{ mu_Ncn_i_n + (1/2) * sigma_Ncn_i_n^2 }
+ ! * erfc( - ( 1 / sqrt(2) ) * ( ( mu_chi_i / sigma_chi_i )
+ ! + rho_chi_Ncn_i_n * sigma_Ncn_i_n ) );
+ !
+ ! which can be reduced to:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = (1/2) * mu_Ncn_i
+ ! * erfc( - ( 1 / sqrt(2) ) * ( ( mu_chi_i / sigma_chi_i )
+ ! + rho_chi_Ncn_i_n * sigma_Ncn_i_n ) ).
+ !
+ ! When chi is constant, but Ncn varies, in the ith PDF component, the
+ ! integral is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = mu_Ncn_i;
+ !
+ ! when mu_chi_i > 0; and
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = 0;
+ !
+ ! when mu_chi_i <= 0.
+ !
+ ! When chi varies, but Ncn is constant, in the ith PDF component, the
+ ! integral is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = mu_Ncn_i * (1/2) * erfc( - ( mu_chi_i / ( sqrt(2) * sigma_chi_i ) ) ).
+ !
+ ! When both chi and Ncn are constant in the ith PDF component, the integral
+ ! is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = mu_Ncn_i;
+ !
+ ! when mu_chi_i > 0; and
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = 0;
+ !
+ ! when mu_chi_i <= 0.
+ !
+ !
+ ! Solving for
+ ! =================
+ !
+ ! The individual marginal for simplified cloud nuclei concentration, Ncn, is
+ ! a single lognormal distribution over the entire horizontal domain. In
+ ! order to accomplish this in a two-component PDF structure, the PDF
+ ! parameters involving Ncn are set equal between the two components. This
+ ! results in:
+ !
+ ! mu_Ncn_1 = mu_Ncn_2 = mu_Ncn_i = ;
+ ! mu_Ncn_1_n = mu_Ncn_2_n = mu_Ncn_i_n;
+ ! sigma_Ncn_1 = sigma_Ncn_2 = sigma_Ncn_i = sqrt( );
+ ! sigma_Ncn_1_n = sigma_Ncn_2_n = sigma_Ncn_i_n;
+ ! rho_chi_Ncn_1 = rho_chi_Ncn_2 = rho_chi_Ncn_i = rho_chi_Ncn; and
+ ! rho_chi_Ncn_1_n = rho_chi_Ncn_2_n = rho_chi_Ncn_i_n.
+ !
+ ! Additionally, the equation for sigma_Ncn_i_n is:
+ !
+ ! sigma_Ncn_i_n = sqrt( ln( 1 + ( sigma_Ncn_i^2 / mu_Ncn_i^2 ) ) );
+ !
+ ! and the equation for rho_chi_Ncn_i_n is:
+ !
+ ! rho_chi_Ncn_i_n
+ ! = rho_chi_Ncn_i * sqrt( exp{ sigma_Ncn_i_n^2 } - 1 ) / sigma_Ncn_i_n.
+ !
+ ! The product of rho_chi_Ncn_i_n and sigma_Ncn_i_n is:
+ !
+ ! rho_chi_Ncn_i_n * sigma_Ncn_i_n
+ ! = rho_chi_Ncn_i * sqrt( exp{ sigma_Ncn_i_n^2 } - 1 ).
+ !
+ ! After substituting for sigma_Ncn_i_n^2, the equation for the product of
+ ! rho_chi_Ncn_i_n and sigma_Ncn_i_n is:
+ !
+ ! rho_chi_Ncn_i_n * sigma_Ncn_i_n
+ ! = rho_chi_Ncn_i * sqrt( sigma_Ncn_i^2 / mu_Ncn_i^2 );
+ !
+ ! which can be rewritten as:
+ !
+ ! rho_chi_Ncn_i_n * sigma_Ncn_i_n
+ ! = rho_chi_Ncn * sqrt( / ^2 ).
+ !
+ ! Substituting all of this into the equation for , the equation for
+ ! becomes:
+ !
+ ! =
+ ! * SUM(i=1,n) mixt_frac_i
+ ! ---
+ ! | (1/2) * erfc( - ( 1 / sqrt(2) )
+ ! | * ( ( mu_chi_i / sigma_chi_i )
+ ! | + rho_chi_Ncn * sqrt(/^2) ) );
+ ! | where sigma_chi_i > 0 and > 0;
+ ! |
+ ! * | (1/2) * erfc( - ( mu_chi_i / ( sqrt(2) * sigma_chi_i ) ) );
+ ! | where sigma_chi_i > 0 and = 0;
+ ! |
+ ! | 1; where sigma_chi_i = 0 and mu_chi_i > 0;
+ ! |
+ ! | 0; where sigma_chi_i = 0 and mu_chi_i <= 0.
+ ! ---
+ !
+ ! In order to isolate , the value of /^2 is set to a
+ ! constant value, const_Ncn. The value of this constant does not depend on
+ ! . Likewise, the value of rho_chi_Ncn does not depend on .
+ ! Solving for , the equation becomes:
+ !
+ !
+ ! = / ( SUM(i=1,n) mixt_frac_i
+ ! ---
+ ! | (1/2) * erfc( - ( 1 / sqrt(2) )
+ ! | * ( ( mu_chi_i / sigma_chi_i )
+ ! | + rho_chi_Ncn * sqrt( const_Ncn ) ) );
+ ! | where sigma_chi_i > 0 and const_Ncn > 0;
+ ! |
+ ! * | (1/2) * erfc( - ( mu_chi_i / ( sqrt(2) * sigma_chi_i ) ) );
+ ! | where sigma_chi_i > 0 and const_Ncn = 0;
+ ! |
+ ! | 1; where sigma_chi_i = 0 and mu_chi_i > 0;
+ ! |
+ ! | 0; where sigma_chi_i = 0 and mu_chi_i <= 0 ).
+ ! ---
+ !
+ ! When the denominator term is 0, there is only clear air. Both the
+ ! numerator () and the denominator have a value of 0, and is set
+ ! to an appropriate value.
+
+ ! References:
+ !-----------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ one, & ! Constant(s)
+ zero
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in) :: &
+ mu_chi_1, & ! Mean of chi (old s) (1st PDF component) [kg/kg]
+ mu_chi_2, & ! Mean of chi (old s) (2nd PDF component) [kg/kg]
+ sigma_chi_1, & ! Standard deviation of chi (1st PDF component) [kg/kg]
+ sigma_chi_2, & ! Standard deviation of chi (2nd PDF component) [kg/kg]
+ mixt_frac ! Mixture fraction [-]
+
+ real( kind = core_rknd ), intent(in) :: &
+ Ncm, & ! Mean cloud droplet conc. (overall) [num/kg]
+ const_Ncnp2_on_Ncnm2, & ! Prescribed ratio of to ^2 [-]
+ const_corr_chi_Ncn, & ! Prescribed correlation of chi and Ncn [-]
+ Ncnm_val_denom_0 ! Ncnm value -- denominator in eqn. is 0 [num/kg]
+
+ ! Return Variable
+ real( kind = core_rknd ) :: &
+ Ncnm ! Mean simplified cloud nuclei concentration (overall) [num/kg]
+
+ ! Local Variable
+ real( kind = core_rknd ) :: &
+ denominator_term ! Denominator in the equation for [-]
+
+
+ denominator_term &
+ = mixt_frac &
+ * bivar_Ncnm_eqn_comp( mu_chi_1, sigma_chi_1, &
+ const_Ncnp2_on_Ncnm2, const_corr_chi_Ncn ) &
+ + ( one - mixt_frac ) &
+ * bivar_Ncnm_eqn_comp( mu_chi_2, sigma_chi_2, &
+ const_Ncnp2_on_Ncnm2, const_corr_chi_Ncn )
+
+
+ if ( denominator_term > zero ) then
+
+ Ncnm = Ncm / denominator_term
+
+ else ! denominator_term = 0
+
+ ! When the denominator is 0, it is usually because there is only clear
+ ! air. In that scenario, Ncm should also be 0. Set Ncnm to a value that
+ ! is usual or typical
+ Ncnm = Ncnm_val_denom_0
+
+ endif ! denominator_term > 0
+
+
+ return
+
+ end function Ncm_to_Ncnm
+
+ !=============================================================================
+ function bivar_NL_chi_Ncn_mean( mu_chi_i, mu_Ncn_i, sigma_chi_i, &
+ sigma_Ncn_i, sigma_Ncn_i_n, corr_chi_Ncn_i_n )
+
+ ! Description:
+ ! The double integral over Ncn * H(chi) multiplied by the
+ ! bivariate normal-lognormal joint PDF of chi and Ncn is evaluated. The
+ ! integral is given by:
+ !
+ ! INT(-inf:inf) INT(0:inf) Ncn * H(chi) * P_i(chi,Ncn) dNcn dchi;
+ !
+ ! which reduces to:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi;
+ !
+ ! where the individual marginal distribution of chi is normal in the ith PDF
+ ! component and the individual marginal distribution of Ncn is lognormal in
+ ! the ith PDF component.
+ !
+ ! When both chi and Ncn vary in the ith PDF component, the integral is
+ ! evaluated and the result is:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = (1/2) * exp{ mu_Ncn_i_n + (1/2) * sigma_Ncn_i_n^2 }
+ ! * erfc( - ( 1 / sqrt(2) ) * ( ( mu_chi_i / sigma_chi_i )
+ ! + rho_chi_Ncn_i_n * sigma_Ncn_i_n ) );
+ !
+ ! which can be reduced to:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = (1/2) * mu_Ncn_i
+ ! * erfc( - ( 1 / sqrt(2) ) * ( ( mu_chi_i / sigma_chi_i )
+ ! + rho_chi_Ncn_i_n * sigma_Ncn_i_n ) ).
+ !
+ ! When chi is constant, but Ncn varies, in the ith PDF component, the
+ ! integral is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = mu_Ncn_i;
+ !
+ ! when mu_chi_i > 0; and
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = 0;
+ !
+ ! when mu_chi_i <= 0.
+ !
+ ! When chi varies, but Ncn is constant, in the ith PDF component, the
+ ! integral is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi
+ ! = mu_Ncn_i * (1/2) * erfc( - ( mu_chi_i / ( sqrt(2) * sigma_chi_i ) ) ).
+ !
+ ! When both chi and Ncn are constant in the ith PDF component, the integral
+ ! is evaluated and results in:
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = mu_Ncn_i;
+ !
+ ! when mu_chi_i > 0; and
+ !
+ ! INT(0:inf) INT(0:inf) Ncn * P_i(chi,Ncn) dNcn dchi = 0;
+ !
+ ! when mu_chi_i <= 0.
+
+ ! References:
+ !-----------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ sqrt_2, & ! Constant(s)
+ one, &
+ one_half, &
+ zero, &
+ chi_tol, &
+ Ncn_tol
+
+ use anl_erf, only: &
+ erfc ! Procedure(s)
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in) :: &
+ mu_chi_i, & ! Mean of chi (old s) (ith PDF component) [kg/kg]
+ mu_Ncn_i, & ! Mean of Ncn (ith PDF component) [num/kg]
+ sigma_chi_i, & ! Standard deviation of chi (ith PDF comp.) [kg/kg]
+ sigma_Ncn_i, & ! Standard deviation of Ncn (ith PDF comp.) [num/kg]
+ sigma_Ncn_i_n, & ! Standard deviation of ln Ncn (ith PDF component) [-]
+ corr_chi_Ncn_i_n ! Correlation of chi and ln Ncn (ith PDF comp.) [-]
+
+ ! Return Variable
+ real( kind = core_rknd ) :: &
+ bivar_NL_chi_Ncn_mean
+
+
+ if ( sigma_chi_i <=chi_tol .and. sigma_Ncn_i <= Ncn_tol ) then
+
+ ! The ith PDF component variances of both chi and Ncn are 0.
+
+ if ( mu_chi_i > zero ) then
+
+ bivar_NL_chi_Ncn_mean = mu_Ncn_i
+
+ else ! mu_chi_i <= 0
+
+ bivar_NL_chi_Ncn_mean = zero
+
+ endif
+
+
+ elseif ( sigma_chi_i <= chi_tol ) then
+
+ ! The ith PDF component variance of chi is 0.
+
+ if ( mu_chi_i > zero ) then
+
+ bivar_NL_chi_Ncn_mean = mu_Ncn_i
+
+ else ! mu_chi_i <= 0
+
+ bivar_NL_chi_Ncn_mean = zero
+
+ endif
+
+
+ elseif ( sigma_Ncn_i <= Ncn_tol ) then
+
+ ! The ith PDF component variance of Ncn is 0.
+
+ bivar_NL_chi_Ncn_mean &
+ = mu_Ncn_i * one_half * erfc( - ( mu_chi_i / ( sqrt_2 * sigma_chi_i ) ) )
+
+
+ else
+
+ ! Both chi and Ncn vary in the ith PDF component.
+
+ bivar_NL_chi_Ncn_mean &
+ = one_half * mu_Ncn_i &
+ * erfc( - ( one / sqrt_2 ) &
+ * ( ( mu_chi_i / sigma_chi_i ) &
+ + corr_chi_Ncn_i_n * sigma_Ncn_i_n ) )
+
+
+ endif
+
+
+ return
+
+ end function bivar_NL_chi_Ncn_mean
+
+ !=============================================================================
+ function bivar_Ncnm_eqn_comp( mu_chi_i, sigma_chi_i, &
+ const_Ncnp2_on_Ncnm2, const_corr_chi_Ncn )
+
+ ! Description:
+ ! When is found based on the value of , the following equation is
+ ! used:
+ !
+ !
+ ! = / ( SUM(i=1,n) mixt_frac_i
+ ! ---
+ ! | (1/2) * erfc( - ( 1 / sqrt(2) )
+ ! | * ( ( mu_chi_i / sigma_chi_i )
+ ! | + rho_chi_Ncn * sqrt( const_Ncn ) ) );
+ ! | where sigma_chi_i > 0 and const_Ncn > 0;
+ ! |
+ ! * | (1/2) * erfc( - ( mu_chi_i / ( sqrt(2) * sigma_chi_i ) ) );
+ ! | where sigma_chi_i > 0 and const_Ncn = 0;
+ ! |
+ ! | 1; where sigma_chi_i = 0 and mu_chi_i > 0;
+ ! |
+ ! | 0; where sigma_chi_i = 0 and mu_chi_i <= 0 ).
+ ! ---
+ !
+ ! In the above equation, const_Ncn = / ^2. It is a constant,
+ ! prescribed parameter. Likewise, rho_chi_Ncn is a parameter that is not
+ ! based on the value of .
+ !
+ ! When the denominator term is 0, there is only clear air. Both the
+ ! numerator () and the denominator have a value of 0, and is set
+ ! to an appropriate value.
+ !
+ ! The contribution of the ith PDF component to the denominator term in the
+ ! equation is calculated here.
+
+ ! References:
+ !-----------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ sqrt_2, & ! Constant(s)
+ one, &
+ one_half, &
+ zero, &
+ chi_tol
+
+ use anl_erf, only: &
+ erfc ! Procedure(s)
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in) :: &
+ mu_chi_i, & ! Mean of chi (old s) (ith PDF component) [kg/kg]
+ sigma_chi_i ! Standard deviation of chi (ith PDF component) [kg/kg]
+
+ real( kind = core_rknd ), intent(in) :: &
+ const_Ncnp2_on_Ncnm2, & ! Prescribed ratio of to ^2 [-]
+ const_corr_chi_Ncn ! Prescribed correlation of chi and Ncn [-]
+
+ ! Return Variable
+ real( kind = core_rknd ) :: &
+ bivar_Ncnm_eqn_comp
+
+
+ if ( sigma_chi_i <= chi_tol ) then
+
+ ! The ith PDF component variances of chi is 0. The value of the ith PDF
+ ! component variance of Ncn does not matter in this scenario.
+
+ if ( mu_chi_i > zero ) then
+
+ bivar_Ncnm_eqn_comp = one
+
+ else ! mu_chi_i <= 0
+
+ bivar_Ncnm_eqn_comp = zero
+
+ endif
+
+
+ elseif ( const_Ncnp2_on_Ncnm2 == zero ) then
+
+ ! The ith PDF component variance of Ncn is 0.
+
+ bivar_Ncnm_eqn_comp &
+ = one_half * erfc( - ( mu_chi_i / ( sqrt_2 * sigma_chi_i ) ) )
+
+
+ else
+
+ ! Both chi and Ncn vary in the ith PDF component.
+
+ bivar_Ncnm_eqn_comp &
+ = one_half &
+ * erfc( - ( one / sqrt_2 ) &
+ * ( ( mu_chi_i / sigma_chi_i ) &
+ + const_corr_chi_Ncn * sqrt( const_Ncnp2_on_Ncnm2 ) ) )
+
+
+ endif
+
+
+ return
+
+ end function bivar_Ncnm_eqn_comp
+
+!===============================================================================
+
+end module Nc_Ncn_eqns
diff --git a/models/atm/cam/src/physics/clubb/Skw_module.F90 b/models/atm/cam/src/physics/clubb/Skw_module.F90
index c51011eae8a1..5c68391bc6b7 100644
--- a/models/atm/cam/src/physics/clubb/Skw_module.F90
+++ b/models/atm/cam/src/physics/clubb/Skw_module.F90
@@ -1,5 +1,6 @@
-!$Id: Skw_module.F90 5623 2012-01-17 17:55:26Z connork@uwm.edu $
-!-------------------------------------------------------------------------------
+!-------------------------------------------------------------------------
+!$Id: Skw_module.F90 6849 2014-04-22 21:52:30Z charlass@uwm.edu $
+!===============================================================================
module Skw_module
implicit none
@@ -28,12 +29,16 @@ elemental function Skw_func( wp2, wp3 ) &
use clubb_precision, only: &
core_rknd ! Variable(s)
+ use parameters_tunable, only: &
+ Skw_denom_coef
+
implicit none
! External
intrinsic :: min, max
! Parameter Constants
+ ! Whether to apply clipping to the final result
logical, parameter :: &
l_clipping_kluge = .false.
@@ -42,15 +47,6 @@ elemental function Skw_func( wp2, wp3 ) &
wp2, & ! w'^2 [m^2/s^2]
wp3 ! w'^3 [m^3/s^3]
- real( kind = core_rknd ), parameter :: &
-
-#ifdef CLUBB_CAM
- Skw_denom_coef = 0.0_core_rknd ! want this as zero if running CAM-CLUBB
-#else
- Skw_denom_coef = 8.0_core_rknd ! Factor to decrease sensitivity in the denominator
- ! of Skw calculation
-#endif
-
! Output Variable
real( kind = core_rknd ) :: &
Skw ! Result Skw [-]
@@ -60,9 +56,9 @@ elemental function Skw_func( wp2, wp3 ) &
!Skw = wp3 / ( max( wp2, w_tol_sqd ) )**1.5_core_rknd
! Calculation of skewness to help reduce the sensitivity of this value to
! small values of wp2.
- Skw = wp3 / ( ( wp2 + Skw_denom_coef * w_tol_sqd ) )**1.5_core_rknd
+ Skw = wp3 / ( wp2 + Skw_denom_coef * w_tol_sqd )**1.5_core_rknd
- ! This is no longer need since clipping is already
+ ! This is no longer needed since clipping is already
! imposed on wp2 and wp3 elsewhere in the code
if ( l_clipping_kluge ) then
Skw = min( max( Skw, -Skw_max_mag ), Skw_max_mag )
diff --git a/models/atm/cam/src/physics/clubb/T_in_K_module.F90 b/models/atm/cam/src/physics/clubb/T_in_K_module.F90
index 5bc5c918a23c..17c040fbc1d5 100644
--- a/models/atm/cam/src/physics/clubb/T_in_K_module.F90
+++ b/models/atm/cam/src/physics/clubb/T_in_K_module.F90
@@ -1,5 +1,6 @@
-! $Id: T_in_K_module.F90 5623 2012-01-17 17:55:26Z connork@uwm.edu $
-
+!-------------------------------------------------------------------------
+! $Id: T_in_K_module.F90 6849 2014-04-22 21:52:30Z charlass@uwm.edu $
+!===============================================================================
module T_in_K_module
implicit none
diff --git a/models/atm/cam/src/physics/clubb/advance_clubb_core_module.F90 b/models/atm/cam/src/physics/clubb/advance_clubb_core_module.F90
new file mode 100644
index 000000000000..0b2fd52f5dfa
--- /dev/null
+++ b/models/atm/cam/src/physics/clubb/advance_clubb_core_module.F90
@@ -0,0 +1,3397 @@
+!-----------------------------------------------------------------------
+! $Id: advance_clubb_core_module.F90 7416 2014-12-04 20:16:51Z schemena@uwm.edu $
+!-----------------------------------------------------------------------
+module advance_clubb_core_module
+
+! Description:
+! The module containing the `core' of the CLUBB parameterization.
+! A host model implementing CLUBB should only require this subroutine
+! and the functions and subroutines it calls.
+!
+! References:
+! ``A PDF-Based Model for Boundary Layer Clouds. Part I:
+! Method and Model Description'' Golaz, et al. (2002)
+! JAS, Vol. 59, pp. 3540--3551.
+!
+! Copyright Notice:
+!
+! This code and the source code it references are (C) 2006-2014
+! Jean-Christophe Golaz, Vincent E. Larson, Brian M. Griffin,
+! David P. Schanen, Adam J. Smith, and Michael J. Falk.
+!
+! The distribution of this code and derived works thereof
+! should include this notice.
+!
+! Portions of this code derived from other sources (Hugh Morrison,
+! ACM TOMS, Numerical Recipes, et cetera) are the intellectual
+! property of their respective authors as noted and are also subject
+! to copyright.
+!-----------------------------------------------------------------------
+
+ implicit none
+
+ public :: &
+ setup_clubb_core, &
+ advance_clubb_core, &
+ cleanup_clubb_core, &
+ set_Lscale_max, &
+ calculate_thlp2_rad
+
+ private ! Default Scope
+
+ contains
+
+ !-----------------------------------------------------------------------
+
+ !#######################################################################
+ !#######################################################################
+ ! If you change the argument list of advance_clubb_core you also have to
+ ! change the calls to this function in the host models CAM, WRF, SAM
+ ! and GFDL.
+ !#######################################################################
+ !#######################################################################
+ subroutine advance_clubb_core &
+ ( l_implemented, dt, fcor, sfc_elevation, hydromet_dim, & ! intent(in)
+ thlm_forcing, rtm_forcing, um_forcing, vm_forcing, & ! intent(in)
+ sclrm_forcing, edsclrm_forcing, wprtp_forcing, & ! intent(in)
+ wpthlp_forcing, rtp2_forcing, thlp2_forcing, & ! intent(in)
+ rtpthlp_forcing, wm_zm, wm_zt, & ! intent(in)
+ wpthlp_sfc, wprtp_sfc, upwp_sfc, vpwp_sfc, & ! intent(in)
+ wpsclrp_sfc, wpedsclrp_sfc, & ! intent(in)
+ p_in_Pa, rho_zm, rho, exner, & ! intent(in)
+ rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! intent(in)
+ invrs_rho_ds_zt, thv_ds_zm, thv_ds_zt, hydromet, & ! intent(in)
+ rfrzm, radf, do_expldiff, & ! intent(in)
+#ifdef CLUBBND_CAM
+ varmu, &
+#endif
+ wphydrometp, wp2hmp, rtphmp_zt, thlphmp_zt, & ! intent(in)
+ host_dx, host_dy, & ! intent(in)
+ um, vm, upwp, vpwp, up2, vp2, & ! intent(inout)
+ thlm, rtm, wprtp, wpthlp, & ! intent(inout)
+ wp2, wp3, rtp2, thlp2, rtpthlp, & ! intent(inout)
+ sclrm, &
+#ifdef GFDL
+ sclrm_trsport_only, & ! h1g, 2010-06-16 ! intent(inout)
+#endif
+ sclrp2, sclrprtp, sclrpthlp, & ! intent(inout)
+ wpsclrp, edsclrm, err_code, & ! intent(inout)
+#ifdef GFDL
+ RH_crit, & !h1g, 2010-06-16 ! intent(inout)
+ do_liquid_only_in_clubb, & ! intent(in)
+#endif
+ rcm, wprcp, cloud_frac, ice_supersat_frac, & ! intent(out)
+ rcm_in_layer, cloud_cover, & ! intent(out)
+#if defined(CLUBB_CAM) || defined(GFDL)
+ khzm, khzt, & ! intent(out)
+#endif
+#ifdef CLUBB_CAM
+ qclvar, thlprcp_out, & ! intent(out)
+#endif
+ pdf_params ) ! intent(out)
+
+ ! Description:
+ ! Subroutine to advance the model one timestep
+
+ ! References:
+ ! ``A PDF-Based Model for Boundary Layer Clouds. Part I:
+ ! Method and Model Description'' Golaz, et al. (2002)
+ ! JAS, Vol. 59, pp. 3540--3551.
+ !-----------------------------------------------------------------------
+
+ ! Modules to be included
+
+ use constants_clubb, only: &
+ em_min, &
+ thl_tol, &
+ rt_tol, &
+ w_tol_sqd, &
+ ep2, &
+ Cp, &
+ Lv, &
+ Ls, &
+ ep1, &
+ p0, &
+ kappa, &
+ fstderr, &
+ zero_threshold, &
+ three_halves, &
+ zero, &
+ unused_var
+
+ use parameters_tunable, only: &
+ gamma_coefc, & ! Variable(s)
+ gamma_coefb, &
+ gamma_coef, &
+ taumax, &
+ c_K, &
+ mu, &
+ Lscale_mu_coef, &
+ Lscale_pert_coef, &
+ c_K10
+
+ use parameters_model, only: &
+ sclr_dim, & ! Variable(s)
+ edsclr_dim, &
+ sclr_tol, &
+ ts_nudge, &
+ rtm_min, &
+ rtm_nudge_max_altitude
+
+ use model_flags, only: &
+ l_tke_aniso, & ! Variable(s)
+ l_gamma_Skw, &
+ l_trapezoidal_rule_zt, &
+ l_trapezoidal_rule_zm, &
+ l_call_pdf_closure_twice, &
+ l_host_applies_sfc_fluxes, &
+ l_use_cloud_cover, &
+ l_rtm_nudge
+
+ use grid_class, only: &
+ gr, & ! Variable(s)
+ zm2zt, & ! Procedure(s)
+ zt2zm, &
+ ddzm
+
+ use numerical_check, only: &
+ parameterization_check, & ! Procedure(s)
+ calculate_spurious_source
+
+ use variables_diagnostic_module, only: &
+ Skw_zt, & ! Variable(s)
+ Skw_zm, &
+ sigma_sqd_w_zt, &
+ wp4, &
+ thlpthvp, &
+ rtpthvp, &
+ rtprcp, &
+ thlprcp, &
+ rcp2, &
+ rsat, &
+ pdf_params_zm, &
+ wprtp2, &
+ wp2rtp, &
+ wpthlp2, &
+ wp2thlp, &
+ wprtpthlp, &
+ wpthvp, &
+ wp2thvp, &
+ wp2rcp
+
+ use variables_diagnostic_module, only: &
+ thvm, &
+ em, &
+ Lscale, &
+ Lscale_up, &
+ Lscale_down, &
+ tau_zm, &
+ tau_zt, &
+ Kh_zm, &
+ Kh_zt, &
+ vg, &
+ ug, &
+ um_ref, &
+ vm_ref
+ use variables_diagnostic_module, only: &
+ wp2_zt, &
+ thlp2_zt, &
+ wpthlp_zt, &
+ wprtp_zt, &
+ rtp2_zt, &
+ rtpthlp_zt, &
+ up2_zt, &
+ vp2_zt, &
+ upwp_zt, &
+ vpwp_zt, &
+ rtm_ref, &
+ thlm_ref
+
+ use variables_diagnostic_module, only: &
+ wpedsclrp, &
+ sclrpthvp, & ! sclr'th_v'
+ sclrprcp, & ! sclr'rc'
+ wp2sclrp, & ! w'^2 sclr'
+ wpsclrp2, & ! w'sclr'^2
+ wpsclrprtp, & ! w'sclr'rt'
+ wpsclrpthlp, & ! w'sclr'thl'
+ wp3_zm, & ! wp3 interpolated to momentum levels
+ Skw_velocity, & ! Skewness velocity [m/s]
+ a3_coef, & ! The a3 coefficient [-]
+ a3_coef_zt ! The a3 coefficient interp. to the zt grid [-]
+
+ use variables_diagnostic_module, only: &
+ wp3_on_wp2, & ! Variable(s)
+ wp3_on_wp2_zt
+
+ use pdf_parameter_module, only: &
+ pdf_parameter ! Type
+
+#ifdef GFDL
+ use advance_sclrm_Nd_module, only: & ! h1g, 2010-06-16 begin mod
+ advance_sclrm_Nd_diffusion_OG, &
+ advance_sclrm_Nd_upwind, &
+ advance_sclrm_Nd_semi_implicit ! h1g, 2010-06-16 end mod
+#endif
+
+ use advance_xm_wpxp_module, only: &
+ ! Variable(s)
+ advance_xm_wpxp ! Compute mean/flux terms
+
+ use advance_xp2_xpyp_module, only: &
+ ! Variable(s)
+ advance_xp2_xpyp ! Computes variance terms
+
+ use surface_varnce_module, only: &
+ surface_varnce ! Procedure
+
+ use pdf_closure_module, only: &
+ ! Procedure
+ pdf_closure, & ! Prob. density function
+ calc_vert_avg_cf_component
+
+ use mixing_length, only: &
+ compute_length ! Procedure
+
+ use advance_windm_edsclrm_module, only: &
+ advance_windm_edsclrm ! Procedure(s)
+
+ use saturation, only: &
+ ! Procedure
+ sat_mixrat_liq ! Saturation mixing ratio
+
+ use advance_wp2_wp3_module, only: &
+ advance_wp2_wp3 ! Procedure
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ use error_code, only : &
+ clubb_at_least_debug_level, & ! Procedure(s)
+ report_error, &
+ fatal_error
+
+ use Skw_module, only: &
+ Skw_func ! Procedure
+
+ use clip_explicit, only: &
+ clip_covars_denom ! Procedure(s)
+
+ use T_in_K_module, only: &
+ ! Read values from namelist
+ thlm2T_in_K ! Procedure
+
+ use stats_clubb_utilities, only: &
+ stats_accumulate ! Procedure
+
+ use stats_type_utilities, only: &
+ stat_update_var_pt, & ! Procedure(s)
+ stat_update_var, &
+ stat_begin_update, &
+ stat_begin_update_pt, &
+ stat_end_update, &
+ stat_end_update_pt
+
+ use stats_variables, only: &
+ irtp2_bt, & ! Variable(s)
+ ithlp2_bt, &
+ irtpthlp_bt, &
+ iwp2_bt, &
+ iwp3_bt, &
+ ivp2_bt, &
+ iup2_bt, &
+ iwprtp_bt, &
+ iwpthlp_bt, &
+ irtm_bt, &
+ ithlm_bt, &
+ ivm_bt, &
+ ium_bt, &
+ ircp2, &
+ iwp4, &
+ irsat, &
+ irvm, &
+ irel_humidity, &
+ iwpthlp_zt, &
+ iSkw_zt, &
+ iSkw_zm
+
+ use stats_variables, only: &
+ iwprtp_zt, &
+ iup2_zt, &
+ ivp2_zt, &
+ iupwp_zt, &
+ ivpwp_zt, &
+ ithlp2_sf, &
+ irtp2_sf, &
+ irtpthlp_sf, &
+ iup2_sf, &
+ ivp2_sf, &
+ iwp2_sf, &
+ l_stats_samp, &
+ l_stats, &
+ stats_zt, &
+ stats_zm, &
+ stats_sfc, &
+ irtm_spur_src, &
+ ithlm_spur_src
+
+ use stats_variables, only: &
+ irfrzm, & ! Variable(s)
+ icloud_frac_refined, &
+ istability_correction, &
+ ircm_refined
+
+ use stats_variables, only: &
+ iSkw_velocity, & ! Variable(s)
+ igamma_Skw_fnc, &
+ iLscale_pert_1, &
+ iLscale_pert_2
+
+ use fill_holes, only: &
+ vertical_integral, & ! Procedure(s)
+ fill_holes_vertical
+
+ use sigma_sqd_w_module, only: &
+ compute_sigma_sqd_w ! Procedure(s)
+
+ use array_index, only: &
+ iirrm ! Variable
+
+ use pdf_utilities, only: &
+ compute_mean_binormal
+
+ use advance_helper_module, only: &
+ calc_stability_correction ! Procedure(s)
+
+ use interpolation, only: &
+ pvertinterp
+
+ implicit none
+
+ !!! External
+ intrinsic :: sqrt, min, max, exp, mod, real
+
+ ! Constant Parameters
+ logical, parameter :: l_avg_Lscale = .false. ! Lscale is calculated in subroutine compute_length; if l_avg_Lscale
+ ! is true, compute_length is called two additional times with
+ ! perturbed values of rtm and thlm. An average value of Lscale
+ ! from the three calls to compute_length is then calculated.
+ ! This reduces temporal noise in RICO, BOMEX, LBA, and other cases.
+#ifdef CLUBBND_CAM
+
+ logical, parameter :: &
+ l_Lscale_plume_centered = .true. ! Alternate that uses the PDF to
+ ! compute the perturbed values
+
+ logical, parameter :: &
+ l_use_ice_latent = .true. !Includes the effects of ice latent heating in turbulence terms
+
+#else
+
+ logical, parameter :: &
+ l_Lscale_plume_centered = .false. ! Alternate that uses the PDF to
+ ! compute the perturbed values
+
+ logical, parameter :: &
+ l_use_ice_latent = .false. !Includes the effects of ice latent heating in turbulence terms
+
+#endif
+
+ logical, parameter :: &
+ l_iter_xp2_xpyp = .true. ! Set to true when rtp2/thlp2/rtpthlp, et cetera are prognostic
+
+ logical, parameter :: &
+ l_refine_grid_in_cloud = .false., & ! Compute cloud_frac and rcm on a refined grid
+
+ l_interactive_refined = .false. ! Should the refined grid code feed into the model?
+ ! Only has meaning if l_refined_grid_in_cloud is .true.
+
+ real( kind = core_rknd ), parameter :: &
+ chi_at_liq_sat = 0._core_rknd ! Value of chi(s) at saturation with respect to ice
+ ! (zero for liquid)
+ logical, parameter :: &
+ l_stability_correct_tau_zm = .true. ! Use tau_N2_zm instead of tau_zm in wpxp_pr1
+
+ !!! Input Variables
+ logical, intent(in) :: &
+ l_implemented ! Is this part of a larger host model (T/F) ?
+
+ real( kind = core_rknd ), intent(in) :: &
+ dt ! Current timestep duration [s]
+
+ real( kind = core_rknd ), intent(in) :: &
+ fcor, & ! Coriolis forcing [s^-1]
+ sfc_elevation ! Elevation of ground level [m AMSL]
+
+ integer, intent(in) :: &
+ hydromet_dim ! Total number of hydrometeors [#]
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in), dimension(gr%nz) :: &
+ thlm_forcing, & ! theta_l forcing (thermodynamic levels) [K/s]
+ rtm_forcing, & ! r_t forcing (thermodynamic levels) [(kg/kg)/s]
+ um_forcing, & ! u wind forcing (thermodynamic levels) [m/s/s]
+ vm_forcing, & ! v wind forcing (thermodynamic levels) [m/s/s]
+ wprtp_forcing, & ! forcing (momentum levels) [m*K/s^2]
+ wpthlp_forcing, & ! forcing (momentum levels) [m*(kg/kg)/s^2]
+ rtp2_forcing, & ! forcing (momentum levels) [(kg/kg)^2/s]
+ thlp2_forcing, & ! forcing (momentum levels) [K^2/s]
+ rtpthlp_forcing, & ! forcing (momentum levels) [K*(kg/kg)/s]
+ wm_zm, & ! w mean wind component on momentum levels [m/s]
+ wm_zt, & ! w mean wind component on thermo. levels [m/s]
+ p_in_Pa, & ! Air pressure (thermodynamic levels) [Pa]
+ rho_zm, & ! Air density on momentum levels [kg/m^3]
+ rho, & ! Air density on thermodynamic levels [kg/m^3]
+ exner, & ! Exner function (thermodynamic levels) [-]
+ rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
+ rho_ds_zt, & ! Dry, static density on thermo. levels [kg/m^3]
+ invrs_rho_ds_zm, & ! Inv. dry, static density @ momentum levs. [m^3/kg]
+ invrs_rho_ds_zt, & ! Inv. dry, static density @ thermo. levs. [m^3/kg]
+ thv_ds_zm, & ! Dry, base-state theta_v on momentum levs. [K]
+ thv_ds_zt, & ! Dry, base-state theta_v on thermo. levs. [K]
+ rfrzm ! Total ice-phase water mixing ratio [kg/kg]
+
+ logical, intent(in) :: do_expldiff
+
+#ifdef CLUBBND_CAM
+ real( kind = core_rknd ), intent(in) :: varmu
+#endif
+
+ real( kind = core_rknd ), dimension(gr%nz,hydromet_dim), intent(in) :: &
+ hydromet ! Collection of hydrometeors [units vary]
+
+ real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
+ radf ! Buoyancy production at the CL top due to LW radiative cooling [m^2/s^3]
+
+ real( kind = core_rknd ), dimension(gr%nz, hydromet_dim), intent(in) :: &
+ wphydrometp, & ! Covariance of w and a hydrometeor [(m/s) ]
+ wp2hmp, & ! Third-order moment: < w'^2 hm' > [(m/s)^2 ]
+ rtphmp_zt, & ! Covariance of rt and hm (on t-levs.) [(kg/kg) ]
+ thlphmp_zt ! Covariance of thl and hm (on t-levs.) [K ]
+
+ real( kind = core_rknd ), intent(in) :: &
+ wpthlp_sfc, & ! w' theta_l' at surface [(m K)/s]
+ wprtp_sfc, & ! w' r_t' at surface [(kg m)/( kg s)]
+ upwp_sfc, & ! u'w' at surface [m^2/s^2]
+ vpwp_sfc ! v'w' at surface [m^2/s^2]
+
+ ! Passive scalar variables
+ real( kind = core_rknd ), intent(in), dimension(gr%nz,sclr_dim) :: &
+ sclrm_forcing ! Passive scalar forcing [{units vary}/s]
+
+ real( kind = core_rknd ), intent(in), dimension(sclr_dim) :: &
+ wpsclrp_sfc ! Scalar flux at surface [{units vary} m/s]
+
+ ! Eddy passive scalar variables
+ real( kind = core_rknd ), intent(in), dimension(gr%nz,edsclr_dim) :: &
+ edsclrm_forcing ! Eddy passive scalar forcing [{units vary}/s]
+
+ real( kind = core_rknd ), intent(in), dimension(edsclr_dim) :: &
+ wpedsclrp_sfc ! Eddy-Scalar flux at surface [{units vary} m/s]
+
+ ! Host model horizontal grid spacing, if part of host model.
+ real( kind = core_rknd ), intent(in) :: &
+ host_dx, & ! East-West horizontal grid spacing [m]
+ host_dy ! North-South horizontal grid spacing [m]
+
+ !!! Input/Output Variables
+ ! These are prognostic or are planned to be in the future
+ real( kind = core_rknd ), intent(inout), dimension(gr%nz) :: &
+ um, & ! u mean wind component (thermodynamic levels) [m/s]
+ upwp, & ! u'w' (momentum levels) [m^2/s^2]
+ vm, & ! v mean wind component (thermodynamic levels) [m/s]
+ vpwp, & ! v'w' (momentum levels) [m^2/s^2]
+ up2, & ! u'^2 (momentum levels) [m^2/s^2]
+ vp2, & ! v'^2 (momentum levels) [m^2/s^2]
+ rtm, & ! total water mixing ratio, r_t (thermo. levels) [kg/kg]
+ wprtp, & ! w' r_t' (momentum levels) [(kg/kg) m/s]
+ thlm, & ! liq. water pot. temp., th_l (thermo. levels) [K]
+ wpthlp, & ! w' th_l' (momentum levels) [(m/s) K]
+ rtp2, & ! r_t'^2 (momentum levels) [(kg/kg)^2]
+ thlp2, & ! th_l'^2 (momentum levels) [K^2]
+ rtpthlp, & ! r_t' th_l' (momentum levels) [(kg/kg) K]
+ wp2, & ! w'^2 (momentum levels) [m^2/s^2]
+ wp3 ! w'^3 (thermodynamic levels) [m^3/s^3]
+
+ ! Passive scalar variables
+ real( kind = core_rknd ), intent(inout), dimension(gr%nz,sclr_dim) :: &
+ sclrm, & ! Passive scalar mean (thermo. levels) [units vary]
+ wpsclrp, & ! w'sclr' (momentum levels) [{units vary} m/s]
+ sclrp2, & ! sclr'^2 (momentum levels) [{units vary}^2]
+ sclrprtp, & ! sclr'rt' (momentum levels) [{units vary} (kg/kg)]
+ sclrpthlp ! sclr'thl' (momentum levels) [{units vary} K]
+
+#ifdef GFDL
+ real( kind = core_rknd ), intent(inout), dimension(gr%nz,sclr_dim) :: & ! h1g, 2010-06-16
+ sclrm_trsport_only ! Passive scalar concentration due to pure transport [{units vary}/s]
+#endif
+
+ ! Eddy passive scalar variable
+ real( kind = core_rknd ), intent(inout), dimension(gr%nz,edsclr_dim) :: &
+ edsclrm ! Eddy passive scalar mean (thermo. levels) [units vary]
+
+ ! Variables that need to be output for use in other parts of the CLUBB
+ ! code, such as microphysics (rcm, pdf_params), forcings (rcm), and/or
+ ! BUGSrad (cloud_cover).
+ real( kind = core_rknd ), intent(out), dimension(gr%nz) :: &
+ rcm, & ! cloud water mixing ratio, r_c (thermo. levels) [kg/kg]
+ rcm_in_layer, & ! rcm in cloud layer [kg/kg]
+ cloud_cover ! cloud cover [-]
+
+ type(pdf_parameter), dimension(gr%nz), intent(out) :: &
+ pdf_params ! PDF parameters [units vary]
+
+ ! Variables that need to be output for use in host models
+ real( kind = core_rknd ), intent(out), dimension(gr%nz) :: &
+ wprcp, & ! w'r_c' (momentum levels) [(kg/kg) m/s]
+ cloud_frac, & ! cloud fraction (thermodynamic levels) [-]
+ ice_supersat_frac ! ice cloud fraction (thermodynamic levels) [-]
+
+ ! Eric Raut declared this variable solely for output to disk
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ rc_coef ! Coefficient of X' R_l' in Eq. (34) [-]
+
+#if defined(CLUBB_CAM) || defined(GFDL)
+ real( kind = core_rknd ), intent(out), dimension(gr%nz) :: &
+ khzt, & ! eddy diffusivity on thermo levels
+ khzm, & ! eddy diffusivity on momentum levels
+ thlprcp_out
+#endif
+
+#ifdef CLUBB_CAM
+ real( kind = core_rknd), intent(out), dimension(gr%nz) :: &
+ qclvar ! cloud water variance
+#endif
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ Km_zm
+
+ real( kind = core_rknd ):: newmu
+
+ !!! Output Variable
+ ! Diagnostic, for if some calculation goes amiss.
+ integer, intent(inout) :: err_code
+
+#ifdef GFDL
+ ! hlg, 2010-06-16
+ real( kind = core_rknd ), intent(inOUT), dimension(gr%nz, min(1,sclr_dim) , 2) :: &
+ RH_crit ! critical relative humidity for droplet and ice nucleation
+! ---> h1g, 2012-06-14
+ logical, intent(in) :: do_liquid_only_in_clubb
+! <--- h1g, 2012-06-14
+#endif
+
+ !!! Local Variables
+ integer :: i, k, ixind, &
+ err_code_pdf_closure, err_code_surface
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ sigma_sqd_w, & ! PDF width parameter (momentum levels) [-]
+ sqrt_em_zt, & ! sqrt( em ) on zt levels; where em is TKE [m/s]
+ gamma_Skw_fnc, & ! Gamma as a function of skewness [???]
+ Lscale_pert_1, Lscale_pert_2, & ! For avg. calculation of Lscale [m]
+ thlm_pert_1, thlm_pert_2, & ! For avg. calculation of Lscale [K]
+ rtm_pert_1, rtm_pert_2, & ! For avg. calculation of Lscale [kg/kg]
+ thlm_pert_pos_rt, thlm_pert_neg_rt, & ! For avg. calculation of Lscale [K]
+ rtm_pert_pos_rt, rtm_pert_neg_rt ! For avg. calculation of Lscale [kg/kg]
+ !Lscale_weight Uncomment this if you need to use this vairable at some point.
+
+ ! For pdf_closure
+ real( kind = core_rknd ), dimension(gr%nz,sclr_dim) :: &
+ wpsclrp_zt, & ! w' sclr' on thermo. levels
+ sclrp2_zt, & ! sclr'^2 on thermo. levels
+ sclrprtp_zt, & ! sclr' r_t' on thermo. levels
+ sclrpthlp_zt ! sclr' th_l' on thermo. levels
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ p_in_Pa_zm, & ! Pressure interpolated to momentum levels [Pa]
+ exner_zm, & ! Exner interpolated to momentum levels [-]
+ w_1_zm, & ! Mean w (1st PDF component) [m/s]
+ w_2_zm, & ! Mean w (2nd PDF component) [m/s]
+ varnce_w_1_zm, & ! Variance of w (1st PDF component) [m^2/s^2]
+ varnce_w_2_zm, & ! Variance of w (2nd PDF component) [m^2/s^2]
+ mixt_frac_zm ! Weight of 1st PDF component (Sk_w dependent) [-]
+
+ real( kind = core_rknd ), dimension(gr%nz,hydromet_dim) :: &
+ wphydrometp_zt, & ! Covariance of w and hm (on t-levs.) [(m/s) ]
+ wp2hmp_zm, & ! Moment (on m-levs.) [(m/s)^2 ]
+ rtphmp, & ! Covariance of rt and hm [(kg/kg) ]
+ thlphmp ! Covariance of thl and hm [K ]
+
+ integer :: &
+ wprtp_cl_num, & ! Instance of w'r_t' clipping (1st or 3rd).
+ wpthlp_cl_num, & ! Instance of w'th_l' clipping (1st or 3rd).
+ wpsclrp_cl_num, & ! Instance of w'sclr' clipping (1st or 3rd).
+ upwp_cl_num, & ! Instance of u'w' clipping (1st or 2nd).
+ vpwp_cl_num ! Instance of v'w' clipping (1st or 2nd).
+
+ ! These local variables are declared because they originally belong on the momentum
+ ! grid levels, but pdf_closure outputs them on the thermodynamic grid levels.
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ wp4_zt, & ! w'^4 (on thermo. grid) [m^4/s^4]
+ wpthvp_zt, & ! Buoyancy flux (on thermo. grid) [(K m)/s]
+ rtpthvp_zt, & ! r_t' th_v' (on thermo. grid) [(kg K)/kg]
+ thlpthvp_zt, & ! th_l' th_v' (on thermo. grid) [K^2]
+ wprcp_zt, & ! w' r_c' (on thermo. grid) [(m kg)/(s kg)]
+ rtprcp_zt, & ! r_t' r_c' (on thermo. grid) [(kg^2)/(kg^2)]
+ thlprcp_zt, & ! th_l' r_c' (on thermo. grid) [(K kg)/kg]
+ rcp2_zt, & ! r_c'^2 (on thermo. grid) [(kg^2)/(kg^2)]
+ rc_coef_zt ! X'R_l' coef. (on thermo. grid) [-]
+
+ real( kind = core_rknd ), dimension(gr%nz, sclr_dim) :: &
+ sclrpthvp_zt, & ! sclr'th_v' (on thermo. grid)
+ sclrprcp_zt ! sclr'rc' (on thermo. grid)
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ wprtp2_zm, & ! w'rt'^2 on momentum grid [m kg^2/kg^2]
+ wp2rtp_zm, & ! w'^2 rt' on momentum grid [m^2 kg/kg]
+ wpthlp2_zm, & ! w'thl'^2 on momentum grid [m K^2/s]
+ wp2thlp_zm, & ! w'^2 thl' on momentum grid [m^2 K/s^2]
+ wprtpthlp_zm, & ! w'rt'thl' on momentum grid [m kg K/kg s]
+ cloud_frac_zm, & ! Cloud Fraction on momentum grid [-]
+ ice_supersat_frac_zm, & ! Ice Cloud Fraction on momentum grid [-]
+ rtm_zm, & ! Total water mixing ratio [kg/kg]
+ thlm_zm, & ! Liquid potential temperature [kg/kg]
+ rcm_zm, & ! Liquid water mixing ratio on momentum grid [kg/kg]
+ wp2thvp_zm, & ! w'^2 th_v' on momentum grid [m^2 K/s^2]
+ wp2rcp_zm, & ! w'^2 rc' on momentum grid [m^2 kg/kg s^2]
+ sign_rtpthlp ! sign of the covariance rtpthlp [-]
+
+ real( kind = core_rknd ), dimension(gr%nz,sclr_dim) :: &
+ wpsclrprtp_zm, & ! w'sclr'rt' on momentum grid
+ wpsclrp2_zm, & ! w'sclr'^2 on momentum grid
+ wpsclrpthlp_zm, & ! w'sclr'thl' on momentum grid
+ wp2sclrp_zm, & ! w'^2 sclr' on momentum grid
+ sclrm_zm ! Passive scalar mean on momentum grid
+
+ real( kind = core_rknd ) :: &
+ rtm_integral_before, &
+ rtm_integral_after, &
+ rtm_integral_forcing, &
+ rtm_flux_top, &
+ rtm_flux_sfc, &
+ rtm_spur_src, &
+ thlm_integral_before, &
+ thlm_integral_after, &
+ thlm_integral_forcing, &
+ thlm_flux_top, &
+ thlm_flux_sfc, &
+ thlm_spur_src, &
+ mu_pert_1, mu_pert_2, & ! For l_avg_Lscale
+ mu_pert_pos_rt, mu_pert_neg_rt ! For l_Lscale_plume_centered
+
+ !The following variables are defined for use when l_use_ice_latent = .true.
+ type(pdf_parameter), dimension(gr%nz) :: &
+ pdf_params_frz, &
+ pdf_params_zm_frz
+
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ rtm_frz, &
+ thlm_frz, &
+ wp4_zt_frz, &
+ wprtp2_frz, &
+ wp2rtp_frz, &
+ wpthlp2_frz, &
+ wp2thlp_frz, &
+ wprtpthlp_frz, &
+ cloud_frac_frz, &
+ ice_supersat_frac_frz, &
+ rcm_frz, &
+ wpthvp_frz, &
+ wpthvp_zt_frz, &
+ wp2thvp_frz, &
+ wp2thvp_zm_frz, &
+ rtpthvp_frz, &
+ rtpthvp_zt_frz, &
+ thlpthvp_frz, &
+ thlpthvp_zt_frz, &
+ wprcp_zt_frz, &
+ wp2rcp_frz
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ rtprcp_zt_frz, &
+ thlprcp_zt_frz, &
+ rcp2_zt_frz, &
+ rc_coef_zt_frz, &
+ wp4_frz, &
+ wprtp2_zm_frz, &
+ wp2rtp_zm_frz, &
+ wpthlp2_zm_frz, &
+ wp2thlp_zm_frz, &
+ wprtpthlp_zm_frz, &
+ cloud_frac_zm_frz, &
+ ice_supersat_frac_zm_frz, &
+ rcm_zm_frz, &
+ wprcp_frz, &
+ wp2rcp_zm_frz, &
+ rtprcp_frz, &
+ thlprcp_frz, &
+ rcp2_frz, &
+ rtm_zm_frz, &
+ thlm_zm_frz, &
+ rc_coef_frz
+
+ real( kind = core_rknd ), dimension(gr%nz,sclr_dim) :: &
+ wpsclrprtp_frz, &
+ wpsclrp2_frz, &
+ sclrpthvp_zt_frz, &
+ wpsclrpthlp_frz, &
+ sclrprcp_zt_frz, &
+ wp2sclrp_frz, &
+ wpsclrprtp_zm_frz, &
+ wpsclrp2_zm_frz, &
+ sclrpthvp_frz, &
+ wpsclrpthlp_zm_frz, &
+ sclrprcp_frz, &
+ wp2sclrp_zm_frz
+
+ real( kind = core_rknd ) :: &
+ cloud_frac_1_refined, & ! cloud_frac_1 computed on refined grid
+ cloud_frac_2_refined, & ! cloud_frac_2 computed on refined grid
+ rc_1_refined, & ! rc_1 computed on refined grid
+ rc_2_refined, & ! rc_2 computed on refined grid
+ cloud_frac_refined, & ! cloud_frac gridbox mean on refined grid
+ rcm_refined, & ! rcm gridbox mean on refined grid
+ thlm1000, &
+ thlm700
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ rrm ! Rain water mixing ratio
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ stability_correction, & ! Stability correction factor
+ tau_N2_zm, & ! Tau with a static stability correction applied to it [s]
+ tau_C6_zm, & ! Tau values used for the C6 (pr1) term in wpxp [s]
+ tau_C1_zm ! Tau values used for the C1 (dp1) term in wp2 [s]
+
+ real( kind = core_rknd ) :: Lscale_max
+
+ !----- Begin Code -----
+
+ ! Determine the maximum allowable value for Lscale (in meters).
+ call set_Lscale_max( l_implemented, host_dx, host_dy, & ! intent(in)
+ Lscale_max ) ! intent(out)
+
+ if ( l_stats .and. l_stats_samp ) then
+ ! Spurious source will only be calculated if rtm_ma and thlm_ma are zero.
+ ! Therefore, wm must be zero or l_implemented must be true.
+ if ( l_implemented .or. ( all( wm_zt == 0._core_rknd ) .and. &
+ all( wm_zm == 0._core_rknd ) ) ) then
+ ! Get the vertical integral of rtm and thlm before this function begins
+ ! so that spurious source can be calculated
+ rtm_integral_before &
+ = vertical_integral( (gr%nz - 2 + 1), rho_ds_zt(2:gr%nz), &
+ rtm(2:gr%nz), gr%invrs_dzt(2:gr%nz) )
+
+ thlm_integral_before &
+ = vertical_integral( (gr%nz - 2 + 1), rho_ds_zt(2:gr%nz), &
+ thlm(2:gr%nz), gr%invrs_dzt(2:gr%nz) )
+ end if
+ end if
+
+ !----------------------------------------------------------------
+ ! Test input variables
+ !----------------------------------------------------------------
+ if ( clubb_at_least_debug_level( 2 ) ) then
+ call parameterization_check &
+ ( thlm_forcing, rtm_forcing, um_forcing, vm_forcing, & ! intent(in)
+ wm_zm, wm_zt, p_in_Pa, rho_zm, rho, exner, & ! intent(in)
+ rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! intent(in)
+ invrs_rho_ds_zt, thv_ds_zm, thv_ds_zt, & ! intent(in)
+ wpthlp_sfc, wprtp_sfc, upwp_sfc, vpwp_sfc, & ! intent(in)
+ um, upwp, vm, vpwp, up2, vp2, & ! intent(in)
+ rtm, wprtp, thlm, wpthlp, & ! intent(in)
+ wp2, wp3, rtp2, thlp2, rtpthlp, & ! intent(in)
+ "beginning of ", & ! intent(in)
+ wpsclrp_sfc, wpedsclrp_sfc, & ! intent(in)
+ sclrm, wpsclrp, sclrp2, sclrprtp, sclrpthlp, & ! intent(in)
+ sclrm_forcing, edsclrm, edsclrm_forcing, & ! intent(in)
+ err_code ) ! intent(inout)
+ end if
+ !-----------------------------------------------------------------------
+
+ if ( l_stats_samp ) then
+ call stat_update_var( irfrzm, rfrzm, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ end if
+
+ ! Set up budget stats variables.
+ if ( l_stats_samp ) then
+
+ call stat_begin_update( iwp2_bt, wp2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update( ivp2_bt, vp2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update( iup2_bt, up2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update( iwprtp_bt, wprtp / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update( iwpthlp_bt, wpthlp / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update( irtp2_bt, rtp2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update( ithlp2_bt, thlp2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update( irtpthlp_bt, rtpthlp / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+
+ call stat_begin_update( irtm_bt, rtm / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_begin_update( ithlm_bt, thlm / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_begin_update( ium_bt, um / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_begin_update( ivm_bt, vm / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_begin_update( iwp3_bt, wp3 / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+
+ end if
+
+ ! SET SURFACE VALUES OF FLUXES (BROUGHT IN)
+ ! We only do this for host models that do not apply the flux
+ ! elsewhere in the code (e.g. WRF). In other cases the _sfc variables will
+ ! only be used to compute the variance at the surface. -dschanen 8 Sept 2009
+ if ( .not. l_host_applies_sfc_fluxes ) then
+
+ wpthlp(1) = wpthlp_sfc
+ wprtp(1) = wprtp_sfc
+ upwp(1) = upwp_sfc
+ vpwp(1) = vpwp_sfc
+
+ ! Set fluxes for passive scalars (if enabled)
+ if ( sclr_dim > 0 ) then
+ wpsclrp(1,1:sclr_dim) = wpsclrp_sfc(1:sclr_dim)
+ end if
+
+ if ( edsclr_dim > 0 ) then
+ wpedsclrp(1,1:edsclr_dim) = wpedsclrp_sfc(1:edsclr_dim)
+ end if
+
+ else
+
+ wpthlp(1) = 0.0_core_rknd
+ wprtp(1) = 0.0_core_rknd
+ upwp(1) = 0.0_core_rknd
+ vpwp(1) = 0.0_core_rknd
+
+ ! Set fluxes for passive scalars (if enabled)
+ if ( sclr_dim > 0 ) then
+ wpsclrp(1,1:sclr_dim) = 0.0_core_rknd
+ end if
+
+ if ( edsclr_dim > 0 ) then
+ wpedsclrp(1,1:edsclr_dim) = 0.0_core_rknd
+ end if
+
+ end if ! ~l_host_applies_sfc_fluxes
+
+#ifdef CLUBBND_CAM
+ newmu = varmu
+#else
+ newmu = mu
+#endif
+
+ !---------------------------------------------------------------------------
+ ! Interpolate wp3 to momentum levels, and wp2 to thermodynamic levels
+ ! and then compute Skw for m & t grid
+ !---------------------------------------------------------------------------
+
+ wp2_zt = max( zm2zt( wp2 ), w_tol_sqd ) ! Positive definite quantity
+ wp3_zm = zt2zm( wp3 )
+
+ Skw_zt(1:gr%nz) = Skw_func( wp2_zt(1:gr%nz), wp3(1:gr%nz) )
+ Skw_zm(1:gr%nz) = Skw_func( wp2(1:gr%nz), wp3_zm(1:gr%nz) )
+
+ if ( l_stats_samp ) then
+ call stat_update_var( iSkw_zt, Skw_zt, & ! In
+ stats_zt ) ! In/Out
+ call stat_update_var( iSkw_zm, Skw_zm, &
+ stats_zm ) ! In/Out
+ end if
+
+ ! The right hand side of this conjunction is only for reducing cpu time,
+ ! since the more complicated formula is mathematically equivalent
+ if ( l_gamma_Skw .and. ( gamma_coef /= gamma_coefb ) ) then
+ !----------------------------------------------------------------
+ ! Compute gamma as a function of Skw - 14 April 06 dschanen
+ !----------------------------------------------------------------
+
+ gamma_Skw_fnc = gamma_coefb + (gamma_coef-gamma_coefb) &
+ *exp( -(1.0_core_rknd/2.0_core_rknd) * (Skw_zm/gamma_coefc)**2 )
+
+ else
+
+ gamma_Skw_fnc = gamma_coef
+
+ end if
+
+ ! Compute sigma_sqd_w (dimensionless PDF width parameter)
+ sigma_sqd_w = compute_sigma_sqd_w( gamma_Skw_fnc, wp2, thlp2, rtp2, wpthlp, wprtp )
+
+ if ( l_stats_samp ) then
+ call stat_update_var( igamma_Skw_fnc, gamma_Skw_fnc, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ endif
+
+ ! Smooth in the vertical using interpolation
+ sigma_sqd_w = zt2zm( zm2zt( sigma_sqd_w ) )
+
+ ! Interpolate the the stats_zt grid
+ sigma_sqd_w_zt = max( zm2zt( sigma_sqd_w ), zero_threshold ) ! Pos. def. quantity
+
+ ! Compute the a3 coefficient (formula 25 in `Equations for CLUBB')
+! a3_coef = 3.0_core_rknd * sigma_sqd_w*sigma_sqd_w &
+! + 6.0_core_rknd*(1.0_core_rknd-sigma_sqd_w)*sigma_sqd_w &
+! + (1.0_core_rknd-sigma_sqd_w)*(1.0_core_rknd-sigma_sqd_w) &
+! - 3.0_core_rknd
+
+ ! This is a simplified version of the formula above.
+ a3_coef = -2._core_rknd * ( 1._core_rknd - sigma_sqd_w )**2
+
+ ! We found we obtain fewer spikes in wp3 when we clip a3 to be no greater
+ ! than -1.4 -dschanen 4 Jan 2011
+ a3_coef = max( a3_coef, -1.4_core_rknd ) ! Known magic number
+
+ a3_coef_zt = zm2zt( a3_coef )
+
+ !---------------------------------------------------------------------------
+ ! Interpolate thlp2, rtp2, and rtpthlp to thermodynamic levels,
+ !---------------------------------------------------------------------------
+
+ ! Interpolate variances to the stats_zt grid (statistics and closure)
+ thlp2_zt = max( zm2zt( thlp2 ), thl_tol**2 ) ! Positive def. quantity
+ rtp2_zt = max( zm2zt( rtp2 ), rt_tol**2 ) ! Positive def. quantity
+ rtpthlp_zt = zm2zt( rtpthlp )
+
+ ! Compute skewness velocity for stats output purposes
+ if ( iSkw_velocity > 0 ) then
+ Skw_velocity = ( 1.0_core_rknd / ( 1.0_core_rknd - sigma_sqd_w(1:gr%nz) ) ) &
+ * ( wp3_zm(1:gr%nz) / max( wp2(1:gr%nz), w_tol_sqd ) )
+ end if
+
+ ! Compute wp3 / wp2 on zt levels. Always use the interpolated value in the
+ ! denominator since it's less likely to create spikes
+ wp3_on_wp2_zt = ( wp3(1:gr%nz) / max( wp2_zt(1:gr%nz), w_tol_sqd ) )
+
+ ! Clip wp3_on_wp2_zt if it's too large
+ do k=1, gr%nz
+ if( wp3_on_wp2_zt(k) < 0._core_rknd ) then
+ wp3_on_wp2_zt = max( -1000._core_rknd, wp3_on_wp2_zt )
+ else
+ wp3_on_wp2_zt = min( 1000._core_rknd, wp3_on_wp2_zt )
+ end if
+ end do
+
+ ! Compute wp3_on_wp2 by interpolating wp3_on_wp2_zt
+ wp3_on_wp2 = zt2zm( wp3_on_wp2_zt )
+
+ ! Smooth again as above
+ wp3_on_wp2_zt = zm2zt( wp3_on_wp2 )
+
+ !----------------------------------------------------------------
+ ! Call closure scheme
+ !----------------------------------------------------------------
+
+ ! Put passive scalar input on the t grid for the PDF
+ do i = 1, sclr_dim, 1
+ wpsclrp_zt(:,i) = zm2zt( wpsclrp(:,i) )
+ sclrp2_zt(:,i) = max( zm2zt( sclrp2(:,i) ), zero_threshold ) ! Pos. def. quantity
+ sclrprtp_zt(:,i) = zm2zt( sclrprtp(:,i) )
+ sclrpthlp_zt(:,i) = zm2zt( sclrpthlp(:,i) )
+ end do ! i = 1, sclr_dim, 1
+
+ ! Interpolate hydrometeor mixed moments to momentum levels.
+ do i = 1, hydromet_dim, 1
+ wphydrometp_zt(:,i) = zm2zt( wphydrometp(:,i) )
+ enddo ! i = 1, hydromet_dim, 1
+
+
+ do k = 1, gr%nz, 1
+
+ call pdf_closure &
+ ( hydromet_dim, p_in_Pa(k), exner(k), thv_ds_zt(k), wm_zt(k), & ! intent(in)
+ wp2_zt(k), wp3(k), sigma_sqd_w_zt(k), & ! intent(in)
+ Skw_zt(k), rtm(k), rtp2_zt(k), & ! intent(in)
+ zm2zt( wprtp, k ), thlm(k), thlp2_zt(k), & ! intent(in)
+ zm2zt( wpthlp, k ), rtpthlp_zt(k), sclrm(k,:), & ! intent(in)
+ wpsclrp_zt(k,:), sclrp2_zt(k,:), sclrprtp_zt(k,:), & ! intent(in)
+ sclrpthlp_zt(k,:), k, & ! intent(in)
+#ifdef GFDL
+ RH_crit(k, : , :), do_liquid_only_in_clubb, & ! intent(in)
+#endif
+ wphydrometp_zt(k,:), wp2hmp(k,:), & ! intent(in)
+ rtphmp_zt(k,:), thlphmp_zt(k,:), & ! intent(in)
+ wp4_zt(k), wprtp2(k), wp2rtp(k), & ! intent(out)
+ wpthlp2(k), wp2thlp(k), wprtpthlp(k), & ! intent(out)
+ cloud_frac(k), ice_supersat_frac(k), & ! intent(out)
+ rcm(k), wpthvp_zt(k), wp2thvp(k), rtpthvp_zt(k), & ! intent(out)
+ thlpthvp_zt(k), wprcp_zt(k), wp2rcp(k), rtprcp_zt(k), & ! intent(out)
+ thlprcp_zt(k), rcp2_zt(k), pdf_params(k), & ! intent(out)
+ err_code_pdf_closure, & ! intent(out)
+ wpsclrprtp(k,:), wpsclrp2(k,:), sclrpthvp_zt(k,:), & ! intent(out)
+ wpsclrpthlp(k,:), sclrprcp_zt(k,:), wp2sclrp(k,:), & ! intent(out)
+ rc_coef_zt(k) ) ! intent(out)
+
+ ! Subroutine may produce NaN values, and if so, exit
+ ! gracefully.
+ ! Joshua Fasching March 2008
+
+ if ( fatal_error( err_code_pdf_closure ) ) then
+
+ if ( clubb_at_least_debug_level( 1 ) ) then
+ write(fstderr,*) "At grid level = ",k
+ end if
+
+ err_code = err_code_pdf_closure
+ end if
+
+ end do ! k = 1, gr%nz, 1
+
+ if ( l_refine_grid_in_cloud ) then
+
+ ! Compute cloud_frac and rcm on a refined grid to improve parameterization
+ ! of subgrid clouds
+ do k=1, gr%nz
+
+ if ( pdf_params(k)%chi_1/pdf_params(k)%stdev_chi_1 > -1._core_rknd ) then
+
+ ! Recalculate cloud_frac and r_c for each PDF component
+
+ call calc_vert_avg_cf_component &
+ ( gr%nz, k, gr%zt, pdf_params%chi_1, & ! Intent(in)
+ pdf_params%stdev_chi_1, (/(chi_at_liq_sat,i=1,gr%nz)/), & ! Intent(in)
+ cloud_frac_1_refined, rc_1_refined ) ! Intent(out)
+
+ call calc_vert_avg_cf_component &
+ ( gr%nz, k, gr%zt, pdf_params%chi_2, & ! Intent(in)
+ pdf_params%stdev_chi_2, (/(chi_at_liq_sat,i=1,gr%nz)/), & ! Intent(in)
+ cloud_frac_2_refined, rc_2_refined ) ! Intent(out)
+
+ cloud_frac_refined = compute_mean_binormal &
+ ( cloud_frac_1_refined, cloud_frac_2_refined, &
+ pdf_params(k)%mixt_frac )
+
+ rcm_refined = compute_mean_binormal &
+ ( rc_1_refined, rc_2_refined, pdf_params(k)%mixt_frac )
+
+ if ( l_interactive_refined ) then
+ ! I commented out the lines that modify the values in pdf_params, as it seems that
+ ! these values need to remain consistent with the rest of the PDF.
+ ! Eric Raut Jun 2014
+ ! Replace pdf_closure estimates with refined estimates
+ ! pdf_params(k)%rc_1 = rc_1_refined
+ ! pdf_params(k)%rc_2 = rc_2_refined
+ rcm(k) = rcm_refined
+
+ ! pdf_params(k)%cloud_frac_1 = cloud_frac_1_refined
+ ! pdf_params(k)%cloud_frac_2 = cloud_frac_2_refined
+ cloud_frac(k) = cloud_frac_refined
+ end if
+
+ else
+ ! Set these equal to the non-refined values so we have something to
+ ! output to stats!
+ cloud_frac_refined = cloud_frac(k)
+ rcm_refined = rcm(k)
+ end if ! pdf_params(k)%chi_1/pdf_params(k)%stdev_chi_1 > -1._core_rknd
+
+ ! Stats output
+ if ( l_stats_samp ) then
+ call stat_update_var_pt( icloud_frac_refined, k, cloud_frac_refined, stats_zt )
+ call stat_update_var_pt( ircm_refined, k, rcm_refined, stats_zt )
+ end if
+
+ end do ! k=1, gr%nz
+
+ end if ! l_refine_grid_in_cloud
+
+ if( l_rtm_nudge ) then
+ ! Nudge rtm to prevent excessive drying
+ where( rtm < rtm_min .and. gr%zt < rtm_nudge_max_altitude )
+ rtm = rtm + (rtm_ref - rtm) * ( dt / ts_nudge )
+ end where
+ end if
+
+
+ if ( l_call_pdf_closure_twice ) then
+ ! Call pdf_closure a second time on momentum levels, to
+ ! output (rather than interpolate) the variables which
+ ! belong on the momentum levels.
+
+ ! Interpolate sclrm to the momentum level for use in
+ ! the second call to pdf_closure
+ do i = 1, sclr_dim
+ sclrm_zm(:,i) = zt2zm( sclrm(:,i) )
+ ! Clip if extrap. causes sclrm_zm to be less than sclr_tol
+ sclrm_zm(gr%nz,i) = max( sclrm_zm(gr%nz,i), sclr_tol(i) )
+ end do ! i = 1, sclr_dim
+
+ ! Interpolate pressure, p_in_Pa, to momentum levels.
+ ! The pressure at thermodynamic level k = 1 has been set to be the surface
+ ! (or model lower boundary) pressure. Since the surface (or model lower
+ ! boundary) is located at momentum level k = 1, the pressure there is
+ ! p_sfc, which is p_in_Pa(1). Thus, p_in_Pa_zm(1) = p_in_Pa(1).
+ p_in_Pa_zm(:) = zt2zm( p_in_Pa )
+ p_in_Pa_zm(1) = p_in_Pa(1)
+
+ ! Clip pressure if the extrapolation leads to a negative value of pressure
+ p_in_Pa_zm(gr%nz) = max( p_in_Pa_zm(gr%nz), 0.5_core_rknd*p_in_Pa(gr%nz) )
+ ! Set exner at momentum levels, exner_zm, based on p_in_Pa_zm.
+ exner_zm(:) = (p_in_Pa_zm(:)/p0)**kappa
+
+ rtm_zm = zt2zm( rtm )
+ ! Clip if extrapolation at the top level causes rtm_zm to be < rt_tol
+ rtm_zm(gr%nz) = max( rtm_zm(gr%nz), rt_tol )
+ thlm_zm = zt2zm( thlm )
+ ! Clip if extrapolation at the top level causes thlm_zm to be < thl_tol
+ thlm_zm(gr%nz) = max( thlm_zm(gr%nz), thl_tol )
+
+ ! Interpolate hydrometeor mixed moments to momentum levels.
+ do i = 1, hydromet_dim, 1
+ rtphmp(:,i) = zt2zm( rtphmp_zt(:,i) )
+ thlphmp(:,i) = zt2zm( thlphmp_zt(:,i) )
+ wp2hmp_zm(:,i) = zt2zm( wp2hmp(:,i) )
+ enddo ! i = 1, hydromet_dim, 1
+
+ ! Call pdf_closure to output the variables which belong on the momentum grid.
+ do k = 1, gr%nz, 1
+
+ call pdf_closure &
+ ( hydromet_dim, p_in_Pa_zm(k), exner_zm(k), thv_ds_zm(k), wm_zm(k), & ! intent(in)
+ wp2(k), wp3_zm(k), sigma_sqd_w(k), & ! intent(in)
+ Skw_zm(k), rtm_zm(k), rtp2(k), & ! intent(in)
+ wprtp(k), thlm_zm(k), thlp2(k), & ! intent(in)
+ wpthlp(k), rtpthlp(k), sclrm_zm(k,:), & ! intent(in)
+ wpsclrp(k,:), sclrp2(k,:), sclrprtp(k,:), & ! intent(in)
+ sclrpthlp(k,:), k, & ! intent(in)
+#ifdef GFDL
+ RH_crit(k, : , :), do_liquid_only_in_clubb, & ! intent(in)
+#endif
+ wphydrometp(k,:), wp2hmp_zm(k,:), & ! intent(in)
+ rtphmp(k,:), thlphmp(k,:), & ! intent(in)
+ wp4(k), wprtp2_zm(k), wp2rtp_zm(k), & ! intent(out)
+ wpthlp2_zm(k), wp2thlp_zm(k), wprtpthlp_zm(k), & ! intent(out)
+ cloud_frac_zm(k), ice_supersat_frac_zm(k), & ! intent(out)
+ rcm_zm(k), wpthvp(k), wp2thvp_zm(k), rtpthvp(k), & ! intent(out)
+ thlpthvp(k), wprcp(k), wp2rcp_zm(k), rtprcp(k), & ! intent(out)
+ thlprcp(k), rcp2(k), pdf_params_zm(k), & ! intent(out)
+ err_code_pdf_closure, & ! intent(out)
+ wpsclrprtp_zm(k,:), wpsclrp2_zm(k,:), sclrpthvp(k,:), & ! intent(out)
+ wpsclrpthlp_zm(k,:), sclrprcp(k,:), wp2sclrp_zm(k,:), & ! intent(out)
+ rc_coef(k) ) ! intent(out)
+
+ ! Subroutine may produce NaN values, and if so, exit
+ ! gracefully.
+ ! Joshua Fasching March 2008
+
+
+ if ( fatal_error( err_code_pdf_closure ) ) then
+
+ if ( clubb_at_least_debug_level( 1 ) ) then
+ write(fstderr,*) "At grid level = ",k
+ end if
+
+ err_code = err_code_pdf_closure
+ end if
+
+ end do ! k = 1, gr%nz, 1
+
+ else ! l_call_pdf_closure_twice is false
+
+ ! Interpolate momentum variables output from the first call to
+ ! pdf_closure back to momentum grid.
+ ! Since top momentum level is higher than top thermo level,
+ ! Set variables at top momentum level to 0.
+
+ ! Only do this for wp4 and rcp2 if we're saving stats, since they are not
+ ! used elsewhere in the parameterization
+ if ( iwp4 > 0 ) then
+ wp4 = max( zt2zm( wp4_zt ), zero_threshold ) ! Pos. def. quantity
+ wp4(gr%nz) = 0.0_core_rknd
+ end if
+
+#ifndef CLUBB_CAM
+ ! CAM-CLUBB needs cloud water variance thus always compute this
+ if ( ircp2 > 0 ) then
+#endif
+ rcp2 = max( zt2zm( rcp2_zt ), zero_threshold ) ! Pos. def. quantity
+#ifndef CLUBB_CAM
+ rcp2(gr%nz) = 0.0_core_rknd
+ end if
+#endif
+
+ wpthvp = zt2zm( wpthvp_zt )
+ wpthvp(gr%nz) = 0.0_core_rknd
+ thlpthvp = zt2zm( thlpthvp_zt )
+ thlpthvp(gr%nz) = 0.0_core_rknd
+ rtpthvp = zt2zm( rtpthvp_zt )
+ rtpthvp(gr%nz) = 0.0_core_rknd
+ wprcp = zt2zm( wprcp_zt )
+ wprcp(gr%nz) = 0.0_core_rknd
+ rc_coef = zt2zm( rc_coef_zt )
+ rc_coef(gr%nz) = 0.0_core_rknd
+ rtprcp = zt2zm( rtprcp_zt )
+ rtprcp(gr%nz) = 0.0_core_rknd
+ thlprcp = zt2zm( thlprcp_zt )
+ thlprcp(gr%nz) = 0.0_core_rknd
+
+ ! Interpolate passive scalars back onto the m grid
+ do i = 1, sclr_dim
+ sclrpthvp(:,i) = zt2zm( sclrpthvp_zt(:,i) )
+ sclrpthvp(gr%nz,i) = 0.0_core_rknd
+ sclrprcp(:,i) = zt2zm( sclrprcp_zt(:,i) )
+ sclrprcp(gr%nz,i) = 0.0_core_rknd
+ end do ! i=1, sclr_dim
+
+ end if ! l_call_pdf_closure_twice
+
+ ! If l_trapezoidal_rule_zt is true, call trapezoidal_rule_zt for
+ ! thermodynamic-level variables output from pdf_closure.
+ ! ldgrant June 2009
+ if ( l_trapezoidal_rule_zt ) then
+ call trapezoidal_rule_zt &
+ ( l_call_pdf_closure_twice, & ! intent(in)
+ wprtp2, wpthlp2, & ! intent(inout)
+ wprtpthlp, cloud_frac, ice_supersat_frac, & ! intent(inout)
+ rcm, wp2thvp, wpsclrprtp, wpsclrp2, & ! intent(inout)
+ wpsclrpthlp, pdf_params, & ! intent(inout)
+ wprtp2_zm, wpthlp2_zm, & ! intent(inout)
+ wprtpthlp_zm, cloud_frac_zm, & ! intent(inout)
+ ice_supersat_frac_zm, rcm_zm, wp2thvp_zm, & ! intent(inout)
+ wpsclrprtp_zm, wpsclrp2_zm, wpsclrpthlp_zm, & ! intent(inout)
+ pdf_params_zm ) ! intent(inout)
+ end if ! l_trapezoidal_rule_zt
+
+ ! If l_trapezoidal_rule_zm is true, call trapezoidal_rule_zm for
+ ! the important momentum-level variabes output from pdf_closure.
+ ! ldgrant Feb. 2010
+ if ( l_trapezoidal_rule_zm ) then
+ call trapezoidal_rule_zm &
+ ( wpthvp_zt, thlpthvp_zt, rtpthvp_zt, & ! intent(in)
+ wpthvp, thlpthvp, rtpthvp ) ! intent(inout)
+ end if ! l_trapezoidal_rule_zm
+
+ ! Vince Larson clipped rcm in order to prevent rvm < 0. 5 Apr 2008.
+ ! This code won't work unless rtm >= 0 !!!
+ ! We do not clip rcm_in_layer because rcm_in_layer only influences
+ ! radiation, and we do not want to bother recomputing it.
+ ! Code is duplicated from below to ensure that relative humidity
+ ! is calculated properly. 3 Sep 2009
+ call clip_rcm( rtm, 'rtm < rcm after pdf_closure', & ! intent (in)
+ rcm ) ! intent (inout)
+
+ ! Compute variables cloud_cover and rcm_in_layer.
+ ! Added July 2009
+ call compute_cloud_cover &
+ ( pdf_params, cloud_frac, rcm, & ! intent(in)
+ cloud_cover, rcm_in_layer ) ! intent(out)
+
+ ! Use cloud_cover and rcm_in_layer to help boost cloud_frac and rcm to help
+ ! increase cloudiness at coarser grid resolutions.
+ if ( l_use_cloud_cover ) then
+ cloud_frac = cloud_cover
+ rcm = rcm_in_layer
+ end if
+
+ ! Clip cloud fraction here if it still exceeds 1.0 due to round off
+ cloud_frac = min( 1.0_core_rknd, cloud_frac )
+ ! Ditto with ice cloud fraction
+ ice_supersat_frac = min( 1.0_core_rknd, ice_supersat_frac )
+
+ if (l_use_ice_latent) then
+ !A third call to pdf_closure, with terms modified to include the effects
+ !of latent heating due to ice. Thlm and rtm add the effects of ice, and
+ !the terms are all renamed with "_frz" appended. The modified terms will
+ !be fed into the calculations of the turbulence terms. storer-3/14/13
+
+ !Also added rain for completeness. storer-3/4/14
+
+ if ( iirrm > 0 ) then
+ rrm = hydromet(:,iirrm)
+ else
+ rrm = zero
+ end if
+
+ thlm_frz = thlm - (Lv / (Cp*exner) ) * rrm - (Ls / (Cp*exner) ) * rfrzm
+ rtm_frz = rtm + rrm + rfrzm
+
+
+ do k = 1, gr%nz, 1
+
+ call pdf_closure &
+ ( hydromet_dim, p_in_Pa(k), exner(k), thv_ds_zt(k), wm_zt(k), & ! intent(in)
+ wp2_zt(k), wp3(k), sigma_sqd_w_zt(k), & ! intent(in)
+ Skw_zt(k), rtm_frz(k), rtp2_zt(k), & ! intent(in)
+ zm2zt( wprtp, k ), thlm_frz(k), thlp2_zt(k), & ! intent(in)
+ zm2zt( wpthlp, k ), rtpthlp_zt(k), sclrm(k,:), & ! intent(in)
+ wpsclrp_zt(k,:), sclrp2_zt(k,:), sclrprtp_zt(k,:), & ! intent(in)
+ sclrpthlp_zt(k,:), k, & ! intent(in)
+#ifdef GFDL
+ RH_crit(k, : , :), do_liquid_only_in_clubb, & ! intent(in)
+#endif
+ wphydrometp_zt(k,:), wp2hmp(k,:), & ! intent(in)
+ rtphmp_zt(k,:), thlphmp_zt(k,:), & ! intent(in)
+ wp4_zt_frz(k), wprtp2_frz(k), wp2rtp_frz(k), & ! intent(out)
+ wpthlp2_frz(k), wp2thlp_frz(k), wprtpthlp_frz(k), & ! intent(out)
+ cloud_frac_frz(k), ice_supersat_frac_frz(k), & ! intent(out)
+ rcm_frz(k), wpthvp_zt_frz(k), wp2thvp_frz(k), rtpthvp_zt_frz(k), & ! intent(out)
+ thlpthvp_zt_frz(k), wprcp_zt_frz(k), wp2rcp_frz(k), rtprcp_zt_frz(k), & ! intent(out)
+ thlprcp_zt_frz(k), rcp2_zt_frz(k), pdf_params_frz(k), & ! intent(out)
+ err_code_pdf_closure, & ! intent(out)
+ wpsclrprtp_frz(k,:), wpsclrp2_frz(k,:), sclrpthvp_zt_frz(k,:), & ! intent(out)
+ wpsclrpthlp_frz(k,:), sclrprcp_zt_frz(k,:), wp2sclrp_frz(k,:), & ! intent(out)
+ rc_coef_zt_frz(k) ) ! intent(out)
+
+ ! Subroutine may produce NaN values, and if so, exit gracefully.
+ ! Joshua Fasching March 2008
+
+ if ( fatal_error( err_code_pdf_closure ) ) then
+
+ if ( clubb_at_least_debug_level ( 1 ) )then
+ write(fstderr,*) "At grid level = ", k
+ end if
+
+ err_code = err_code_pdf_closure
+ end if
+
+ end do !k=1, gr%nz, 1
+
+
+ if( l_rtm_nudge ) then
+ ! Nudge rtm to prevent excessive drying
+ where( rtm < rtm_min .and. gr%zt < rtm_nudge_max_altitude )
+ rtm = rtm + (rtm_ref - rtm) * ( dt / ts_nudge )
+ end where
+ end if
+
+ rtm_zm_frz = zt2zm( rtm_frz )
+ ! Clip if extrapolation at the top level causes rtm_zm to be < rt_tol
+ rtm_zm_frz(gr%nz) = max( rtm_zm_frz(gr%nz), rt_tol )
+ thlm_zm_frz = zt2zm( thlm_frz )
+ ! Clip if extrapolation at the top level causes thlm_zm to be < thl_tol
+ thlm_zm_frz(gr%nz) = max( thlm_zm_frz(gr%nz), thl_tol )
+
+ if ( l_call_pdf_closure_twice ) then
+ ! Call pdf_closure again to output the variables which belong on the momentum grid.
+ do k=1, gr%nz, 1
+ call pdf_closure &
+ ( hydromet_dim, p_in_Pa_zm(k), exner_zm(k), thv_ds_zm(k), wm_zm(k), & ! intent(in)
+ wp2(k), wp3_zm(k), sigma_sqd_w(k), & ! intent(in)
+ Skw_zm(k), rtm_zm_frz(k), rtp2(k), & ! intent(in)
+ wprtp(k), thlm_zm_frz(k), thlp2(k), & ! intent(in)
+ wpthlp(k), rtpthlp(k), sclrm_zm(k,:), & ! intent(in)
+ wpsclrp(k,:), sclrp2(k,:), sclrprtp(k,:), & ! intent(in)
+ sclrpthlp(k,:), k, & ! intent(in)
+#ifdef GFDL
+ RH_crit(k, : , :), do_liquid_only_in_clubb, & ! intent(in)
+#endif
+ wphydrometp(k,:), wp2hmp_zm(k,:), & ! intent(in)
+ rtphmp(k,:), thlphmp(k,:), & ! intent(in)
+ wp4_frz(k), wprtp2_zm_frz(k), wp2rtp_zm_frz(k), & ! intent(out)
+ wpthlp2_zm_frz(k), wp2thlp_zm_frz(k), wprtpthlp_zm_frz(k), & ! intent(out)
+ cloud_frac_zm_frz(k), ice_supersat_frac_zm_frz(k), & ! intent(out)
+ rcm_zm_frz(k), wpthvp_frz(k), wp2thvp_zm_frz(k), rtpthvp_frz(k), & ! intent(out)
+ thlpthvp_frz(k), wprcp_frz(k), wp2rcp_zm_frz(k), rtprcp_frz(k), & ! intent(out)
+ thlprcp_frz(k), rcp2_frz(k), pdf_params_zm_frz(k), & ! intent(out)
+ err_code_pdf_closure, & ! intent(out)
+ wpsclrprtp_zm_frz(k,:), wpsclrp2_zm_frz(k,:), sclrpthvp_frz(k,:), & ! intent(out)
+ wpsclrpthlp_zm_frz(k,:), sclrprcp_frz(k,:), wp2sclrp_zm_frz(k,:), & ! intent(out)
+ rc_coef_frz(k) ) ! intent(out)
+
+ ! Subroutine may produce NaN values, and if so, exit
+ ! gracefully.
+ ! Joshua Fasching March 2008
+
+
+ if ( fatal_error( err_code_pdf_closure ) ) then
+
+ if ( clubb_at_least_debug_level( 1 ) ) then
+ write(fstderr,*) "At grid level = ",k
+ end if
+
+ err_code = err_code_pdf_closure
+ end if
+
+ end do ! k = 1, gr%nz, 1
+ else ! l_call_pdf_closure_twice is false
+
+ wpthvp_frz = zt2zm( wpthvp_zt_frz )
+ wpthvp_frz(gr%nz) = 0.0_core_rknd
+ thlpthvp_frz = zt2zm( thlpthvp_zt_frz )
+ thlpthvp_frz(gr%nz) = 0.0_core_rknd
+ rtpthvp_frz = zt2zm( rtpthvp_zt_frz )
+ rtpthvp_frz(gr%nz) = 0.0_core_rknd
+
+ end if ! l_call_pdf_closure_twice
+
+ if ( l_trapezoidal_rule_zt ) then
+ call trapezoidal_rule_zt &
+ ( l_call_pdf_closure_twice, & ! intent(in)
+ wprtp2_frz, wpthlp2_frz, & ! intent(inout)
+ wprtpthlp_frz, cloud_frac_frz, ice_supersat_frac_frz, & ! intent(inout)
+ rcm_frz, wp2thvp_frz, wpsclrprtp_frz, wpsclrp2_frz, & ! intent(inout)
+ wpsclrpthlp_frz, pdf_params_frz, & ! intent(inout)
+ wprtp2_zm_frz, wpthlp2_zm_frz, & ! intent(inout)
+ wprtpthlp_zm_frz, cloud_frac_zm_frz, & ! intent(inout)
+ ice_supersat_frac_zm_frz, rcm_zm_frz, wp2thvp_zm_frz, & ! intent(inout)
+ wpsclrprtp_zm_frz, wpsclrp2_zm_frz, wpsclrpthlp_zm_frz, & ! intent(inout)
+ pdf_params_zm_frz ) ! intent(inout)
+ end if ! l_trapezoidal_rule_zt
+
+ ! If l_trapezoidal_rule_zm is true, call trapezoidal_rule_zm for
+ ! the important momentum-level variabes output from pdf_closure.
+ ! ldgrant Feb. 2010
+ if ( l_trapezoidal_rule_zm ) then
+ call trapezoidal_rule_zm &
+ ( wpthvp_zt_frz, thlpthvp_zt_frz, rtpthvp_zt_frz, & ! intent(in)
+ wpthvp_frz, thlpthvp_frz, rtpthvp_frz ) ! intent(inout)
+ end if ! l_trapezoidal_rule_zm
+
+ wpthvp = wpthvp_frz
+ wp2thvp = wp2thvp_frz
+ thlpthvp = thlpthvp_frz
+ rtpthvp = rtpthvp_frz
+
+ end if ! l_use_ice_latent = .true.
+
+
+
+
+
+ !----------------------------------------------------------------
+ ! Compute thvm
+ !----------------------------------------------------------------
+
+ thvm = thlm + ep1 * thv_ds_zt * rtm &
+ + ( Lv/(Cp*exner) - ep2 * thv_ds_zt ) * rcm
+
+ !----------------------------------------------------------------
+ ! Compute tke (turbulent kinetic energy)
+ !----------------------------------------------------------------
+
+ if ( .not. l_tke_aniso ) then
+ ! tke is assumed to be 3/2 of wp2
+ em = three_halves * wp2 ! Known magic number
+ else
+ em = 0.5_core_rknd * ( wp2 + vp2 + up2 )
+ end if
+
+ !----------------------------------------------------------------
+ ! Compute mixing length
+ !----------------------------------------------------------------
+
+ if ( l_avg_Lscale .and. .not. l_Lscale_plume_centered ) then
+ ! Call compute length two additional times with perturbed values
+ ! of rtm and thlm so that an average value of Lscale may be calculated.
+ if ( l_use_ice_latent ) then
+ !Include the effects of ice in the length scale calculation
+
+ thlm_pert_1 = thlm_frz + Lscale_pert_coef * sqrt( max( thlp2, thl_tol**2 ) )
+ rtm_pert_1 = rtm_frz + Lscale_pert_coef * sqrt( max( rtp2, rt_tol**2 ) )
+ mu_pert_1 = newmu / Lscale_mu_coef
+
+ thlm_pert_2 = thlm_frz - Lscale_pert_coef * sqrt( max( thlp2, thl_tol**2 ) )
+ rtm_pert_2 = rtm_frz - Lscale_pert_coef * sqrt( max( rtp2, rt_tol**2 ) )
+ mu_pert_2 = newmu * Lscale_mu_coef
+ else
+ thlm_pert_1 = thlm + Lscale_pert_coef * sqrt( max( thlp2, thl_tol**2 ) )
+ rtm_pert_1 = rtm + Lscale_pert_coef * sqrt( max( rtp2, rt_tol**2 ) )
+ mu_pert_1 = newmu / Lscale_mu_coef
+
+ thlm_pert_2 = thlm - Lscale_pert_coef * sqrt( max( thlp2, thl_tol**2 ) )
+ rtm_pert_2 = rtm - Lscale_pert_coef * sqrt( max( rtp2, rt_tol**2 ) )
+ mu_pert_2 = newmu * Lscale_mu_coef
+ end if
+
+ call compute_length( thvm, thlm_pert_1, rtm_pert_1, em, Lscale_max, & ! intent(in)
+ p_in_Pa, exner, thv_ds_zt, mu_pert_1, l_implemented, & ! intent(in)
+ err_code, & ! intent(inout)
+ Lscale_pert_1, Lscale_up, Lscale_down ) ! intent(out)
+
+ call compute_length( thvm, thlm_pert_2, rtm_pert_2, em, Lscale_max, & ! intent(in)
+ p_in_Pa, exner, thv_ds_zt, mu_pert_2, l_implemented, & ! intent(in)
+ err_code, & ! intent(inout)
+ Lscale_pert_2, Lscale_up, Lscale_down ) ! intent(out)
+
+ else if ( l_avg_Lscale .and. l_Lscale_plume_centered ) then
+ ! Take the values of thl and rt based one 1st or 2nd plume
+
+ do k = 1, gr%nz, 1
+ sign_rtpthlp(k) = sign(1.0_core_rknd, rtpthlp(k))
+ end do
+
+ if ( l_use_ice_latent ) then
+ where ( pdf_params_frz%rt_1 > pdf_params_frz%rt_2 )
+ rtm_pert_pos_rt = pdf_params_frz%rt_1 &
+ + Lscale_pert_coef * sqrt( max( pdf_params_frz%varnce_rt_1, rt_tol**2 ) )
+ thlm_pert_pos_rt = pdf_params_frz%thl_1 + ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params_frz%varnce_thl_1, thl_tol**2 ) ) )
+ thlm_pert_neg_rt = pdf_params_frz%thl_2 - ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params_frz%varnce_thl_2, thl_tol**2 ) ) )
+ rtm_pert_neg_rt = pdf_params_frz%rt_2 &
+ - Lscale_pert_coef * sqrt( max( pdf_params_frz%varnce_rt_2, rt_tol**2 ) )
+ !Lscale_weight = pdf_params%mixt_frac
+ else where
+ rtm_pert_pos_rt = pdf_params_frz%rt_2 &
+ + Lscale_pert_coef * sqrt( max( pdf_params_frz%varnce_rt_2, rt_tol**2 ) )
+ thlm_pert_pos_rt = pdf_params_frz%thl_2 + ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params_frz%varnce_thl_2, thl_tol**2 ) ) )
+ thlm_pert_neg_rt = pdf_params_frz%thl_1 - ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params_frz%varnce_thl_1, thl_tol**2 ) ) )
+ rtm_pert_neg_rt = pdf_params_frz%rt_1 &
+ - Lscale_pert_coef * sqrt( max( pdf_params_frz%varnce_rt_1, rt_tol**2 ) )
+ !Lscale_weight = 1.0_core_rknd - pdf_params%mixt_frac
+ end where
+ else
+ where ( pdf_params%rt_1 > pdf_params%rt_2 )
+ rtm_pert_pos_rt = pdf_params%rt_1 &
+ + Lscale_pert_coef * sqrt( max( pdf_params%varnce_rt_1, rt_tol**2 ) )
+ thlm_pert_pos_rt = pdf_params%thl_1 + ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params%varnce_thl_1, thl_tol**2 ) ) )
+ thlm_pert_neg_rt = pdf_params%thl_2 - ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params%varnce_thl_2, thl_tol**2 ) ) )
+ rtm_pert_neg_rt = pdf_params%rt_2 &
+ - Lscale_pert_coef * sqrt( max( pdf_params%varnce_rt_2, rt_tol**2 ) )
+ !Lscale_weight = pdf_params%mixt_frac
+ else where
+ rtm_pert_pos_rt = pdf_params%rt_2 &
+ + Lscale_pert_coef * sqrt( max( pdf_params%varnce_rt_2, rt_tol**2 ) )
+ thlm_pert_pos_rt = pdf_params%thl_2 + ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params%varnce_thl_2, thl_tol**2 ) ) )
+ thlm_pert_neg_rt = pdf_params%thl_1 - ( sign_rtpthlp * Lscale_pert_coef &
+ * sqrt( max( pdf_params%varnce_thl_1, thl_tol**2 ) ) )
+ rtm_pert_neg_rt = pdf_params%rt_1 &
+ - Lscale_pert_coef * sqrt( max( pdf_params%varnce_rt_1, rt_tol**2 ) )
+ !Lscale_weight = 1.0_core_rknd - pdf_params%mixt_frac
+ end where
+ end if
+ mu_pert_pos_rt = newmu / Lscale_mu_coef
+ mu_pert_neg_rt = newmu * Lscale_mu_coef
+
+ ! Call length with perturbed values of thl and rt
+ call compute_length( thvm, thlm_pert_pos_rt, rtm_pert_pos_rt, em, Lscale_max, &!intent(in)
+ p_in_Pa, exner, thv_ds_zt, mu_pert_pos_rt, l_implemented, & !intent(in)
+ err_code, & ! intent(inout)
+ Lscale_pert_1, Lscale_up, Lscale_down ) ! intent(out)
+
+ call compute_length( thvm, thlm_pert_neg_rt, rtm_pert_neg_rt, em, Lscale_max, &!intent(in)
+ p_in_Pa, exner, thv_ds_zt, mu_pert_neg_rt, l_implemented, & !intent(in)
+ err_code, & ! intent(inout)
+ Lscale_pert_2, Lscale_up, Lscale_down ) ! intent(out)
+ else
+ Lscale_pert_1 = unused_var ! Undefined
+ Lscale_pert_2 = unused_var ! Undefined
+
+ end if ! l_avg_Lscale
+
+ if ( l_stats_samp ) then
+ call stat_update_var( iLscale_pert_1, Lscale_pert_1, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_update_var( iLscale_pert_2, Lscale_pert_2, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ end if ! l_stats_samp
+
+ ! ********** NOTE: **********
+ ! This call to compute_length must be last. Otherwise, the values of
+ ! Lscale_up and Lscale_down in stats will be based on perturbation length scales
+ ! rather than the mean length scale.
+ call compute_length( thvm, thlm, rtm, em, Lscale_max, & ! intent(in)
+ p_in_Pa, exner, thv_ds_zt, newmu, l_implemented, & ! intent(in)
+ err_code, & ! intent(inout)
+ Lscale, Lscale_up, Lscale_down ) ! intent(out)
+
+ if ( l_avg_Lscale ) then
+ if ( l_Lscale_plume_centered ) then
+ ! Weighted average of mean, pert_1, & pert_2
+! Lscale = 0.5_core_rknd * ( Lscale + Lscale_weight*Lscale_pert_1 &
+! + (1.0_core_rknd-Lscale_weight)*Lscale_pert_2 )
+
+ ! Weighted average of just the perturbed values
+! Lscale = Lscale_weight*Lscale_pert_1 + (1.0_core_rknd-Lscale_weight)*Lscale_pert_2
+
+ ! Un-weighted average of just the perturbed values
+ Lscale = 0.5_core_rknd*( Lscale_pert_1 + Lscale_pert_2 )
+ else
+ Lscale = (1.0_core_rknd/3.0_core_rknd) * ( Lscale + Lscale_pert_1 + Lscale_pert_2 )
+ end if
+ end if
+
+ !----------------------------------------------------------------
+ ! Dissipation time
+ !----------------------------------------------------------------
+! Vince Larson replaced the cutoff of em_min by w_tol**2. 7 Jul 2007
+! This is to prevent tau from being too large (producing little damping)
+! in stably stratified layers with little turbulence.
+! sqrt_em_zt = SQRT( MAX( em_min, zm2zt( em ) ) )
+! tau_zt = MIN( Lscale / sqrt_em_zt, taumax )
+! tau_zm &
+! = MIN( ( zt2zm( Lscale ) / SQRT( MAX( em_min, em ) ) ), taumax )
+! Addition by Brian: Model constant em_min is now set to (3/2)*w_tol_sqd.
+! Thus, em_min can replace w_tol_sqd here.
+ sqrt_em_zt = SQRT( MAX( em_min, zm2zt( em ) ) )
+
+ tau_zt = MIN( Lscale / sqrt_em_zt, taumax )
+ tau_zm = MIN( ( MAX( zt2zm( Lscale ), zero_threshold ) &
+ / SQRT( MAX( em_min, em ) ) ), taumax )
+! End Vince Larson's replacement.
+
+ ! Determine the static stability corrected version of tau_zm
+ ! Create a damping time scale that is more strongly damped at the
+ ! altitudes where the Brunt-Vaisala frequency (N^2) is large.
+ tau_N2_zm = tau_zm / calc_stability_correction( thlm, Lscale, em )
+
+ ! Modification to damp noise in stable region
+! Vince Larson commented out because it may prevent turbulence from
+! initiating in unstable regions. 7 Jul 2007
+! do k = 1, gr%nz
+! if ( wp2(k) <= 0.005_core_rknd ) then
+! tau_zt(k) = taumin
+! tau_zm(k) = taumin
+! end if
+! end do
+! End Vince Larson's commenting.
+
+ !----------------------------------------------------------------
+ ! Eddy diffusivity coefficient
+ !----------------------------------------------------------------
+ ! c_K is 0.548 usually (Duynkerke and Driedonks 1987)
+ ! CLUBB uses a smaller value to better fit empirical data.
+
+ Kh_zt = c_K * Lscale * sqrt_em_zt
+ Kh_zm = c_K * max( zt2zm( Lscale ), zero_threshold ) &
+ * sqrt( max( em, em_min ) )
+
+#if defined(CLUBB_CAM) || defined(GFDL)
+ khzt(:) = Kh_zt(:)
+ khzm(:) = Kh_zm(:)
+ thlprcp_out(:) = thlprcp(:)
+#endif
+
+#ifdef CLUBB_CAM
+ qclvar(:) = rcp2_zt(:)
+#endif
+
+ !----------------------------------------------------------------
+ ! Set Surface variances
+ !----------------------------------------------------------------
+
+ ! Surface variances should be set here, before the call to either
+ ! advance_xp2_xpyp or advance_wp2_wp3.
+ ! Surface effects should not be included with any case where the lowest
+ ! level is not the ground level. Brian Griffin. December 22, 2005.
+ if ( gr%zm(1) == sfc_elevation ) then
+
+ ! Reflect surface varnce changes in budget
+ if ( l_stats_samp ) then
+ call stat_begin_update_pt( ithlp2_sf, 1, & ! intent(in)
+ thlp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update_pt( irtp2_sf, 1, & ! intent(in)
+ rtp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update_pt( irtpthlp_sf, 1, & ! intent(in)
+ rtpthlp(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update_pt( iup2_sf, 1, & ! intent(in)
+ up2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update_pt( ivp2_sf, 1, & ! intent(in)
+ vp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_begin_update_pt( iwp2_sf, 1, & ! intent(in)
+ wp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ end if
+
+ call surface_varnce( upwp_sfc, vpwp_sfc, wpthlp_sfc, wprtp_sfc, & ! intent(in)
+ um(2), vm(2), Lscale_up(2), wpsclrp_sfc, & ! intent(in)
+ wp2(1), up2(1), vp2(1), & ! intent(out)
+ thlp2(1), rtp2(1), rtpthlp(1), err_code_surface,& ! intent(out)
+ sclrp2(1,1:sclr_dim), & ! intent(out)
+ sclrprtp(1,1:sclr_dim), & ! intent(out)
+ sclrpthlp(1,1:sclr_dim) ) ! intent(out)
+
+ if ( fatal_error( err_code_surface ) ) then
+ call report_error( err_code_surface ) ! intent(in)
+ err_code = err_code_surface
+ end if
+
+ ! Update surface stats
+ if ( l_stats_samp ) then
+ call stat_end_update_pt( ithlp2_sf, 1, & ! intent(in)
+ thlp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update_pt( irtp2_sf, 1, & ! intent(in)
+ rtp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update_pt( irtpthlp_sf, 1, & ! intent(in)
+ rtpthlp(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update_pt( iup2_sf, 1, & ! intent(in)
+ up2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update_pt( ivp2_sf, 1, & ! intent(in)
+ vp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update_pt( iwp2_sf, 1, & ! intent(in)
+ wp2(1) / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ end if
+
+ else
+
+ ! Variances for cases where the lowest level is not at the surface.
+ ! Eliminate surface effects on lowest level variances.
+ wp2(1) = w_tol_sqd
+ up2(1) = w_tol_sqd
+ vp2(1) = w_tol_sqd
+ thlp2(1) = thl_tol**2
+ rtp2(1) = rt_tol**2
+ rtpthlp(1) = 0.0_core_rknd
+
+ do i = 1, sclr_dim, 1
+ sclrp2(1,i) = 0.0_core_rknd
+ sclrprtp(1,i) = 0.0_core_rknd
+ sclrpthlp(1,i) = 0.0_core_rknd
+ end do
+
+ end if ! gr%zm(1) == sfc_elevation
+
+
+ !#######################################################################
+ !############## ADVANCE PROGNOSTIC VARIABLES ONE TIMESTEP ##############
+ !#######################################################################
+
+ ! Store the saturation mixing ratio for output purposes. Brian
+ ! Compute rsat if either rsat or rel_humidity is to be saved. ldgrant
+ if ( ( irsat > 0 ) .or. ( irel_humidity > 0 ) ) then
+ rsat = sat_mixrat_liq( p_in_Pa, thlm2T_in_K( thlm, exner, rcm ) )
+ end if
+
+
+ if ( l_stats_samp ) then
+ call stat_update_var( irvm, rtm - rcm, & !intent(in)
+ stats_zt ) !intent(inout)
+
+ ! Output relative humidity (q/q∗ where q∗ is the saturation mixing ratio over liquid)
+ ! Added an extra check for irel_humidity > 0; otherwise, if both irsat = 0 and
+ ! irel_humidity = 0, rsat is not computed, leading to a floating-point exception
+ ! when stat_update_var is called for rel_humidity. ldgrant
+ if ( irel_humidity > 0 ) then
+ call stat_update_var( irel_humidity, (rtm - rcm) / rsat, & !intent(in)
+ stats_zt) !intent(inout)
+ end if ! irel_humidity > 0
+ end if ! l_stats_samp
+
+ !----------------------------------------------------------------
+ ! Advance rtm/wprtp and thlm/wpthlp one time step
+ !----------------------------------------------------------------
+ if ( l_call_pdf_closure_twice ) then
+ w_1_zm = pdf_params_zm%w_1
+ w_2_zm = pdf_params_zm%w_2
+ varnce_w_1_zm = pdf_params_zm%varnce_w_1
+ varnce_w_2_zm = pdf_params_zm%varnce_w_2
+ mixt_frac_zm = pdf_params_zm%mixt_frac
+ else
+ w_1_zm = zt2zm( pdf_params%w_1 )
+ w_2_zm = zt2zm( pdf_params%w_2 )
+ varnce_w_1_zm = zt2zm( pdf_params%varnce_w_1 )
+ varnce_w_2_zm = zt2zm( pdf_params%varnce_w_2 )
+ mixt_frac_zm = zt2zm( pdf_params%mixt_frac )
+ end if
+
+ ! Determine stability correction factor
+ stability_correction = calc_stability_correction( thlm, Lscale, em ) ! In
+ if ( l_stats_samp ) then
+ call stat_update_var( istability_correction, stability_correction, & ! In
+ stats_zm ) ! In/Out
+ end if
+
+ ! Here we determine if we're using tau_zm or tau_N2_zm, which is tau
+ ! that has been stability corrected for stably stratified regions.
+ ! -dschanen 7 Nov 2014
+ if ( l_stability_correct_tau_zm ) then
+ tau_N2_zm = tau_zm / stability_correction
+ tau_C6_zm = tau_N2_zm
+ tau_C1_zm = tau_N2_zm
+
+ else
+ tau_N2_zm = unused_var
+ tau_C6_zm = tau_zm
+ tau_C1_zm = tau_zm
+
+ end if ! l_stability_correction
+
+ call advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, & ! intent(in)
+ Lscale, wp3_on_wp2, wp3_on_wp2_zt, Kh_zt, Kh_zm, & ! intent(in)
+ tau_C6_zm, Skw_zm, rtpthvp, rtm_forcing, & ! intent(in)
+ wprtp_forcing, rtm_ref, thlpthvp, & ! intent(in)
+ thlm_forcing, wpthlp_forcing, thlm_ref, & ! intent(in)
+ rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! intent(in)
+ invrs_rho_ds_zt, thv_ds_zm, rtp2, thlp2, & ! intent(in)
+ w_1_zm, w_2_zm, varnce_w_1_zm, varnce_w_2_zm, & ! intent(in)
+ mixt_frac_zm, l_implemented, em, & ! intent(in)
+ sclrpthvp, sclrm_forcing, sclrp2, & ! intent(in)
+ rtm, wprtp, thlm, wpthlp, & ! intent(inout)
+ err_code, & ! intent(inout)
+ sclrm, wpsclrp ) ! intent(inout)
+
+ ! Vince Larson clipped rcm in order to prevent rvm < 0. 5 Apr 2008.
+ ! This code won't work unless rtm >= 0 !!!
+ ! We do not clip rcm_in_layer because rcm_in_layer only influences
+ ! radiation, and we do not want to bother recomputing it. 6 Aug 2009
+ call clip_rcm( rtm, 'rtm < rcm in advance_xm_wpxp', & ! intent(in)
+ rcm ) ! intent(inout)
+
+#ifdef GFDL
+ call advance_sclrm_Nd_diffusion_OG( dt, & ! h1g, 2012-06-16 ! intent(in)
+ sclrm, sclrm_trsport_only, & ! intent(inout)
+ Kh_zm, cloud_frac, & ! intent(in)
+ err_code ) ! intent(out)
+#endif
+
+ !----------------------------------------------------------------
+ ! Compute some of the variances and covariances. These include the variance of
+ ! total water (rtp2), liquid potential termperature (thlp2), their
+ ! covariance (rtpthlp), and the variance of horizontal wind (up2 and vp2).
+ ! The variance of vertical velocity is computed later.
+ !----------------------------------------------------------------
+
+ ! We found that certain cases require a time tendency to run
+ ! at shorter timesteps so these are prognosed now.
+
+ ! We found that if we call advance_xp2_xpyp first, we can use a longer timestep.
+ call advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, thlm, & ! intent(in)
+ wpthlp, wpthvp, um, vm, wp2, wp2_zt, & ! intent(in)
+ wp3, upwp, vpwp, sigma_sqd_w, Skw_zm, & ! intent(in)
+ Kh_zt, rtp2_forcing, thlp2_forcing, & ! intent(in)
+ rtpthlp_forcing, rho_ds_zm, rho_ds_zt, & ! intent(in)
+ invrs_rho_ds_zm, thv_ds_zm, & ! intent(in)
+ Lscale, wp3_on_wp2, wp3_on_wp2_zt, & ! intent(in)
+ l_iter_xp2_xpyp, dt, & ! intent(in)
+ sclrm, wpsclrp, & ! intent(in)
+ rtp2, thlp2, rtpthlp, up2, vp2, & ! intent(inout)
+ err_code, & ! intent(inout)
+ sclrp2, sclrprtp, sclrpthlp ) ! intent(inout)
+
+ !----------------------------------------------------------------
+ ! Covariance clipping for wprtp, wpthlp, wpsclrp, upwp, and vpwp
+ ! after subroutine advance_xp2_xpyp updated xp2.
+ !----------------------------------------------------------------
+
+ wprtp_cl_num = 2 ! Second instance of w'r_t' clipping.
+ wpthlp_cl_num = 2 ! Second instance of w'th_l' clipping.
+ wpsclrp_cl_num = 2 ! Second instance of w'sclr' clipping.
+ upwp_cl_num = 1 ! First instance of u'w' clipping.
+ vpwp_cl_num = 1 ! First instance of v'w' clipping.
+
+ call clip_covars_denom( dt, rtp2, thlp2, up2, vp2, wp2, & ! intent(in)
+ sclrp2, wprtp_cl_num, wpthlp_cl_num, & ! intent(in)
+ wpsclrp_cl_num, upwp_cl_num, vpwp_cl_num, & ! intent(in)
+ wprtp, wpthlp, upwp, vpwp, wpsclrp ) ! intent(inout)
+
+
+ !----------------------------------------------------------------
+ ! Advance 2nd and 3rd order moment of vertical velocity (wp2 / wp3)
+ ! by one timestep
+ !----------------------------------------------------------------
+
+ call advance_wp2_wp3 &
+ ( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, & ! intent(in)
+ a3_coef, a3_coef_zt, wp3_on_wp2, & ! intent(in)
+ wpthvp, wp2thvp, um, vm, upwp, vpwp, & ! intent(in)
+ up2, vp2, Kh_zm, Kh_zt, tau_zm, tau_zt, tau_C1_zm, & ! intent(in)
+ Skw_zm, Skw_zt, rho_ds_zm, rho_ds_zt, & ! intent(in)
+ invrs_rho_ds_zm, invrs_rho_ds_zt, radf, & ! intent(in)
+ thv_ds_zm, thv_ds_zt, pdf_params%mixt_frac, & ! intent(in)
+ wp2, wp3, wp3_zm, wp2_zt, err_code ) ! intent(inout)
+
+ !----------------------------------------------------------------
+ ! Covariance clipping for wprtp, wpthlp, wpsclrp, upwp, and vpwp
+ ! after subroutine advance_wp2_wp3 updated wp2.
+ !----------------------------------------------------------------
+
+ wprtp_cl_num = 3 ! Third instance of w'r_t' clipping.
+ wpthlp_cl_num = 3 ! Third instance of w'th_l' clipping.
+ wpsclrp_cl_num = 3 ! Third instance of w'sclr' clipping.
+ upwp_cl_num = 2 ! Second instance of u'w' clipping.
+ vpwp_cl_num = 2 ! Second instance of v'w' clipping.
+
+ call clip_covars_denom( dt, rtp2, thlp2, up2, vp2, wp2, & ! intent(in)
+ sclrp2, wprtp_cl_num, wpthlp_cl_num, & ! intent(in)
+ wpsclrp_cl_num, upwp_cl_num, vpwp_cl_num, & ! intent(in)
+ wprtp, wpthlp, upwp, vpwp, wpsclrp ) ! intent(inout)
+
+ !----------------------------------------------------------------
+ ! Advance the horizontal mean of the wind in the x-y directions
+ ! (i.e. um, vm) and the mean of the eddy-diffusivity scalars
+ ! (i.e. edsclrm) by one time step
+ !----------------------------------------------------------------i
+
+ Km_zm = Kh_zm * c_K10
+
+ if (do_expldiff) then
+ edsclrm(:,edsclr_dim-1)=thlm(:)
+ edsclrm(:,edsclr_dim)=rtm(:)
+ endif
+
+ call advance_windm_edsclrm( dt, wm_zt, Km_zm, ug, vg, um_ref, vm_ref, & ! intent(in)
+ wp2, up2, vp2, um_forcing, vm_forcing, & ! intent(in)
+ edsclrm_forcing, & ! intent(in)
+ rho_ds_zm, invrs_rho_ds_zt, & ! intent(in)
+ fcor, l_implemented, & ! intent(in)
+ um, vm, edsclrm, & ! intent(inout)
+ upwp, vpwp, wpedsclrp, & ! intent(inout)
+ err_code ) ! intent(inout)
+
+ call pvertinterp(gr%nz, p_in_Pa, 70000.0_core_rknd, thlm, thlm700)
+ call pvertinterp(gr%nz, p_in_Pa, 100000.0_core_rknd, thlm, thlm1000)
+ if (do_expldiff .and. thlm700 - thlm1000 .lt. 20.0_core_rknd) then
+ thlm(:) = edsclrm(:,edsclr_dim-1)
+ rtm(:) = edsclrm(:,edsclr_dim)
+ endif
+
+ do ixind=1,edsclr_dim
+ call fill_holes_vertical(2,0.0_core_rknd,"zt",rho_ds_zt,rho_ds_zm,edsclrm(:,ixind))
+ enddo
+
+ !#######################################################################
+ !############# ACCUMULATE STATISTICS #############
+ !#######################################################################
+
+ if ( l_stats_samp ) then
+
+ call stat_end_update( iwp2_bt, wp2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update( ivp2_bt, vp2 / dt,& ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update( iup2_bt, up2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update( iwprtp_bt, wprtp / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update( iwpthlp_bt, wpthlp / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update( irtp2_bt, rtp2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update( ithlp2_bt, thlp2 / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+ call stat_end_update( irtpthlp_bt, rtpthlp / dt, & ! intent(in)
+ stats_zm ) ! intent(inout)
+
+ call stat_end_update( irtm_bt, rtm / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_end_update( ithlm_bt, thlm / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_end_update( ium_bt, um / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_end_update( ivm_bt, vm / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+ call stat_end_update( iwp3_bt, wp3 / dt, & ! intent(in)
+ stats_zt ) ! intent(inout)
+
+ end if ! l_stats_samp
+
+
+ if ( iwpthlp_zt > 0 ) then
+ wpthlp_zt = zm2zt( wpthlp )
+ end if
+
+ if ( iwprtp_zt > 0 ) then
+ wprtp_zt = zm2zt( wprtp )
+ end if
+
+ if ( iup2_zt > 0 ) then
+ up2_zt = max( zm2zt( up2 ), w_tol_sqd )
+ end if
+
+ if (ivp2_zt > 0 ) then
+ vp2_zt = max( zm2zt( vp2 ), w_tol_sqd )
+ end if
+
+ if ( iupwp_zt > 0 ) then
+ upwp_zt = zm2zt( upwp )
+ end if
+
+ if ( ivpwp_zt > 0 ) then
+ vpwp_zt = zm2zt( vpwp )
+ end if
+
+ call stats_accumulate &
+ ( um, vm, upwp, vpwp, up2, vp2, & ! intent(in)
+ thlm, rtm, wprtp, wpthlp, & ! intent(in)
+ wp2, wp3, rtp2, thlp2, rtpthlp, & ! intent(in)
+ p_in_Pa, exner, rho, rho_zm, & ! intent(in)
+ rho_ds_zm, rho_ds_zt, thv_ds_zm, & ! intent(in)
+ thv_ds_zt, wm_zt, wm_zm, rcm, wprcp, rc_coef, & ! intent(in)
+ rcm_zm, rtm_zm, thlm_zm, cloud_frac, ice_supersat_frac,& ! intent(in)
+ cloud_frac_zm, ice_supersat_frac_zm, rcm_in_layer, & ! intent(in)
+ cloud_cover, sigma_sqd_w, pdf_params, & ! intent(in)
+ sclrm, sclrp2, sclrprtp, sclrpthlp, sclrm_forcing, & ! intent(in)
+ wpsclrp, edsclrm, edsclrm_forcing ) ! intent(in)
+
+
+ if ( clubb_at_least_debug_level( 2 ) ) then
+ call parameterization_check &
+ ( thlm_forcing, rtm_forcing, um_forcing, vm_forcing, & ! intent(in)
+ wm_zm, wm_zt, p_in_Pa, rho_zm, rho, exner, & ! intent(in)
+ rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! intent(in)
+ invrs_rho_ds_zt, thv_ds_zm, thv_ds_zt, & ! intent(in)
+ wpthlp_sfc, wprtp_sfc, upwp_sfc, vpwp_sfc, & ! intent(in)
+ um, upwp, vm, vpwp, up2, vp2, & ! intent(in)
+ rtm, wprtp, thlm, wpthlp, & ! intent(in)
+ wp2, wp3, rtp2, thlp2, rtpthlp, & ! intent(in)
+ "end of ", & ! intent(in)
+ wpsclrp_sfc, wpedsclrp_sfc, & ! intent(in)
+ sclrm, wpsclrp, sclrp2, sclrprtp, sclrpthlp, & ! intent(in)
+ sclrm_forcing, edsclrm, edsclrm_forcing, & ! intent(in)
+ err_code ) ! intent(inout)
+ end if
+
+ if ( l_stats .and. l_stats_samp ) then
+ ! Spurious source will only be calculated if rtm_ma and thlm_ma are zero.
+ ! Therefore, wm must be zero or l_implemented must be true.
+ if ( l_implemented .or. ( all( wm_zt == 0._core_rknd ) .and. &
+ all( wm_zm == 0._core_rknd ) ) ) then
+ ! Calculate the spurious source for rtm
+ rtm_flux_top = rho_ds_zm(gr%nz) * wprtp(gr%nz)
+
+ if ( .not. l_host_applies_sfc_fluxes ) then
+ rtm_flux_sfc = rho_ds_zm(1) * wprtp_sfc
+ else
+ rtm_flux_sfc = 0.0_core_rknd
+ end if
+
+ rtm_integral_after &
+ = vertical_integral( (gr%nz - 2 + 1), rho_ds_zt(2:gr%nz), &
+ rtm(2:gr%nz), gr%invrs_dzt(2:gr%nz) )
+
+ rtm_integral_forcing &
+ = vertical_integral( (gr%nz - 2 + 1), rho_ds_zt(2:gr%nz), &
+ rtm_forcing(2:gr%nz), gr%invrs_dzt(2:gr%nz) )
+
+ rtm_spur_src &
+ = calculate_spurious_source( rtm_integral_after, &
+ rtm_integral_before, &
+ rtm_flux_top, rtm_flux_sfc, &
+ rtm_integral_forcing, &
+ dt )
+
+ ! Calculate the spurious source for thlm
+ thlm_flux_top = rho_ds_zm(gr%nz) * wpthlp(gr%nz)
+
+ if ( .not. l_host_applies_sfc_fluxes ) then
+ thlm_flux_sfc = rho_ds_zm(1) * wpthlp_sfc
+ else
+ thlm_flux_sfc = 0.0_core_rknd
+ end if
+
+ thlm_integral_after &
+ = vertical_integral( (gr%nz - 2 + 1), rho_ds_zt(2:gr%nz), &
+ thlm(2:gr%nz), gr%invrs_dzt(2:gr%nz) )
+
+ thlm_integral_forcing &
+ = vertical_integral( (gr%nz - 2 + 1), rho_ds_zt(2:gr%nz), &
+ thlm_forcing(2:gr%nz), gr%invrs_dzt(2:gr%nz) )
+
+ thlm_spur_src &
+ = calculate_spurious_source( thlm_integral_after, &
+ thlm_integral_before, &
+ thlm_flux_top, thlm_flux_sfc, &
+ thlm_integral_forcing, &
+ dt )
+ else ! If l_implemented is false, we don't want spurious source output
+ rtm_spur_src = -9999.0_core_rknd
+ thlm_spur_src = -9999.0_core_rknd
+ end if
+
+ ! Write the var to stats
+ call stat_update_var_pt( irtm_spur_src, 1, rtm_spur_src, & ! intent(in)
+ stats_sfc ) ! intent(inout)
+ call stat_update_var_pt( ithlm_spur_src, 1, thlm_spur_src, & ! intent(in)
+ stats_sfc ) ! intent(inout)
+ end if
+
+ return
+ end subroutine advance_clubb_core
+
+ !-----------------------------------------------------------------------
+ subroutine setup_clubb_core &
+ ( nzmax, T0_in, ts_nudge_in, & ! intent(in)
+ hydromet_dim_in, sclr_dim_in, & ! intent(in)
+ sclr_tol_in, edsclr_dim_in, params, & ! intent(in)
+ l_host_applies_sfc_fluxes, & ! intent(in)
+ l_uv_nudge, saturation_formula, & ! intent(in)
+#ifdef GFDL
+ I_sat_sphum, & ! intent(in) h1g, 2010-06-16
+#endif
+ l_implemented, grid_type, deltaz, zm_init, zm_top, & ! intent(in)
+ momentum_heights, thermodynamic_heights, & ! intent(in)
+ sfc_elevation, & ! intent(in)
+#ifdef GFDL
+ cloud_frac_min , & ! intent(in) h1g, 2010-06-16
+#endif
+ err_code ) ! intent(out)
+ !
+ ! Description:
+ ! Subroutine to set up the model for execution.
+ !
+ ! References:
+ ! None
+ !-------------------------------------------------------------------------
+ use grid_class, only: &
+ setup_grid, & ! Procedure
+ gr ! Variable(s)
+
+ use parameter_indices, only: &
+ nparams ! Variable(s)
+
+ use parameters_tunable, only: &
+ setup_parameters ! Procedure
+
+ use parameters_model, only: &
+ setup_parameters_model ! Procedure
+
+ use variables_diagnostic_module, only: &
+ setup_diagnostic_variables ! Procedure
+
+ use variables_prognostic_module, only: &
+ setup_prognostic_variables ! Procedure
+
+ use constants_clubb, only: &
+ fstderr ! Variable(s)
+
+ use error_code, only: &
+ clubb_no_error ! Constant(s)
+
+ use model_flags, only: &
+ setup_model_flags ! Subroutine
+
+#ifdef MKL
+ use csr_matrix_module, only: &
+ initialize_csr_matrix, & ! Subroutine
+ intlc_5d_5d_ja_size ! Variable
+
+ use gmres_wrap, only: &
+ gmres_init ! Subroutine
+
+ use gmres_cache, only: &
+ gmres_cache_temp_init, &! Subroutine
+ gmres_idx_wp2wp3 ! Variable
+#endif /* MKL */
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+
+ ! Grid definition
+ integer, intent(in) :: nzmax ! Vertical grid levels [#]
+ ! Only true when used in a host model
+ ! CLUBB determines what nzmax should be
+ ! given zm_init and zm_top when
+ ! running in standalone mode.
+
+ real( kind = core_rknd ), intent(in) :: &
+ sfc_elevation ! Elevation of ground level [m AMSL]
+
+ ! Flag to see if CLUBB is running on it's own,
+ ! or if it's implemented as part of a host model.
+ logical, intent(in) :: l_implemented ! (T/F)
+
+ ! If CLUBB is running on it's own, this option determines
+ ! if it is using:
+ ! 1) an evenly-spaced grid,
+ ! 2) a stretched (unevenly-spaced) grid entered on the
+ ! thermodynamic grid levels (with momentum levels set
+ ! halfway between thermodynamic levels), or
+ ! 3) a stretched (unevenly-spaced) grid entered on the
+ ! momentum grid levels (with thermodynamic levels set
+ ! halfway between momentum levels).
+ integer, intent(in) :: grid_type
+
+ ! If the CLUBB model is running by itself, and is using an
+ ! evenly-spaced grid (grid_type = 1), it needs the vertical
+ ! grid spacing, momentum-level starting altitude, and maximum
+ ! altitude as input.
+ real( kind = core_rknd ), intent(in) :: &
+ deltaz, & ! Change in altitude per level [m]
+ zm_init, & ! Initial grid altitude (momentum level) [m]
+ zm_top ! Maximum grid altitude (momentum level) [m]
+
+ ! If the CLUBB parameterization is implemented in a host model,
+ ! it needs to use the host model's momentum level altitudes
+ ! and thermodynamic level altitudes.
+ ! If the CLUBB model is running by itself, but is using a
+ ! stretched grid entered on thermodynamic levels (grid_type = 2),
+ ! it needs to use the thermodynamic level altitudes as input.
+ ! If the CLUBB model is running by itself, but is using a
+ ! stretched grid entered on momentum levels (grid_type = 3),
+ ! it needs to use the momentum level altitudes as input.
+ real( kind = core_rknd ), intent(in), dimension(nzmax) :: &
+ momentum_heights, & ! Momentum level altitudes (input) [m]
+ thermodynamic_heights ! Thermodynamic level altitudes (input) [m]
+
+ ! Model parameters
+ real( kind = core_rknd ), intent(in) :: &
+ T0_in, ts_nudge_in
+
+ integer, intent(in) :: &
+ hydromet_dim_in, & ! Number of hydrometeor species
+ sclr_dim_in, & ! Number of passive scalars
+ edsclr_dim_in ! Number of eddy-diff. passive scalars
+
+ real( kind = core_rknd ), intent(in), dimension(sclr_dim_in) :: &
+ sclr_tol_in ! Thresholds for passive scalars
+
+ real( kind = core_rknd ), intent(in), dimension(nparams) :: &
+ params ! Including C1, nu1, nu2, etc.
+
+ ! Flags
+ logical, intent(in) :: &
+ l_uv_nudge, & ! Wind nudging
+ l_host_applies_sfc_fluxes ! Whether to apply for the surface flux
+
+ character(len=*), intent(in) :: &
+ saturation_formula ! Approximation for saturation vapor pressure
+
+#ifdef GFDL
+ logical, intent(in) :: & ! h1g, 2010-06-16 begin mod
+ I_sat_sphum
+
+ real( kind = core_rknd ), intent(in) :: &
+ cloud_frac_min ! h1g, 2010-06-16 end mod
+#endif
+
+ ! Output variables
+ integer, intent(out) :: &
+ err_code ! Diagnostic for a problem with the setup
+
+ ! Local variables
+ integer :: begin_height, end_height
+
+ !----- Begin Code -----
+
+ ! Sanity check for the saturation formula
+ select case ( trim( saturation_formula ) )
+ case ( "bolton", "Bolton" )
+ ! Using the Bolton 1980 approximations for SVP over vapor/ice
+
+ case ( "flatau", "Flatau" )
+ ! Using the Flatau, et al. polynomial approximation for SVP over vapor/ice
+
+ case ( "gfdl", "GFDL" ) ! h1g, 2010-06-16
+ ! Using the GFDL SVP formula (Goff-Gratch)
+
+ ! Add new saturation formulas after this
+
+ case default
+ write(fstderr,*) "Error in setup_clubb_core."
+ write(fstderr,*) "Unknown approx. of saturation vapor pressure: "// &
+ trim( saturation_formula )
+ stop
+ end select
+
+ ! Setup grid
+ call setup_grid( nzmax, sfc_elevation, l_implemented, & ! intent(in)
+ grid_type, deltaz, zm_init, zm_top, & ! intent(in)
+ momentum_heights, thermodynamic_heights, & ! intent(in)
+ begin_height, end_height ) ! intent(out)
+
+ ! Setup flags
+#ifdef GFDL
+ call setup_model_flags &
+ ( l_host_applies_sfc_fluxes, & ! intent(in)
+ l_uv_nudge, saturation_formula, & ! intent(in)
+ I_sat_sphum ) ! intent(in) h1g, 2010-06-16
+
+#else
+ call setup_model_flags &
+ ( l_host_applies_sfc_fluxes, & ! intent(in)
+ l_uv_nudge, saturation_formula ) ! intent(in)
+#endif
+
+
+ ! Define model constant parameters
+#ifdef GFDL
+ call setup_parameters_model( T0_in, ts_nudge_in, & ! intent(in)
+ hydromet_dim_in, & ! intent(in)
+ sclr_dim_in, sclr_tol_in, edsclr_dim_in, & ! intent(in)
+ cloud_frac_min ) ! intent(in) h1g, 2010-06-16
+#else
+ call setup_parameters_model( T0_in, ts_nudge_in, & ! intent(in)
+ hydromet_dim_in, & ! intent(in)
+ sclr_dim_in, sclr_tol_in, edsclr_dim_in ) ! intent(in)
+#endif
+
+ ! Define tunable constant parameters
+ call setup_parameters &
+ ( deltaz, params, gr%nz, & ! intent(in)
+ grid_type, momentum_heights(begin_height:end_height), & ! intent(in)
+ thermodynamic_heights(begin_height:end_height), & ! intent(in)
+ err_code ) ! intent(out)
+
+ ! Error Report
+ ! Joshua Fasching February 2008
+ if ( err_code /= clubb_no_error ) then
+
+ write(fstderr,*) "Error in setup_clubb_core"
+
+ write(fstderr,*) "Intent(in)"
+
+ write(fstderr,*) "deltaz = ", deltaz
+ write(fstderr,*) "zm_init = ", zm_init
+ write(fstderr,*) "zm_top = ", zm_top
+ write(fstderr,*) "momentum_heights = ", momentum_heights
+ write(fstderr,*) "thermodynamic_heights = ", &
+ thermodynamic_heights
+ write(fstderr,*) "T0_in = ", T0_in
+ write(fstderr,*) "ts_nudge_in = ", ts_nudge_in
+ write(fstderr,*) "params = ", params
+
+ return
+
+ end if
+
+#ifdef GFDL
+! setup prognostic_variables
+ call setup_prognostic_variables( gr%nz ) ! intent(in) h1g, 2010-06-16
+#else
+ if ( .not. l_implemented ) then
+ call setup_prognostic_variables( gr%nz ) ! intent(in)
+ end if
+#endif
+
+ ! The diagnostic variables need to be
+ ! declared, allocated, initialized, and deallocated whether CLUBB
+ ! is part of a larger model or not.
+ call setup_diagnostic_variables( gr%nz ) ! intent(in)
+
+#ifdef MKL
+ ! Initialize the CSR matrix class.
+ if ( l_gmres ) then
+ call initialize_csr_matrix
+ end if
+
+ if ( l_gmres ) then
+ call gmres_cache_temp_init( gr%nz ) ! intent(in)
+ call gmres_init( (2 * gr%nz), intlc_5d_5d_ja_size ) ! intent(in)
+ end if
+#endif /* MKL */
+
+ return
+ end subroutine setup_clubb_core
+
+ !----------------------------------------------------------------------------
+ subroutine cleanup_clubb_core( l_implemented )
+ !
+ ! Description:
+ ! Frees memory used by the model itself.
+ !
+ ! References:
+ ! None
+ !---------------------------------------------------------------------------
+ use parameters_model, only: sclr_tol ! Variable
+
+ use variables_diagnostic_module, only: &
+ cleanup_diagnostic_variables ! Procedure
+
+ use variables_prognostic_module, only: &
+ cleanup_prognostic_variables ! Procedure
+
+ use grid_class, only: &
+ cleanup_grid ! Procedure
+
+ use parameters_tunable, only: &
+ cleanup_nu ! Procedure
+
+ implicit none
+
+ ! Flag to see if CLUBB is running on it's own,
+ ! or if it's implemented as part of a host model.
+ logical, intent(in) :: l_implemented ! (T/F)
+
+ !----- Begin Code -----
+#ifdef GFDL
+ ! cleanup prognostic_variables
+ call cleanup_prognostic_variables( ) ! h1g, 2010-06-16
+#else
+ if ( .not. l_implemented ) then
+ call cleanup_prognostic_variables( )
+ end if
+#endif
+
+ ! The diagnostic variables need to be
+ ! declared, allocated, initialized, and deallocated whether CLUBB
+ ! is part of a larger model or not.
+ call cleanup_diagnostic_variables( )
+
+ ! De-allocate the array for the passive scalar tolerances
+ deallocate( sclr_tol )
+
+ ! De-allocate the arrays for the grid
+ call cleanup_grid( )
+
+ ! De-allocate the arrays for nu
+ call cleanup_nu( )
+
+ return
+ end subroutine cleanup_clubb_core
+
+ !-----------------------------------------------------------------------
+ subroutine trapezoidal_rule_zt &
+ ( l_call_pdf_closure_twice, & ! intent(in)
+ wprtp2, wpthlp2, & ! intent(inout)
+ wprtpthlp, cloud_frac, ice_supersat_frac, & ! intent(inout)
+ rcm, wp2thvp, wpsclrprtp, wpsclrp2, & ! intent(inout)
+ wpsclrpthlp, pdf_params, & ! intent(inout)
+ wprtp2_zm, wpthlp2_zm, & ! intent(inout)
+ wprtpthlp_zm, cloud_frac_zm, & ! intent(inout)
+ ice_supersat_frac_zm, rcm_zm, wp2thvp_zm, & ! intent(inout)
+ wpsclrprtp_zm, wpsclrp2_zm, wpsclrpthlp_zm, & ! intent(inout)
+ pdf_params_zm ) ! intent(inout)
+ !
+ ! Description:
+ ! This subroutine takes the output variables on the thermo.
+ ! grid and either: interpolates them to the momentum grid, or uses the
+ ! values output from the second call to pdf_closure on momentum levels if
+ ! l_call_pdf_closure_twice is true. It then calls the function
+ ! trapezoid_zt to recompute the variables on the thermo. grid.
+ !
+ ! ldgrant June 2009
+ !
+ ! Note:
+ ! The argument variables in the last 5 lines of the subroutine
+ ! (wprtp2_zm through pdf_params_zm) are declared intent(inout) because
+ ! if l_call_pdf_closure_twice is true, these variables will already have
+ ! values from pdf_closure on momentum levels and will not be altered in
+ ! this subroutine. However, if l_call_pdf_closure_twice is false, these
+ ! variables will not have values yet and will be interpolated to
+ ! momentum levels in this subroutine.
+ ! References:
+ ! None
+ !-----------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ fstderr ! Constant(s)
+
+ use stats_variables, only: &
+ iwprtp2, & ! Varibles
+ iwprtpthlp, &
+ iwpthlp2, &
+ iwprtp2, &
+ iwpsclrp2, &
+ iwpsclrprtp, &
+ iwpsclrpthlp, &
+ l_stats
+
+ use grid_class, only: &
+ gr, & ! Variable
+ zt2zm ! Procedure
+
+ use parameters_model, only: &
+ sclr_dim ! Number of passive scalar variables
+
+ use pdf_parameter_module, only: &
+ pdf_parameter ! Derived data type
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Constant parameters
+ logical, parameter :: &
+ l_apply_rule_to_pdf_params = .false. ! Apply the trapezoidal rule to pdf_params
+
+ ! Input variables
+ logical, intent(in) :: l_call_pdf_closure_twice
+
+ ! Input/Output variables
+ ! Thermodynamic level variables output from the first call to pdf_closure
+ real( kind = core_rknd ), dimension(gr%nz), intent(inout) :: &
+ wprtp2, & ! w'rt'^2 [m kg^2/kg^2]
+ wpthlp2, & ! w'thl'^2 [m K^2/s]
+ wprtpthlp, & ! w'rt'thl' [m kg K/kg s]
+ cloud_frac, & ! Cloud Fraction [-]
+ ice_supersat_frac, & ! Ice Cloud Fraction [-]
+ rcm, & ! Liquid water mixing ratio [kg/kg]
+ wp2thvp ! w'^2 th_v' [m^2 K/s^2]
+
+ real( kind = core_rknd ), dimension(gr%nz,sclr_dim), intent(inout) :: &
+ wpsclrprtp, & ! w'sclr'rt'
+ wpsclrp2, & ! w'sclr'^2
+ wpsclrpthlp ! w'sclr'thl'
+
+ type (pdf_parameter), dimension(gr%nz), intent(inout) :: &
+ pdf_params ! PDF parameters [units vary]
+
+ ! Thermo. level variables brought to momentum levels either by
+ ! interpolation (in subroutine trapezoidal_rule_zt) or by
+ ! the second call to pdf_closure (in subroutine advance_clubb_core)
+ real( kind = core_rknd ), dimension(gr%nz), intent(inout) :: &
+ wprtp2_zm, & ! w'rt'^2 on momentum grid [m kg^2/kg^2]
+ wpthlp2_zm, & ! w'thl'^2 on momentum grid [m K^2/s]
+ wprtpthlp_zm, & ! w'rt'thl' on momentum grid [m kg K/kg s]
+ cloud_frac_zm, & ! Cloud Fraction on momentum grid [-]
+ ice_supersat_frac_zm, & ! Ice Cloud Fraction on momentum grid [-]
+ rcm_zm, & ! Liquid water mixing ratio on momentum grid [kg/kg]
+ wp2thvp_zm ! w'^2 th_v' on momentum grid [m^2 K/s^2]
+
+ real( kind = core_rknd ), dimension(gr%nz,sclr_dim), intent(inout) :: &
+ wpsclrprtp_zm, & ! w'sclr'rt' on momentum grid
+ wpsclrp2_zm, & ! w'sclr'^2 on momentum grid
+ wpsclrpthlp_zm ! w'sclr'thl' on momentum grid
+
+ type (pdf_parameter), dimension(gr%nz), intent(inout) :: &
+ pdf_params_zm ! PDF parameters on momentum grid [units vary]
+
+ ! Local variables
+
+ ! Components of PDF_parameters on the momentum grid (_zm) and on the thermo. grid (_zt)
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ w_1_zt, & ! Mean of w for 1st normal distribution [m/s]
+ w_1_zm, & ! Mean of w for 1st normal distribution [m/s]
+ w_2_zm, & ! Mean of w for 2nd normal distribution [m/s]
+ w_2_zt, & ! Mean of w for 2nd normal distribution [m/s]
+ varnce_w_1_zm, & ! Variance of w for 1st normal distribution [m^2/s^2]
+ varnce_w_1_zt, & ! Variance of w for 1st normal distribution [m^2/s^2]
+ varnce_w_2_zm, & ! Variance of w for 2nd normal distribution [m^2/s^2]
+ varnce_w_2_zt, & ! Variance of w for 2nd normal distribution [m^2/s^2]
+ rt_1_zm, & ! Mean of r_t for 1st normal distribution [kg/kg]
+ rt_1_zt, & ! Mean of r_t for 1st normal distribution [kg/kg]
+ rt_2_zm, & ! Mean of r_t for 2nd normal distribution [kg/kg]
+ rt_2_zt, & ! Mean of r_t for 2nd normal distribution [kg/kg]
+ varnce_rt_1_zm, & ! Variance of r_t for 1st normal distribution [kg^2/kg^2]
+ varnce_rt_1_zt, & ! Variance of r_t for 1st normal distribution [kg^2/kg^2]
+ varnce_rt_2_zm, & ! Variance of r_t for 2nd normal distribution [kg^2/kg^2]
+ varnce_rt_2_zt, & ! Variance of r_t for 2nd normal distribution [kg^2/kg^2]
+ crt_1_zm, & ! Coefficient for s' [-]
+ crt_1_zt, & ! Coefficient for s' [-]
+ crt_2_zm ! Coefficient for s' [-]
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ crt_2_zt, & ! Coefficient for s' [-]
+ cthl_1_zm, & ! Coefficient for s' [1/K]
+ cthl_1_zt, & ! Coefficient for s' [1/K]
+ cthl_2_zm, & ! Coefficient for s' [1/K]
+ cthl_2_zt, & ! Coefficient for s' [1/K]
+ thl_1_zm, & ! Mean of th_l for 1st normal distribution [K]
+ thl_1_zt, & ! Mean of th_l for 1st normal distribution [K]
+ thl_2_zm, & ! Mean of th_l for 2nd normal distribution [K]
+ thl_2_zt, & ! Mean of th_l for 2nd normal distribution
+ varnce_thl_1_zm, & ! Variance of th_l for 1st normal distribution [K^2]
+ varnce_thl_1_zt, & ! Variance of th_l for 1st normal distribution [K^2]
+ varnce_thl_2_zm, & ! Variance of th_l for 2nd normal distribution [K^2]
+ varnce_thl_2_zt ! Variance of th_l for 2nd normal distribution [K^2]
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ mixt_frac_zm, & ! Weight of 1st normal distribution (Sk_w dependent) [-]
+ mixt_frac_zt, & ! Weight of 1st normal distribution (Sk_w dependent) [-]
+ rc_1_zm, & ! Mean of r_c for 1st normal distribution [kg/kg]
+ rc_1_zt, & ! Mean of r_c for 1st normal distribution [kg/kg]
+ rc_2_zm, & ! Mean of r_c for 2nd normal distribution [kg/kg]
+ rc_2_zt, & ! Mean of r_c for 2nd normal distribution [kg/kg]
+ rsatl_1_zm, & ! Mean of r_sl for 1st normal distribution [kg/kg]
+ rsatl_1_zt, & ! Mean of r_sl for 1st normal distribution [kg/kg]
+ rsatl_2_zm, & ! Mean of r_sl for 2nd normal distribution [kg/kg]
+ rsatl_2_zt, & ! Mean of r_sl for 2nd normal distribution [kg/kg]
+ cloud_frac_1_zm, & ! Cloud fraction for 1st normal distribution [-]
+ cloud_frac_1_zt, & ! Cloud fraction for 1st normal distribution [-]
+ cloud_frac_2_zm, & ! Cloud fraction for 2nd normal distribution [-]
+ cloud_frac_2_zt, & ! Cloud fraction for 2nd normal distribution [-]
+ chi_1_zm, & ! Mean of chi(s) for 1st normal distribution [kg/kg]
+ chi_1_zt, & ! Mean of chi(s) for 1st normal distribution [kg/kg]
+ chi_2_zm, & ! Mean of chi(s) for 2nd normal distribution [kg/kg]
+ chi_2_zt, & ! Mean of chi(s) for 2nd normal distribution [kg/kg]
+ stdev_chi_1_zm ! Standard deviation of chi(s) for 1st normal distribution [kg/kg]
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ stdev_chi_1_zt, & ! Standard deviation of chi(s) for 1st normal distribution [kg/kg]
+ stdev_chi_2_zm, & ! Standard deviation of chi(s) for 2nd normal distribution [kg/kg]
+ stdev_chi_2_zt, & ! Standard deviation of chi(s) for 2nd normal distribution [kg/kg]
+ stdev_eta_1_zm, & ! Standard deviation of eta(t) for 1st normal distribution [kg/kg]
+ stdev_eta_1_zt, & ! Standard deviation of eta(t) for 1st normal distribution [kg/kg]
+ stdev_eta_2_zm, & ! Standard deviation of eta(t) for 2nd normal distribution [kg/kg]
+ stdev_eta_2_zt, & ! Standard deviation of eta(t) for 2nd normal distribution [kg/kg]
+ rrtthl_zm, & ! Within-a-normal correlation of r_t and th_l [-]
+ rrtthl_zt, & ! Within-a-normal correlation of r_t and th_l [-]
+ alpha_thl_zm, & ! Factor relating to normalized variance for th_l [-]
+ alpha_thl_zt, & ! Factor relating to normalized variance for th_l [-]
+ alpha_rt_zm, & ! Factor relating to normalized variance for r_t [-]
+ alpha_rt_zt ! Factor relating to normalized variance for r_t [-]
+
+ integer :: i
+
+ !----------------------- Begin Code -----------------------------
+
+ ! Store components of pdf_params in the locally declared variables
+ ! We only apply the trapezoidal rule to these when
+ ! l_apply_rule_to_pdf_params is true. This is because when we apply the
+ ! rule to the final result of pdf_closure rather than the intermediate
+ ! results it can lead to an inconsistency in how we determine which
+ ! PDF component a point is in and whether the point is in or out of cloud,
+ ! which is turn will break the latin hypercube code that samples
+ ! preferentially in cloud. -dschanen 13 Feb 2012
+
+ if ( l_apply_rule_to_pdf_params ) then
+ w_1_zt = pdf_params%w_1
+ w_2_zt = pdf_params%w_2
+ varnce_w_1_zt = pdf_params%varnce_w_1
+ varnce_w_2_zt = pdf_params%varnce_w_2
+ rt_1_zt = pdf_params%rt_1
+ rt_2_zt = pdf_params%rt_2
+ varnce_rt_1_zt = pdf_params%varnce_rt_1
+ varnce_rt_2_zt = pdf_params%varnce_rt_2
+ crt_1_zt = pdf_params%crt_1
+ crt_2_zt = pdf_params%crt_2
+ cthl_1_zt = pdf_params%cthl_1
+ cthl_2_zt = pdf_params%cthl_2
+ thl_1_zt = pdf_params%thl_1
+ thl_2_zt = pdf_params%thl_2
+ varnce_thl_1_zt = pdf_params%varnce_thl_1
+ varnce_thl_2_zt = pdf_params%varnce_thl_2
+ mixt_frac_zt = pdf_params%mixt_frac
+ rc_1_zt = pdf_params%rc_1
+ rc_2_zt = pdf_params%rc_2
+ rsatl_1_zt = pdf_params%rsatl_1
+ rsatl_2_zt = pdf_params%rsatl_2
+ cloud_frac_1_zt = pdf_params%cloud_frac_1
+ cloud_frac_2_zt = pdf_params%cloud_frac_2
+ chi_1_zt = pdf_params%chi_1
+ chi_2_zt = pdf_params%chi_2
+ stdev_chi_1_zt = pdf_params%stdev_chi_1
+ stdev_chi_2_zt = pdf_params%stdev_chi_2
+ stdev_eta_1_zt = pdf_params%stdev_eta_1
+ stdev_eta_2_zt = pdf_params%stdev_eta_2
+ rrtthl_zt = pdf_params%rrtthl
+ alpha_thl_zt = pdf_params%alpha_thl
+ alpha_rt_zt = pdf_params%alpha_rt
+ end if
+
+ ! If l_call_pdf_closure_twice is true, the _zm variables already have
+ ! values from the second call to pdf_closure in advance_clubb_core.
+ ! If it is false, the variables are interpolated to the _zm levels.
+ if ( l_call_pdf_closure_twice ) then
+
+ ! Store, in locally declared variables, the pdf_params output
+ ! from the second call to pdf_closure
+ if ( l_apply_rule_to_pdf_params ) then
+ w_1_zm = pdf_params_zm%w_1
+ w_2_zm = pdf_params_zm%w_2
+ varnce_w_1_zm = pdf_params_zm%varnce_w_1
+ varnce_w_2_zm = pdf_params_zm%varnce_w_2
+ rt_1_zm = pdf_params_zm%rt_1
+ rt_2_zm = pdf_params_zm%rt_2
+ varnce_rt_1_zm = pdf_params_zm%varnce_rt_1
+ varnce_rt_2_zm = pdf_params_zm%varnce_rt_2
+ crt_1_zm = pdf_params_zm%crt_1
+ crt_2_zm = pdf_params_zm%crt_2
+ cthl_1_zm = pdf_params_zm%cthl_1
+ cthl_2_zm = pdf_params_zm%cthl_2
+ thl_1_zm = pdf_params_zm%thl_1
+ thl_2_zm = pdf_params_zm%thl_2
+ varnce_thl_1_zm = pdf_params_zm%varnce_thl_1
+ varnce_thl_2_zm = pdf_params_zm%varnce_thl_2
+ mixt_frac_zm = pdf_params_zm%mixt_frac
+ rc_1_zm = pdf_params_zm%rc_1
+ rc_2_zm = pdf_params_zm%rc_2
+ rsatl_1_zm = pdf_params_zm%rsatl_1
+ rsatl_2_zm = pdf_params_zm%rsatl_2
+ cloud_frac_1_zm = pdf_params_zm%cloud_frac_1
+ cloud_frac_2_zm = pdf_params_zm%cloud_frac_2
+ chi_1_zm = pdf_params_zm%chi_1
+ chi_2_zm = pdf_params_zm%chi_2
+ stdev_chi_1_zm = pdf_params_zm%stdev_chi_1
+ stdev_chi_2_zm = pdf_params_zm%stdev_chi_2
+ stdev_eta_1_zm = pdf_params_zm%stdev_eta_1
+ stdev_eta_2_zm = pdf_params_zm%stdev_eta_2
+ rrtthl_zm = pdf_params_zm%rrtthl
+ alpha_thl_zm = pdf_params_zm%alpha_thl
+ alpha_rt_zm = pdf_params_zm%alpha_rt
+ end if
+
+ else
+
+ ! Interpolate thermodynamic variables to the momentum grid.
+ ! Since top momentum level is higher than top thermo. level,
+ ! set variables at top momentum level to 0.
+ wprtp2_zm = zt2zm( wprtp2 )
+ wprtp2_zm(gr%nz) = 0.0_core_rknd
+ wpthlp2_zm = zt2zm( wpthlp2 )
+ wpthlp2_zm(gr%nz) = 0.0_core_rknd
+ wprtpthlp_zm = zt2zm( wprtpthlp )
+ wprtpthlp_zm(gr%nz) = 0.0_core_rknd
+ cloud_frac_zm = zt2zm( cloud_frac )
+ cloud_frac_zm(gr%nz) = 0.0_core_rknd
+ ice_supersat_frac_zm = zt2zm( ice_supersat_frac )
+ ice_supersat_frac_zm(gr%nz) = 0.0_core_rknd
+ rcm_zm = zt2zm( rcm )
+ rcm_zm(gr%nz) = 0.0_core_rknd
+ wp2thvp_zm = zt2zm( wp2thvp )
+ wp2thvp_zm(gr%nz) = 0.0_core_rknd
+
+ do i = 1, sclr_dim
+ wpsclrprtp_zm(:,i) = zt2zm( wpsclrprtp(:,i) )
+ wpsclrprtp_zm(gr%nz,i) = 0.0_core_rknd
+ wpsclrp2_zm(:,i) = zt2zm( wpsclrp2(:,i) )
+ wpsclrp2_zm(gr%nz,i) = 0.0_core_rknd
+ wpsclrpthlp_zm(:,i) = zt2zm( wpsclrpthlp(:,i) )
+ wpsclrpthlp_zm(gr%nz,i) = 0.0_core_rknd
+ end do ! i = 1, sclr_dim
+
+ if ( l_apply_rule_to_pdf_params ) then
+ w_1_zm = zt2zm( pdf_params%w_1 )
+ w_1_zm(gr%nz) = 0.0_core_rknd
+ w_2_zm = zt2zm( pdf_params%w_2 )
+ w_2_zm(gr%nz) = 0.0_core_rknd
+ varnce_w_1_zm = zt2zm( pdf_params%varnce_w_1 )
+ varnce_w_1_zm(gr%nz) = 0.0_core_rknd
+ varnce_w_2_zm = zt2zm( pdf_params%varnce_w_2 )
+ varnce_w_2_zm(gr%nz) = 0.0_core_rknd
+ rt_1_zm = zt2zm( pdf_params%rt_1 )
+ rt_1_zm(gr%nz) = 0.0_core_rknd
+ rt_2_zm = zt2zm( pdf_params%rt_2 )
+ rt_2_zm(gr%nz) = 0.0_core_rknd
+ varnce_rt_1_zm = zt2zm( pdf_params%varnce_rt_1 )
+ varnce_rt_1_zm(gr%nz) = 0.0_core_rknd
+ varnce_rt_2_zm = zt2zm( pdf_params%varnce_rt_2 )
+ varnce_rt_2_zm(gr%nz) = 0.0_core_rknd
+ crt_1_zm = zt2zm( pdf_params%crt_1 )
+ crt_1_zm(gr%nz) = 0.0_core_rknd
+ crt_2_zm = zt2zm( pdf_params%crt_2 )
+ crt_2_zm(gr%nz) = 0.0_core_rknd
+ cthl_1_zm = zt2zm( pdf_params%cthl_1 )
+ cthl_1_zm(gr%nz) = 0.0_core_rknd
+ cthl_2_zm = zt2zm( pdf_params%cthl_2 )
+ cthl_2_zm(gr%nz) = 0.0_core_rknd
+ thl_1_zm = zt2zm( pdf_params%thl_1 )
+ thl_1_zm(gr%nz) = 0.0_core_rknd
+ thl_2_zm = zt2zm( pdf_params%thl_2 )
+ thl_2_zm(gr%nz) = 0.0_core_rknd
+ varnce_thl_1_zm = zt2zm( pdf_params%varnce_thl_1 )
+ varnce_thl_1_zm(gr%nz) = 0.0_core_rknd
+ varnce_thl_2_zm = zt2zm( pdf_params%varnce_thl_2 )
+ varnce_thl_2_zm(gr%nz) = 0.0_core_rknd
+ mixt_frac_zm = zt2zm( pdf_params%mixt_frac )
+ mixt_frac_zm(gr%nz) = 0.0_core_rknd
+ rc_1_zm = zt2zm( pdf_params%rc_1 )
+ rc_1_zm(gr%nz) = 0.0_core_rknd
+ rc_2_zm = zt2zm( pdf_params%rc_2 )
+ rc_2_zm(gr%nz) = 0.0_core_rknd
+ rsatl_1_zm = zt2zm( pdf_params%rsatl_1 )
+ rsatl_1_zm(gr%nz) = 0.0_core_rknd
+ rsatl_2_zm = zt2zm( pdf_params%rsatl_2 )
+ rsatl_2_zm(gr%nz) = 0.0_core_rknd
+ cloud_frac_1_zm = zt2zm( pdf_params%cloud_frac_1 )
+ cloud_frac_1_zm(gr%nz) = 0.0_core_rknd
+ cloud_frac_2_zm = zt2zm( pdf_params%cloud_frac_2 )
+ cloud_frac_2_zm(gr%nz) = 0.0_core_rknd
+ chi_1_zm = zt2zm( pdf_params%chi_1 )
+ chi_1_zm(gr%nz) = 0.0_core_rknd
+ chi_2_zm = zt2zm( pdf_params%chi_2 )
+ chi_2_zm(gr%nz) = 0.0_core_rknd
+ stdev_chi_1_zm = zt2zm( pdf_params%stdev_chi_1 )
+ stdev_chi_1_zm(gr%nz) = 0.0_core_rknd
+ stdev_chi_2_zm = zt2zm( pdf_params%stdev_chi_2 )
+ stdev_chi_2_zm(gr%nz) = 0.0_core_rknd
+ stdev_eta_1_zm = zt2zm( pdf_params%stdev_eta_1 )
+ stdev_eta_1_zm(gr%nz) = 0.0_core_rknd
+ stdev_eta_2_zm = zt2zm( pdf_params%stdev_eta_2 )
+ stdev_eta_2_zm(gr%nz) = 0.0_core_rknd
+ rrtthl_zm = zt2zm( pdf_params%rrtthl )
+ rrtthl_zm(gr%nz) = 0.0_core_rknd
+ alpha_thl_zm = zt2zm( pdf_params%alpha_thl )
+ alpha_thl_zm(gr%nz) = 0.0_core_rknd
+ alpha_rt_zm = zt2zm( pdf_params%alpha_rt )
+ alpha_rt_zm(gr%nz) = 0.0_core_rknd
+ end if
+ end if ! l_call_pdf_closure_twice
+
+ if ( l_stats ) then
+ ! Use the trapezoidal rule to recompute the variables on the stats_zt level
+ if ( iwprtp2 > 0 ) then
+ wprtp2 = trapezoid_zt( wprtp2, wprtp2_zm )
+ end if
+ if ( iwpthlp2 > 0 ) then
+ wpthlp2 = trapezoid_zt( wpthlp2, wpthlp2_zm )
+ end if
+ if ( iwprtpthlp > 0 ) then
+ wprtpthlp = trapezoid_zt( wprtpthlp, wprtpthlp_zm )
+ end if
+
+ do i = 1, sclr_dim
+ if ( iwpsclrprtp(i) > 0 ) then
+ wpsclrprtp(:,i) = trapezoid_zt( wpsclrprtp(:,i), wpsclrprtp_zm(:,i) )
+ end if
+ if ( iwpsclrpthlp(i) > 0 ) then
+ wpsclrpthlp(:,i) = trapezoid_zt( wpsclrpthlp(:,i), wpsclrpthlp_zm(:,i) )
+ end if
+ if ( iwpsclrp2(i) > 0 ) then
+ wpsclrp2(:,i) = trapezoid_zt( wpsclrp2(:,i), wpsclrp2_zm(:,i) )
+ end if
+ end do ! i = 1, sclr_dim
+ end if ! l_stats
+
+ cloud_frac = trapezoid_zt( cloud_frac, cloud_frac_zm )
+ ice_supersat_frac = trapezoid_zt( ice_supersat_frac, ice_supersat_frac_zm )
+ rcm = trapezoid_zt( rcm, rcm_zm )
+
+ wp2thvp = trapezoid_zt( wp2thvp, wp2thvp_zm )
+
+ if ( l_apply_rule_to_pdf_params ) then
+ ! Note: this code makes PDF component cloud water mixing ratios and
+ ! cloud fractions inconsistent with the PDF. Other parts of
+ ! CLUBB require PDF component cloud fractions to remain
+ ! consistent with the PDF. This code needs to be refactored
+ ! so that cloud_frac_1 and cloud_frac_2 are preserved.
+ write(fstderr,*) "The code in l_apply_rule_to_pdf_params does not " &
+ // "preserve cloud_frac_1 and cloud_frac_2 in a " &
+ // "manner consistent with the PDF as required " &
+ // "by other parts of CLUBB."
+ stop "Please refactor before continuing."
+ pdf_params%w_1 = trapezoid_zt( w_1_zt, w_1_zm )
+ pdf_params%w_2 = trapezoid_zt( w_2_zt, w_2_zm )
+ pdf_params%varnce_w_1 = trapezoid_zt( varnce_w_1_zt, varnce_w_1_zm )
+ pdf_params%varnce_w_2 = trapezoid_zt( varnce_w_2_zt, varnce_w_2_zm )
+ pdf_params%rt_1 = trapezoid_zt( rt_1_zt, rt_1_zm )
+ pdf_params%rt_2 = trapezoid_zt( rt_2_zt, rt_2_zm )
+ pdf_params%varnce_rt_1 = trapezoid_zt( varnce_rt_1_zt, varnce_rt_1_zm )
+ pdf_params%varnce_rt_2 = trapezoid_zt( varnce_rt_2_zt, varnce_rt_2_zm )
+ pdf_params%crt_1 = trapezoid_zt( crt_1_zt, crt_1_zm )
+ pdf_params%crt_2 = trapezoid_zt( crt_2_zt, crt_2_zm )
+ pdf_params%cthl_1 = trapezoid_zt( cthl_1_zt, cthl_1_zm )
+ pdf_params%cthl_2 = trapezoid_zt( cthl_2_zt, cthl_2_zm )
+ pdf_params%thl_1 = trapezoid_zt( thl_1_zt, thl_1_zm )
+ pdf_params%thl_2 = trapezoid_zt( thl_2_zt, thl_2_zm )
+ pdf_params%varnce_thl_1 = trapezoid_zt( varnce_thl_1_zt, varnce_thl_1_zm )
+ pdf_params%varnce_thl_2 = trapezoid_zt( varnce_thl_2_zt, varnce_thl_2_zm )
+ pdf_params%mixt_frac = trapezoid_zt( mixt_frac_zt, mixt_frac_zm )
+ pdf_params%rc_1 = trapezoid_zt( rc_1_zt, rc_1_zm )
+ pdf_params%rc_2 = trapezoid_zt( rc_2_zt, rc_2_zm )
+ pdf_params%rsatl_1 = trapezoid_zt( rsatl_1_zt, rsatl_1_zm )
+ pdf_params%rsatl_2 = trapezoid_zt( rsatl_2_zt, rsatl_2_zm )
+ pdf_params%cloud_frac_1 = trapezoid_zt( cloud_frac_1_zt, cloud_frac_1_zm )
+ pdf_params%cloud_frac_2 = trapezoid_zt( cloud_frac_2_zt, cloud_frac_2_zm )
+ pdf_params%chi_1 = trapezoid_zt( chi_1_zt, chi_1_zm )
+ pdf_params%chi_2 = trapezoid_zt( chi_2_zt, chi_2_zm )
+ pdf_params%rrtthl = trapezoid_zt( rrtthl_zt, rrtthl_zm )
+ pdf_params%alpha_thl = trapezoid_zt( alpha_thl_zt, alpha_thl_zm )
+ pdf_params%alpha_rt = trapezoid_zt( alpha_rt_zt, alpha_rt_zm )
+ pdf_params%stdev_chi_1 = trapezoid_zt( stdev_chi_1_zt, stdev_chi_1_zm )
+ pdf_params%stdev_chi_2 = trapezoid_zt( stdev_chi_2_zt, stdev_chi_2_zm )
+ pdf_params%stdev_eta_1 = trapezoid_zt( stdev_eta_1_zt, stdev_eta_1_zm )
+ pdf_params%stdev_eta_2 = trapezoid_zt( stdev_eta_2_zt, stdev_eta_2_zm )
+ end if
+
+ ! End of trapezoidal rule
+
+ return
+ end subroutine trapezoidal_rule_zt
+
+ !-----------------------------------------------------------------------
+ subroutine trapezoidal_rule_zm &
+ ( wpthvp_zt, thlpthvp_zt, rtpthvp_zt, & ! intent(in)
+ wpthvp, thlpthvp, rtpthvp ) ! intent(inout)
+ !
+ ! Description:
+ ! This subroutine recomputes three variables on the
+ ! momentum grid from pdf_closure -- wpthvp, thlpthvp, and
+ ! rtpthvp -- by calling the function trapezoid_zm. Only these three
+ ! variables are used in this subroutine because they are the only
+ ! pdf_closure momentum variables used elsewhere in CLUBB.
+ !
+ ! The _zt variables are output from the first call to pdf_closure.
+ ! The _zm variables are output from the second call to pdf_closure
+ ! on the momentum levels.
+ ! This is done before the call to this subroutine.
+ !
+ ! ldgrant Feb. 2010
+ !
+ ! References:
+ ! None
+ !-----------------------------------------------------------------------
+
+ use grid_class, only: gr ! Variable
+
+ use clubb_precision, only: &
+ core_rknd ! variable(s)
+
+ implicit none
+
+ ! Input variables
+ real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
+ wpthvp_zt, & ! Buoyancy flux (on thermo. grid) [(K m)/s]
+ thlpthvp_zt, & ! th_l' th_v' (on thermo. grid) [K^2]
+ rtpthvp_zt ! r_t' th_v' (on thermo. grid) [(kg K)/kg]
+
+ ! Input/Output variables
+ real( kind = core_rknd ), dimension(gr%nz), intent(inout) :: &
+ wpthvp, & ! Buoyancy flux [(K m)/s]
+ thlpthvp, & ! th_l' th_v' [K^2]
+ rtpthvp ! r_t' th_v' [(kg K)/kg]
+
+ !----------------------- Begin Code -----------------------------
+
+ ! Use the trapezoidal rule to recompute the variables on the zm level
+ wpthvp = trapezoid_zm( wpthvp, wpthvp_zt )
+ thlpthvp = trapezoid_zm( thlpthvp, thlpthvp_zt )
+ rtpthvp = trapezoid_zm( rtpthvp, rtpthvp_zt )
+
+ return
+ end subroutine trapezoidal_rule_zm
+
+ !-----------------------------------------------------------------------
+ pure function trapezoid_zt( variable_zt, variable_zm )
+ !
+ ! Description:
+ ! Function which uses the trapezoidal rule from calculus
+ ! to recompute the values for the variables on the thermo. grid which
+ ! are output from the first call to pdf_closure in module clubb_core.
+ !
+ ! ldgrant June 2009
+ !--------------------------------------------------------------------
+
+ use grid_class, only: gr ! Variable
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
+ variable_zt, & ! Variable on the zt grid
+ variable_zm ! Variable on the zm grid
+
+ ! Result
+ real( kind = core_rknd ), dimension(gr%nz) :: trapezoid_zt
+
+ ! Local Variable
+ integer :: k ! Loop index
+
+ !------------ Begin Code --------------
+
+ ! Boundary condition: trapezoidal rule not valid at zt level 1
+ trapezoid_zt(1) = variable_zt(1)
+
+ do k = 2, gr%nz
+ ! Trapezoidal rule from calculus
+ trapezoid_zt(k) = 0.5_core_rknd * ( variable_zm(k) + variable_zt(k) ) &
+ * ( gr%zm(k) - gr%zt(k) ) * gr%invrs_dzt(k) &
+ + 0.5_core_rknd * ( variable_zt(k) + variable_zm(k-1) ) &
+ * ( gr%zt(k) - gr%zm(k-1) ) * gr%invrs_dzt(k)
+ end do ! k = 2, gr%nz
+
+ return
+ end function trapezoid_zt
+
+ !-----------------------------------------------------------------------
+ pure function trapezoid_zm( variable_zm, variable_zt )
+ !
+ ! Description:
+ ! Function which uses the trapezoidal rule from calculus
+ ! to recompute the values for the important variables on the momentum
+ ! grid which are output from pdf_closure in module clubb_core.
+ ! These momentum variables only include wpthvp, thlpthvp, and rtpthvp.
+ !
+ ! ldgrant Feb. 2010
+ !--------------------------------------------------------------------
+
+ use grid_class, only: gr ! Variable
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
+ variable_zm, & ! Variable on the zm grid
+ variable_zt ! Variable on the zt grid
+
+ ! Result
+ real( kind = core_rknd ), dimension(gr%nz) :: trapezoid_zm
+
+ ! Local Variable
+ integer :: k ! Loop index
+
+ !------------ Begin Code --------------
+
+ ! Boundary conditions: trapezoidal rule not valid at top zm level, nzmax.
+ ! Trapezoidal rule also not used at zm level 1.
+ trapezoid_zm(1) = variable_zm(1)
+ trapezoid_zm(gr%nz) = variable_zm(gr%nz)
+
+ do k = 2, gr%nz-1
+ ! Trapezoidal rule from calculus
+ trapezoid_zm(k) = 0.5_core_rknd * ( variable_zt(k+1) + variable_zm(k) ) &
+ * ( gr%zt(k+1) - gr%zm(k) ) * gr%invrs_dzm(k) &
+ + 0.5_core_rknd * ( variable_zm(k) + variable_zt(k) ) &
+ * ( gr%zm(k) - gr%zt(k) ) * gr%invrs_dzm(k)
+ end do ! k = 2, gr%nz-1
+
+ return
+ end function trapezoid_zm
+
+ !-----------------------------------------------------------------------
+ subroutine compute_cloud_cover &
+ ( pdf_params, cloud_frac, rcm, & ! intent(in)
+ cloud_cover, rcm_in_layer ) ! intent(out)
+ !
+ ! Description:
+ ! Subroutine to compute cloud cover (the amount of sky
+ ! covered by cloud) and rcm in layer (liquid water mixing ratio in
+ ! the portion of the grid box filled by cloud).
+ !
+ ! References:
+ ! Definition of 's' comes from:
+ ! ``The Gaussian Cloud Model Relations'' G. L. Mellor (1977)
+ ! JAS, Vol. 34, pp. 356--358.
+ !
+ ! Notes:
+ ! Added July 2009
+ !---------------------------------------------------------------------
+
+ use constants_clubb, only: &
+ rc_tol, & ! Variable(s)
+ fstderr
+
+ use grid_class, only: gr ! Variable
+
+ use pdf_parameter_module, only: &
+ pdf_parameter ! Derived data type
+
+ use error_code, only: &
+ clubb_at_least_debug_level ! Procedure
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! External functions
+ intrinsic :: abs, min, max
+
+ ! Input variables
+ real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
+ cloud_frac, & ! Cloud fraction [-]
+ rcm ! Liquid water mixing ratio [kg/kg]
+
+ type (pdf_parameter), dimension(gr%nz), intent(in) :: &
+ pdf_params ! PDF Parameters [units vary]
+
+ ! Output variables
+ real( kind = core_rknd ), dimension(gr%nz), intent(out) :: &
+ cloud_cover, & ! Cloud cover [-]
+ rcm_in_layer ! Liquid water mixing ratio in cloud layer [kg/kg]
+
+ ! Local variables
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ chi_mean, & ! Mean extended cloud water mixing ratio of the
+ ! two Gaussian distributions
+ vert_cloud_frac_upper, & ! Fraction of cloud in top half of grid box
+ vert_cloud_frac_lower, & ! Fraction of cloud in bottom half of grid box
+ vert_cloud_frac ! Fraction of cloud filling the grid box in the vertical
+
+ integer :: k
+
+ ! ------------ Begin code ---------------
+
+ do k = 1, gr%nz
+
+ chi_mean(k) = pdf_params(k)%mixt_frac * pdf_params(k)%chi_1 + &
+ (1.0_core_rknd-pdf_params(k)%mixt_frac) * pdf_params(k)%chi_2
+
+ end do
+
+ do k = 2, gr%nz-1, 1
+
+ if ( rcm(k) < rc_tol ) then ! No cloud at this level
+
+ cloud_cover(k) = cloud_frac(k)
+ rcm_in_layer(k) = rcm(k)
+
+ else if ( ( rcm(k+1) >= rc_tol ) .and. ( rcm(k-1) >= rc_tol ) ) then
+ ! There is cloud above and below,
+ ! so assume cloud fills grid box from top to bottom
+
+ cloud_cover(k) = cloud_frac(k)
+ rcm_in_layer(k) = rcm(k)
+
+ else if ( ( rcm(k+1) < rc_tol ) .or. ( rcm(k-1) < rc_tol) ) then
+ ! Cloud may fail to reach gridbox top or base or both
+
+ ! First let the cloud fill the entire grid box, then overwrite
+ ! vert_cloud_frac_upper(k) and/or vert_cloud_frac_lower(k)
+ ! for a cloud top, cloud base, or one-point cloud.
+ vert_cloud_frac_upper(k) = 0.5_core_rknd
+ vert_cloud_frac_lower(k) = 0.5_core_rknd
+
+ if ( rcm(k+1) < rc_tol ) then ! Cloud top
+
+ vert_cloud_frac_upper(k) = &
+ ( ( 0.5_core_rknd / gr%invrs_dzm(k) ) / ( gr%zm(k) - gr%zt(k) ) ) &
+ * ( rcm(k) / ( rcm(k) + abs( chi_mean(k+1) ) ) )
+
+ vert_cloud_frac_upper(k) = min( 0.5_core_rknd, vert_cloud_frac_upper(k) )
+
+ ! Make the transition in cloudiness more gradual than using
+ ! the above min statement alone.
+ vert_cloud_frac_upper(k) = vert_cloud_frac_upper(k) + &
+ ( ( rcm(k+1)/rc_tol )*( 0.5_core_rknd -vert_cloud_frac_upper(k) ) )
+
+ else
+
+ vert_cloud_frac_upper(k) = 0.5_core_rknd
+
+ end if
+
+ if ( rcm(k-1) < rc_tol ) then ! Cloud base
+
+ vert_cloud_frac_lower(k) = &
+ ( ( 0.5_core_rknd / gr%invrs_dzm(k-1) ) / ( gr%zt(k) - gr%zm(k-1) ) ) &
+ * ( rcm(k) / ( rcm(k) + abs( chi_mean(k-1) ) ) )
+
+ vert_cloud_frac_lower(k) = min( 0.5_core_rknd, vert_cloud_frac_lower(k) )
+
+ ! Make the transition in cloudiness more gradual than using
+ ! the above min statement alone.
+ vert_cloud_frac_lower(k) = vert_cloud_frac_lower(k) + &
+ ( ( rcm(k-1)/rc_tol )*( 0.5_core_rknd -vert_cloud_frac_lower(k) ) )
+
+ else
+
+ vert_cloud_frac_lower(k) = 0.5_core_rknd
+
+ end if
+
+ vert_cloud_frac(k) = &
+ vert_cloud_frac_upper(k) + vert_cloud_frac_lower(k)
+
+ vert_cloud_frac(k) = &
+ max( cloud_frac(k), min( 1.0_core_rknd, vert_cloud_frac(k) ) )
+
+ cloud_cover(k) = cloud_frac(k) / vert_cloud_frac(k)
+ rcm_in_layer(k) = rcm(k) / vert_cloud_frac(k)
+
+ else
+
+ if ( clubb_at_least_debug_level( 1 ) ) then
+
+ write(fstderr,*) &
+ "Error: Should not arrive here in computation of cloud_cover"
+
+ write(fstderr,*) "At grid level k = ", k
+ write(fstderr,*) "pdf_params(k)%mixt_frac = ", pdf_params(k)%mixt_frac
+ write(fstderr,*) "pdf_params(k)%chi_1 = ", pdf_params(k)%chi_1
+ write(fstderr,*) "pdf_params(k)%chi_2 = ", pdf_params(k)%chi_2
+ write(fstderr,*) "cloud_frac(k) = ", cloud_frac(k)
+ write(fstderr,*) "rcm(k) = ", rcm(k)
+ write(fstderr,*) "rcm(k+1) = ", rcm(k+1)
+ write(fstderr,*) "rcm(k-1) = ", rcm(k-1)
+
+ end if
+
+ return
+
+ end if ! rcm(k) < rc_tol
+
+ end do ! k = 2, gr%nz-1, 1
+
+ cloud_cover(1) = cloud_frac(1)
+ cloud_cover(gr%nz) = cloud_frac(gr%nz)
+
+ rcm_in_layer(1) = rcm(1)
+ rcm_in_layer(gr%nz) = rcm(gr%nz)
+
+ return
+ end subroutine compute_cloud_cover
+ !-----------------------------------------------------------------------
+ subroutine clip_rcm &
+ ( rtm, message, & ! intent(in)
+ rcm ) ! intent(inout)
+ !
+ ! Description:
+ ! Subroutine that reduces cloud water (rcm) whenever
+ ! it exceeds total water (rtm = vapor + liquid).
+ ! This avoids negative values of rvm = water vapor mixing ratio.
+ ! However, it will not ensure that rcm <= rtm if rtm <= 0.
+ !
+ ! References:
+ ! None
+ !---------------------------------------------------------------------
+
+
+ use grid_class, only: gr ! Variable
+
+ use error_code, only : &
+ clubb_at_least_debug_level ! Procedure(s)
+
+ use constants_clubb, only: &
+ fstderr, & ! Variable(s)
+ zero_threshold
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! External functions
+ intrinsic :: max, epsilon
+
+ ! Input variables
+ real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
+ rtm ! Total water mixing ratio [kg/kg]
+
+ character(len= * ), intent(in) :: message
+
+ real( kind = core_rknd ), dimension(gr%nz), intent(inout) :: &
+ rcm ! Cloud water mixing ratio [kg/kg]
+
+ integer :: k
+
+ ! ------------ Begin code ---------------
+
+ ! Vince Larson clipped rcm in order to prevent rvm < 0. 5 Apr 2008.
+ ! This code won't work unless rtm >= 0 !!!
+ ! We do not clip rcm_in_layer because rcm_in_layer only influences
+ ! radiation, and we do not want to bother recomputing it. 6 Aug 2009
+ do k = 1, gr%nz
+ if ( rtm(k) < rcm(k) ) then
+
+ if ( clubb_at_least_debug_level(1) ) then
+ write(fstderr,*) message, ' at k=', k, 'rcm(k) = ', rcm(k), &
+ 'rtm(k) = ', rtm(k), '.', ' Clipping rcm.'
+
+ end if ! clubb_at_least_debug_level(1)
+
+ rcm(k) = max( zero_threshold, rtm(k) - epsilon( rtm(k) ) )
+
+ end if ! rtm(k) < rcm(k)
+
+ end do ! k=1..gr%nz
+
+ return
+ end subroutine clip_rcm
+
+ !-----------------------------------------------------------------------------
+ subroutine set_Lscale_max( l_implemented, host_dx, host_dy, &
+ Lscale_max )
+
+ ! Description:
+ ! This subroutine sets the value of Lscale_max, which is the maximum
+ ! allowable value of Lscale. For standard CLUBB, it is set to a very large
+ ! value so that Lscale will not be limited. However, when CLUBB is running
+ ! as part of a host model, the value of Lscale_max is dependent on the size
+ ! of the host model's horizontal grid spacing. The smaller the host model's
+ ! horizontal grid spacing, the smaller the value of Lscale_max. When Lscale
+ ! is limited to a small value, the value of time-scale Tau is reduced, which
+ ! in turn produces greater damping on CLUBB's turbulent parameters. This
+ ! is the desired effect on turbulent parameters for a host model with small
+ ! horizontal grid spacing, for small areas usually contain much less
+ ! variation in meteorological quantities than large areas.
+
+ ! References:
+ ! None
+ !-----------------------------------------------------------------------
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ logical, intent(in) :: &
+ l_implemented ! Flag to see if CLUBB is running on it's own,
+ ! or if it's implemented as part of a host model.
+
+ real( kind = core_rknd ), intent(in) :: &
+ host_dx, & ! Host model's east-west horizontal grid spacing [m]
+ host_dy ! Host model's north-south horizontal grid spacing [m]
+
+ ! Output Variable
+ real( kind = core_rknd ), intent(out) :: &
+ Lscale_max ! Maximum allowable value for Lscale [m]
+
+ ! ---- Begin Code ----
+
+ ! Determine the maximum allowable value for Lscale (in meters).
+ if ( l_implemented ) then
+ Lscale_max = 0.25_core_rknd * min( host_dx, host_dy )
+ else
+ Lscale_max = 1.0e5_core_rknd
+ end if
+
+ return
+ end subroutine set_Lscale_max
+
+!===============================================================================
+ pure subroutine calculate_thlp2_rad &
+ ( nz, rcm_zm, thlprcp, radht_zm, & ! Intent(in)
+ thlp2_forcing ) ! Intent(inout)
+
+ ! Description:
+ ! Computes the contribution of radiative cooling to thlp2
+
+ ! References:
+ ! See clubb:ticket:632
+ !----------------------------------------------------------------------
+
+ use clubb_precision, only: &
+ core_rknd ! Constant(s)
+
+ use grid_class, only: &
+ zt2zm ! Procedure
+
+ use constants_clubb, only: &
+ two, &
+ rc_tol
+
+ use parameters_tunable, only: &
+ thlp2_rad_coef ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ integer, intent(in) :: &
+ nz ! Number of vertical levels [-]
+
+ real( kind = core_rknd ), dimension(nz), intent(in) :: &
+ rcm_zm, & ! Cloud water mixing ratio on momentum grid [kg/kg]
+ thlprcp, & ! thl'rc' [K kg/kg]
+ radht_zm ! SW + LW heating rate (on momentum grid) [K/s]
+
+ ! Input/Output Variables
+ real( kind = core_rknd ), dimension(nz), intent(inout) :: &
+ thlp2_forcing ! forcing (momentum levels) [K^2/s]
+
+ ! Local Variables
+ integer :: &
+ k ! Loop iterator [-]
+
+ !----------------------------------------------------------------------
+
+
+ do k = 1, nz
+
+ if ( rcm_zm(k) > rc_tol ) then
+
+ thlp2_forcing(k) = thlp2_forcing(k) + &
+ thlp2_rad_coef * ( two ) * radht_zm(k) / rcm_zm(k) * thlprcp(k)
+
+ end if
+
+ end do
+
+
+ return
+ end subroutine calculate_thlp2_rad
+
+
+ !-----------------------------------------------------------------------
+
+end module advance_clubb_core_module
diff --git a/models/atm/cam/src/physics/clubb/advance_helper_module.F90 b/models/atm/cam/src/physics/clubb/advance_helper_module.F90
index 0abef8e02291..503877e2d1d7 100644
--- a/models/atm/cam/src/physics/clubb/advance_helper_module.F90
+++ b/models/atm/cam/src/physics/clubb/advance_helper_module.F90
@@ -1,5 +1,6 @@
!-------------------------------------------------------------------------
-! $Id: advance_helper_module.F90 5623 2012-01-17 17:55:26Z connork@uwm.edu $
+! $Id: advance_helper_module.F90 7381 2014-11-11 23:59:39Z schemena@uwm.edu $
+!===============================================================================
module advance_helper_module
! Description:
@@ -8,7 +9,10 @@ module advance_helper_module
implicit none
- public :: set_boundary_conditions_lhs, set_boundary_conditions_rhs
+ public :: &
+ set_boundary_conditions_lhs, &
+ set_boundary_conditions_rhs, &
+ calc_stability_correction
private ! Set Default Scope
@@ -30,19 +34,25 @@ subroutine set_boundary_conditions_lhs( diag_index, low_bound, high_bound, lhs,
implicit none
+ ! Exernal
+ intrinsic :: present
+
+ ! Input Variables
integer, intent(in) :: &
diag_index, low_bound, high_bound ! boundary indexes for the first variable
- integer, intent(in), optional :: &
- diag_index2, low_bound2, high_bound2 ! boundary indexes for the second variable
-
+ ! Input / Output Variables
real( kind = core_rknd ), dimension(:,:), intent(inout) :: &
lhs ! left hand side of the LAPACK matrix equation
+ ! Optional Input Variables
+ integer, intent(in), optional :: &
+ diag_index2, low_bound2, high_bound2 ! boundary indexes for the second variable
+
! --------------------- BEGIN CODE ----------------------
- if( ( present(low_bound2) .or. present(high_bound2) ) .and. &
- ( .not. present(diag_index2) ) ) then
+ if ( ( present( low_bound2 ) .or. present( high_bound2 ) ) .and. &
+ ( .not. present( diag_index2 ) ) ) then
stop "Boundary index provided without diag_index."
@@ -57,7 +67,7 @@ subroutine set_boundary_conditions_lhs( diag_index, low_bound, high_bound, lhs,
lhs(diag_index,high_bound) = 1.0_core_rknd
! Set the lower boundaries for the second variable, if it is provided
- if( present(low_bound2) ) then
+ if ( present( low_bound2 ) ) then
lhs(:,low_bound2) = 0.0_core_rknd
lhs(diag_index2,low_bound2) = 1.0_core_rknd
@@ -65,13 +75,14 @@ subroutine set_boundary_conditions_lhs( diag_index, low_bound, high_bound, lhs,
end if
! Set the upper boundaries for the second variable, if it is provided
- if( present(high_bound2) ) then
+ if ( present( high_bound2 ) ) then
lhs(:,high_bound2) = 0.0_core_rknd
lhs(diag_index2,high_bound2) = 1.0_core_rknd
end if
+ return
end subroutine set_boundary_conditions_lhs
!--------------------------------------------------------------------------
@@ -92,28 +103,38 @@ subroutine set_boundary_conditions_rhs( &
implicit none
+ ! Exernal
+ intrinsic :: present
+
+ ! Input Variables
+
! The values for the first variable
real( kind = core_rknd ), intent(in) :: low_value, high_value
! The bounds for the first variable
integer, intent(in) :: low_bound, high_bound
+ ! Input / Output Variables
+
+ ! The right-hand side vector
+ real( kind = core_rknd ), dimension(:), intent(inout) :: rhs
+
+ ! Optional Input Variables
+
! The values for the second variable
real( kind = core_rknd ), intent(in), optional :: low_value2, high_value2
! The bounds for the second variable
integer, intent(in), optional :: low_bound2, high_bound2
- ! The right-hand side vector
- real( kind = core_rknd ), dimension(:), intent(inout) :: rhs
! -------------------- BEGIN CODE ------------------------
! Stop execution if a boundary was provided without a value
- if( (present(low_bound2) .and. (.not. present(low_value2))) .or. &
- (present(high_bound2) .and. (.not. present(high_value2))) ) then
+ if ( (present( low_bound2 ) .and. (.not. present( low_value2 ))) .or. &
+ (present( high_bound2 ) .and. (.not. present( high_value2 ))) ) then
- stop "Boundary condition provided without value."
+ stop "Boundary condition provided without value."
end if
@@ -122,15 +143,75 @@ subroutine set_boundary_conditions_rhs( &
rhs(high_bound) = high_value
! If a lower bound was given for the second variable, set it
- if( present(low_bound2) ) then
+ if ( present( low_bound2 ) ) then
rhs(low_bound2) = low_value2
end if
! If an upper bound was given for the second variable, set it
- if( present(high_bound2) ) then
+ if ( present( high_bound2 ) ) then
rhs(high_bound2) = high_value2
end if
+ return
end subroutine set_boundary_conditions_rhs
+ !===============================================================================
+ function calc_stability_correction( thlm, Lscale, em ) &
+ result ( stability_correction )
+ !
+ ! Description:
+ ! Stability Factor
+ !
+ ! References:
+ !
+ !--------------------------------------------------------------------
+
+ use parameters_model, only: &
+ T0 ! Variables(s)
+
+ use constants_clubb, only: &
+ zero, & ! Constant(s)
+ grav
+
+ use grid_class, only: &
+ gr, & ! Variable(s)
+ zt2zm, & ! Procedure(s)
+ ddzt
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+ implicit none
+
+ ! Input Variables
+ real( kind = core_rknd ), intent(in), dimension(gr%nz) :: &
+ Lscale, & ! Turbulent mixing length [m]
+ em, & ! Turbulent Kinetic Energy (TKE) [m^2/s^2]
+ thlm ! th_l (thermo. levels) [K]
+
+ ! Result
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ stability_correction
+
+ ! Local Variables
+ real( kind = core_rknd ) :: &
+ lambda0_stability_coef ! []
+
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ brunt_vaisala_freq, & ! []
+ lambda0_stability
+
+ !------------ Begin Code --------------
+ ! lambda0_stability_coef = 0.025_core_rknd
+ ! changed to 0.030 to provide a simulation similar to track02 simulation
+ lambda0_stability_coef = 0.030_core_rknd
+ brunt_vaisala_freq = ( grav / T0 ) * ddzt( thlm )
+ lambda0_stability = merge( lambda0_stability_coef, zero, brunt_vaisala_freq > zero )
+
+ stability_correction = 1.0_core_rknd &
+ + min( lambda0_stability * brunt_vaisala_freq * zt2zm( Lscale )**2 / em, 3.0_core_rknd )
+
+ return
+ end function calc_stability_correction
+
end module advance_helper_module
diff --git a/models/atm/cam/src/physics/clubb/advance_windm_edsclrm_module.F90 b/models/atm/cam/src/physics/clubb/advance_windm_edsclrm_module.F90
index d328ed76c016..90ae4f2c7f3e 100644
--- a/models/atm/cam/src/physics/clubb/advance_windm_edsclrm_module.F90
+++ b/models/atm/cam/src/physics/clubb/advance_windm_edsclrm_module.F90
@@ -1,5 +1,5 @@
!------------------------------------------------------------------------
-! $Id: advance_windm_edsclrm_module.F90 5623 2012-01-17 17:55:26Z connork@uwm.edu $
+! $Id: advance_windm_edsclrm_module.F90 7315 2014-09-30 20:49:54Z schemena@uwm.edu $
!===============================================================================
module advance_windm_edsclrm_module
@@ -7,13 +7,13 @@ module advance_windm_edsclrm_module
private ! Set Default Scope
- public :: advance_windm_edsclrm
+ public :: advance_windm_edsclrm, xpwp_fnc
private :: windm_edsclrm_solve, &
compute_uv_tndcy, &
windm_edsclrm_lhs, &
- windm_edsclrm_rhs, &
- xpwp_fnc
+ windm_edsclrm_rhs
+
! Private named constants to avoid string comparisons
integer, parameter, private :: &
@@ -31,7 +31,7 @@ module advance_windm_edsclrm_module
!=============================================================================
subroutine advance_windm_edsclrm &
- ( dt, wm_zt, Kh_zm, ug, vg, um_ref, vm_ref, &
+ ( dt, wm_zt, Km_zm, ug, vg, um_ref, vm_ref, &
wp2, up2, vp2, um_forcing, vm_forcing, &
edsclrm_forcing, &
rho_ds_zm, invrs_rho_ds_zt, &
@@ -69,10 +69,9 @@ subroutine advance_windm_edsclrm &
l_tke_aniso
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update, & ! Subroutines
stat_end_update, &
stat_update_var
@@ -85,7 +84,7 @@ subroutine advance_windm_edsclrm &
ium_ndg, &
ivm_ndg, &
iwindm_matrix_condt_num, &
- zt, &
+ stats_zt, &
l_stats_samp
use clip_explicit, only: &
@@ -96,8 +95,7 @@ subroutine advance_windm_edsclrm &
fatal_error
use error_code, only: &
- clubb_no_error, & ! Constant(s)
- clubb_singular_matrix
+ clubb_no_error ! Constant(s)
use constants_clubb, only: &
fstderr, & ! Constant(s)
@@ -118,23 +116,23 @@ subroutine advance_windm_edsclrm &
dummy_nu ! Used to feed zero values into function calls
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
- wm_zt, & ! w wind component on thermodynamic levels [m/s]
- Kh_zm, & ! Eddy diffusivity on momentum levels [m^2/s]
- ug, & ! u (west-to-east) geostrophic wind comp. [m/s]
- vg, & ! v (south-to-north) geostrophic wind comp. [m/s]
- um_ref, & ! Reference u wind component for nudging [m/s]
- vm_ref, & ! Reference v wind component for nudging [m/s]
- wp2, & ! w'^2 (momentum levels) [m^2/s^2]
- up2, & ! u'^2 (momentum levels) [m^2/s^2]
- vp2, & ! v'^2 (momentum levels) [m^2/s^2]
- um_forcing, & ! u forcing [m/s/s]
- vm_forcing, & ! v forcing [m/s/s]
- rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
- invrs_rho_ds_zt ! Inv. dry, static density at thermo. levels [m^3/kg]
+ wm_zt, & ! w wind component on thermodynamic levels [m/s]
+ Km_zm, & ! Eddy diffusivity of winds on momentum levels [m^2/s]
+ ug, & ! u (west-to-east) geostrophic wind comp. [m/s]
+ vg, & ! v (south-to-north) geostrophic wind comp. [m/s]
+ um_ref, & ! Reference u wind component for nudging [m/s]
+ vm_ref, & ! Reference v wind component for nudging [m/s]
+ wp2, & ! w'^2 (momentum levels) [m^2/s^2]
+ up2, & ! u'^2 (momentum levels) [m^2/s^2]
+ vp2, & ! v'^2 (momentum levels) [m^2/s^2]
+ um_forcing, & ! u forcing [m/s/s]
+ vm_forcing, & ! v forcing [m/s/s]
+ rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
+ invrs_rho_ds_zt ! Inv. dry, static density at thermo. levels [m^3/kg]
real( kind = core_rknd ), dimension(gr%nz,edsclr_dim), intent(in) :: &
edsclrm_forcing ! Eddy scalar large-scale forcing [{units vary}/s]
@@ -192,9 +190,10 @@ subroutine advance_windm_edsclrm &
l_imp_sfc_momentum_flux ! Flag for implicit momentum surface fluxes.
integer :: &
- err_code_windm, err_code_edsclrm ! Error code for each LAPACK solve
+ err_code_windm, err_code_edsclrm, & ! Error code for each LAPACK solve
+ nrhs ! Number of right hand side terms
- integer :: i ! Array index
+ integer :: i ! Array index
logical :: l_first_clip_ts, l_last_clip_ts ! flags for clip_covar
@@ -231,17 +230,19 @@ subroutine advance_windm_edsclrm &
! Compute the explicit portion of the um equation.
! Build the right-hand side vector.
- rhs(1:gr%nz,1) = windm_edsclrm_rhs( windm_edsclrm_um, dt, nu10_vert_res_dep, Kh_zm, um, & ! in
- um_tndcy, & ! in
- rho_ds_zm, invrs_rho_ds_zt, & ! in
- l_imp_sfc_momentum_flux, upwp(1) ) ! in
+ rhs(1:gr%nz,windm_edsclrm_um) &
+ = windm_edsclrm_rhs( windm_edsclrm_um, dt, nu10_vert_res_dep, Km_zm, um, & ! in
+ um_tndcy, & ! in
+ rho_ds_zm, invrs_rho_ds_zt, & ! in
+ l_imp_sfc_momentum_flux, upwp(1) ) ! in
! Compute the explicit portion of the vm equation.
! Build the right-hand side vector.
- rhs(1:gr%nz,2) = windm_edsclrm_rhs( windm_edsclrm_vm, dt, nu10_vert_res_dep, Kh_zm, vm, & ! in
- vm_tndcy, & ! in
- rho_ds_zm, invrs_rho_ds_zt, & ! in
- l_imp_sfc_momentum_flux, vpwp(1) ) ! in
+ rhs(1:gr%nz,windm_edsclrm_vm) &
+ = windm_edsclrm_rhs( windm_edsclrm_vm, dt, nu10_vert_res_dep, Km_zm, vm, & ! in
+ vm_tndcy, & ! in
+ rho_ds_zm, invrs_rho_ds_zt, & ! in
+ l_imp_sfc_momentum_flux, vpwp(1) ) ! in
! Store momentum flux (explicit component)
@@ -253,12 +254,12 @@ subroutine advance_windm_edsclrm &
! Solve for x'w' at all intermediate model levels.
! A Crank-Nicholson timestep is used.
- upwp(2:gr%nz-1) = - 0.5_core_rknd * xpwp_fnc( Kh_zm(2:gr%nz-1)+ &
+ upwp(2:gr%nz-1) = - 0.5_core_rknd * xpwp_fnc( Km_zm(2:gr%nz-1)+ &
nu10_vert_res_dep(2:gr%nz-1), & ! in
um(2:gr%nz-1), um(3:gr%nz), & ! in
gr%invrs_dzm(2:gr%nz-1) )
- vpwp(2:gr%nz-1) = - 0.5_core_rknd * xpwp_fnc( Kh_zm(2:gr%nz-1)+ &
+ vpwp(2:gr%nz-1) = - 0.5_core_rknd * xpwp_fnc( Km_zm(2:gr%nz-1)+ &
nu10_vert_res_dep(2:gr%nz-1), & ! in
vm(2:gr%nz-1), vm(3:gr%nz), & ! in
gr%invrs_dzm(2:gr%nz-1) )
@@ -272,25 +273,26 @@ subroutine advance_windm_edsclrm &
! Compute the implicit portion of the um and vm equations.
! Build the left-hand side matrix.
- call windm_edsclrm_lhs( dt, nu10_vert_res_dep, wm_zt, Kh_zm, wind_speed, u_star_sqd, & ! in
+ call windm_edsclrm_lhs( dt, nu10_vert_res_dep, wm_zt, Km_zm, wind_speed, u_star_sqd, & ! in
rho_ds_zm, invrs_rho_ds_zt, & ! in
l_implemented, l_imp_sfc_momentum_flux, & ! in
lhs ) ! out
! Decompose and back substitute for um and vm
- call windm_edsclrm_solve( 2, iwindm_matrix_condt_num, & ! in
- lhs, rhs, & ! in/out
- solution, err_code_windm ) ! out
+ nrhs = 2
+ call windm_edsclrm_solve( nrhs, iwindm_matrix_condt_num, & ! in
+ lhs, rhs, & ! in/out
+ solution, err_code_windm ) ! out
!----------------------------------------------------------------
! Update zonal (west-to-east) component of mean wind, um
!----------------------------------------------------------------
- um(1:gr%nz) = solution(1:gr%nz,1)
+ um(1:gr%nz) = solution(1:gr%nz,windm_edsclrm_um)
!----------------------------------------------------------------
! Update meridional (south-to-north) component of mean wind, vm
!----------------------------------------------------------------
- vm(1:gr%nz) = solution(1:gr%nz,2)
+ vm(1:gr%nz) = solution(1:gr%nz,windm_edsclrm_vm)
if ( l_stats_samp ) then
@@ -313,8 +315,8 @@ subroutine advance_windm_edsclrm &
if ( uv_sponge_damp_settings%l_sponge_damping ) then
if( l_stats_samp ) then
- call stat_begin_update( ium_sdmp, um/real( dt, kind = core_rknd ), zt )
- call stat_begin_update( ivm_sdmp, vm/real( dt, kind = core_rknd ), zt )
+ call stat_begin_update( ium_sdmp, um/dt, stats_zt )
+ call stat_begin_update( ivm_sdmp, vm/dt, stats_zt )
endif
um(1:gr%nz) = sponge_damp_xm( dt, um_ref(1:gr%nz), um(1:gr%nz), &
@@ -322,8 +324,8 @@ subroutine advance_windm_edsclrm &
vm(1:gr%nz) = sponge_damp_xm( dt, vm_ref(1:gr%nz), vm(1:gr%nz), &
uv_sponge_damp_profile )
if( l_stats_samp ) then
- call stat_end_update( ium_sdmp, um/real( dt, kind = core_rknd ), zt )
- call stat_end_update( ivm_sdmp, vm/real( dt, kind = core_rknd ), zt )
+ call stat_end_update( ium_sdmp, um/dt, stats_zt )
+ call stat_end_update( ivm_sdmp, vm/dt, stats_zt )
endif
endif
@@ -334,11 +336,11 @@ subroutine advance_windm_edsclrm &
! A Crank-Nicholson timestep is used.
upwp(2:gr%nz-1) = upwp(2:gr%nz-1) &
- - 0.5_core_rknd * xpwp_fnc( Kh_zm(2:gr%nz-1)+nu10_vert_res_dep(2:gr%nz-1), &
+ - 0.5_core_rknd * xpwp_fnc( Km_zm(2:gr%nz-1)+nu10_vert_res_dep(2:gr%nz-1), &
um(2:gr%nz-1), um(3:gr%nz), gr%invrs_dzm(2:gr%nz-1) ) !in
vpwp(2:gr%nz-1) = vpwp(2:gr%nz-1) &
- - 0.5_core_rknd * xpwp_fnc( Kh_zm(2:gr%nz-1)+nu10_vert_res_dep(2:gr%nz-1), &
+ - 0.5_core_rknd * xpwp_fnc( Km_zm(2:gr%nz-1)+nu10_vert_res_dep(2:gr%nz-1), &
vm(2:gr%nz-1), vm(3:gr%nz), gr%invrs_dzm(2:gr%nz-1) ) !in
@@ -347,30 +349,30 @@ subroutine advance_windm_edsclrm &
! Reflect nudging in budget
if( l_stats_samp ) then
- call stat_begin_update( ium_ndg, um / real( dt, kind = core_rknd ), & ! Intent(in)
- zt ) ! Intent(inout)
- call stat_begin_update( ivm_ndg, vm / real( dt, kind = core_rknd ), & ! Intent(in)
- zt ) ! Intent(inout)
+ call stat_begin_update( ium_ndg, um / dt, & ! Intent(in)
+ stats_zt ) ! Intent(inout)
+ call stat_begin_update( ivm_ndg, vm / dt, & ! Intent(in)
+ stats_zt ) ! Intent(inout)
end if
um(1:gr%nz) = um(1:gr%nz) &
- - ((um(1:gr%nz) - um_ref(1:gr%nz)) * (real( dt, kind = core_rknd )/ts_nudge))
+ - ((um(1:gr%nz) - um_ref(1:gr%nz)) * (dt/ts_nudge))
vm(1:gr%nz) = vm(1:gr%nz) &
- - ((vm(1:gr%nz) - vm_ref(1:gr%nz)) * (real( dt, kind = core_rknd )/ts_nudge))
+ - ((vm(1:gr%nz) - vm_ref(1:gr%nz)) * (dt/ts_nudge))
endif
if( l_stats_samp ) then
! Reflect nudging in budget
if ( l_uv_nudge ) then
- call stat_end_update( ium_ndg, um / real( dt, kind = core_rknd ), & ! Intent(in)
- zt ) ! Intent(inout)
- call stat_end_update( ivm_ndg, vm / real( dt, kind = core_rknd ), & ! Intent(in)
- zt ) ! Intent(inout)
+ call stat_end_update( ium_ndg, um / dt, & ! Intent(in)
+ stats_zt ) ! Intent(inout)
+ call stat_end_update( ivm_ndg, vm / dt, & ! Intent(in)
+ stats_zt ) ! Intent(inout)
end if
- call stat_update_var( ium_ref, um_ref, zt )
- call stat_update_var( ivm_ref, vm_ref, zt )
+ call stat_update_var( ium_ref, um_ref, stats_zt )
+ call stat_update_var( ivm_ref, vm_ref, stats_zt )
end if
if ( l_tke_aniso ) then
@@ -444,7 +446,7 @@ subroutine advance_windm_edsclrm &
!HPF$ INDEPENDENT
do i = 1, edsclr_dim
rhs(1:gr%nz,i) &
- = windm_edsclrm_rhs( windm_edsclrm_scalar, dt, dummy_nu, Kh_zm, & ! in
+ = windm_edsclrm_rhs( windm_edsclrm_scalar, dt, dummy_nu, Km_zm, & ! in
edsclrm(:,i), edsclrm_forcing, & ! in
rho_ds_zm, invrs_rho_ds_zt, & ! in
l_imp_sfc_momentum_flux, wpedsclrp(1,i) ) ! in
@@ -463,7 +465,7 @@ subroutine advance_windm_edsclrm &
!HPF$ INDEPENDENT, REDUCTION(wpedsclrp)
forall( i = 1:edsclr_dim )
wpedsclrp(2:gr%nz-1,i) = &
- - 0.5_core_rknd * xpwp_fnc( Kh_zm(2:gr%nz-1), edsclrm(2:gr%nz-1,i), & ! in
+ - 0.5_core_rknd * xpwp_fnc( Km_zm(2:gr%nz-1), edsclrm(2:gr%nz-1,i), & ! in
edsclrm(3:gr%nz,i), gr%invrs_dzm(2:gr%nz-1) ) ! in
end forall
@@ -475,7 +477,7 @@ subroutine advance_windm_edsclrm &
! Compute the implicit portion of the xm (eddy-scalar) equations.
! Build the left-hand side matrix.
- call windm_edsclrm_lhs( dt, dummy_nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, & ! in
+ call windm_edsclrm_lhs( dt, dummy_nu, wm_zt, Km_zm, wind_speed, u_star_sqd, & ! in
rho_ds_zm, invrs_rho_ds_zt, & ! in
l_implemented, l_imp_sfc_momentum_flux, & ! in
lhs ) ! out
@@ -504,7 +506,7 @@ subroutine advance_windm_edsclrm &
!HPF$ INDEPENDENT, REDUCTION(wpedsclrp)
forall( i = 1:edsclr_dim )
wpedsclrp(2:gr%nz-1,i) = wpedsclrp(2:gr%nz-1,i) &
- - 0.5_core_rknd * xpwp_fnc( Kh_zm(2:gr%nz-1), edsclrm(2:gr%nz-1,i), & ! in
+ - 0.5_core_rknd * xpwp_fnc( Km_zm(2:gr%nz-1), edsclrm(2:gr%nz-1,i), & ! in
edsclrm(3:gr%nz,i), gr%invrs_dzm(2:gr%nz-1) ) ! in
end forall
@@ -539,7 +541,7 @@ subroutine advance_windm_edsclrm &
write(fstderr,*) "dt = ", dt
write(fstderr,*) "wm_zt = ", wm_zt
- write(fstderr,*) "Kh_zm = ", Kh_zm
+ write(fstderr,*) "Km_zm = ", Km_zm
write(fstderr,*) "ug = ", ug
write(fstderr,*) "vg = ", vg
write(fstderr,*) "um_ref = ", um_ref
@@ -1082,15 +1084,12 @@ subroutine windm_edsclrm_solve( nrhs, ixm_matrix_condt_num, &
tridag_solvex
use stats_variables, only: &
- sfc, & ! Variable(s)
+ stats_sfc, & ! Variable(s)
l_stats_samp
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_update_var_pt ! Subroutine
- use constants_clubb, only: &
- fstderr ! Variable(s)
-
use clubb_precision, only: &
core_rknd ! Variable(s)
@@ -1106,8 +1105,7 @@ subroutine windm_edsclrm_solve( nrhs, ixm_matrix_condt_num, &
! Input Variables
integer, intent(in) :: &
- nrhs ! Number of right-hand side (explicit) vectors.
- ! Number of solution vectors.
+ nrhs ! Number of right-hand side (explicit) vectors & Number of solution vectors.
integer, intent(in) :: &
ixm_matrix_condt_num ! Stats index of the condition numbers
@@ -1131,16 +1129,16 @@ subroutine windm_edsclrm_solve( nrhs, ixm_matrix_condt_num, &
! Solve tridiagonal system for xm.
if ( l_stats_samp .and. ixm_matrix_condt_num > 0 ) then
call tridag_solvex &
- ( "windm_edsclrm", gr%nz, nrhs, & ! Intent(in)
+ ( "windm_edsclrm", gr%nz, nrhs, & ! Intent(in)
lhs(kp1_tdiag,:), lhs(k_tdiag,:), lhs(km1_tdiag,:), rhs, & ! Intent(inout)
solution, rcond, err_code ) ! Intent(out)
! Est. of the condition number of the variance LHS matrix
- call stat_update_var_pt( ixm_matrix_condt_num, 1, 1.0_core_rknd / rcond, & ! Intent(in)
- sfc ) ! Intent(inout)
+ call stat_update_var_pt( ixm_matrix_condt_num, 1, 1.0_core_rknd/rcond, & ! Intent(in)
+ stats_sfc ) ! Intent(inout)
else
- call tridag_solve( "windm_edsclrm", gr%nz, nrhs, & ! In
+ call tridag_solve( "windm_edsclrm", gr%nz, nrhs, & ! In
lhs(kp1_tdiag,:), lhs(k_tdiag,:), lhs(km1_tdiag,:), rhs, & ! Inout
solution, err_code ) ! Out
end if
@@ -1169,17 +1167,13 @@ subroutine windm_edsclrm_implicit_stats( solve_type, xm )
ztscr04, &
ztscr05, &
ztscr06, &
- zt
+ stats_zt
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_end_update_pt, & ! Subroutines
stat_update_var_pt
- use constants_clubb, only: &
- fstderr ! Variable(s)
-
use clubb_precision, only: &
- time_precision, & ! Variable(s)
core_rknd
use grid_class, only: &
@@ -1228,7 +1222,7 @@ subroutine windm_edsclrm_implicit_stats( solve_type, xm )
call stat_update_var_pt( ixm_ma, k, &
ztscr01(k) * xm(km1) &
+ ztscr02(k) * xm(k) &
- + ztscr03(k) * xm(kp1), zt )
+ + ztscr03(k) * xm(kp1), stats_zt )
! xm turbulent transport (implicit component)
! xm term ta has both implicit and explicit components;
@@ -1236,7 +1230,7 @@ subroutine windm_edsclrm_implicit_stats( solve_type, xm )
call stat_end_update_pt( ixm_ta, k, &
ztscr04(k) * xm(km1) &
+ ztscr05(k) * xm(k) &
- + ztscr06(k) * xm(kp1), zt )
+ + ztscr06(k) * xm(kp1), stats_zt )
enddo
@@ -1249,14 +1243,14 @@ subroutine windm_edsclrm_implicit_stats( solve_type, xm )
! xm term ma is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( ixm_ma, k, &
ztscr01(k) * xm(km1) &
- + ztscr02(k) * xm(k), zt )
+ + ztscr02(k) * xm(k), stats_zt )
! xm turbulent transport (implicit component)
! xm term ta has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( ixm_ta, k, &
ztscr04(k) * xm(km1) &
- + ztscr05(k) * xm(k), zt )
+ + ztscr05(k) * xm(k), stats_zt )
return
@@ -1296,7 +1290,7 @@ subroutine compute_uv_tndcy( solve_type, fcor, perp_wind_m, perp_wind_g, xm_forc
use grid_class, only: &
gr
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_update_var
use stats_variables, only: &
@@ -1306,7 +1300,7 @@ subroutine compute_uv_tndcy( solve_type, fcor, perp_wind_m, perp_wind_g, xm_forc
ivm_cf, &
ium_f, &
ivm_f, &
- zt, &
+ stats_zt, &
l_stats_samp
use clubb_precision, only: &
@@ -1390,13 +1384,13 @@ subroutine compute_uv_tndcy( solve_type, fcor, perp_wind_m, perp_wind_g, xm_forc
if ( l_stats_samp ) then
! xm term gf is completely explicit; call stat_update_var.
- call stat_update_var( ixm_gf, xm_gf, zt )
+ call stat_update_var( ixm_gf, xm_gf, stats_zt )
! xm term cf is completely explicit; call stat_update_var.
- call stat_update_var( ixm_cf, xm_cf, zt )
+ call stat_update_var( ixm_cf, xm_cf, stats_zt )
! xm term F
- call stat_update_var( ixm_f, xm_forcing, zt )
+ call stat_update_var( ixm_f, xm_forcing, stats_zt )
endif
else ! implemented in a host model.
@@ -1410,7 +1404,7 @@ subroutine compute_uv_tndcy( solve_type, fcor, perp_wind_m, perp_wind_g, xm_forc
end subroutine compute_uv_tndcy
!===============================================================================
- subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
+ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Km_zm, wind_speed, u_star_sqd, &
rho_ds_zm, invrs_rho_ds_zt, &
l_implemented, l_imp_sfc_momentum_flux, &
lhs )
@@ -1428,8 +1422,7 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
gr ! Variable(s)
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use diffusion, only: &
diffusion_zt_lhs ! Procedure(s)
@@ -1459,7 +1452,7 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
km1_tdiag = 3 ! Thermodynamic subdiagonal index.
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
@@ -1467,7 +1460,7 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
wm_zt, & ! w wind component on thermodynamic levels [m/s]
- Kh_zm, & ! Eddy diffusivity on momentum levels [m^2/s]
+ Km_zm, & ! Eddy diffusivity on momentum levels [m^2/s]
wind_speed, & ! wind speed; sqrt( u^2 + v^2 ) [m/s]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
invrs_rho_ds_zt ! Inv. dry, static density at thermo. levels [m^3/kg]
@@ -1491,7 +1484,7 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
! --- Begin Code ---
- ! Initialize the LHS array.
+ ! Initialize the LHS array to zero.
lhs = 0.0_core_rknd
do k = 2, gr%nz, 1
@@ -1507,7 +1500,7 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
+ term_ma_zt_lhs( wm_zt(k), gr%invrs_dzt(k), k, gr%invrs_dzm(k), gr%invrs_dzm(km1) )
else
-
+ ! The host model is assumed to apply the advection term to the mean elsewhere in this case.
lhs(kp1_tdiag:km1_tdiag,k) &
= lhs(kp1_tdiag:km1_tdiag,k) + 0.0_core_rknd
@@ -1531,18 +1524,19 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
lhs(kp1_tdiag:km1_tdiag,k) &
= lhs(kp1_tdiag:km1_tdiag,k) &
+ 0.5_core_rknd * invrs_rho_ds_zt(k) &
- * diffusion_zt_lhs( rho_ds_zm(k) * Kh_zm(k), &
- rho_ds_zm(km1) * Kh_zm(km1), nu, &
+ * diffusion_zt_lhs( rho_ds_zm(k) * Km_zm(k), &
+ rho_ds_zm(km1) * Km_zm(km1), nu, &
gr%invrs_dzm(km1), gr%invrs_dzm(k), &
gr%invrs_dzt(k), diff_k_in )
! LHS time tendency.
lhs(k_tdiag,k) &
- = lhs(k_tdiag,k) + 1.0_core_rknd / real( dt, kind = core_rknd )
+ = lhs(k_tdiag,k) + 1.0_core_rknd / dt
if ( l_stats_samp ) then
! Statistics: implicit contributions for um or vm.
+ ! Note: we don't track these budgets for the eddy scalar variables
if ( ium_ma + ivm_ma > 0 ) then
if ( .not. l_implemented ) then
@@ -1561,8 +1555,8 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
if ( ium_ta + ivm_ta > 0 ) then
tmp(1:3) &
= 0.5_core_rknd * invrs_rho_ds_zt(k) &
- * diffusion_zt_lhs( rho_ds_zm(k) * Kh_zm(k), &
- rho_ds_zm(km1) * Kh_zm(km1), nu, &
+ * diffusion_zt_lhs( rho_ds_zm(k) * Km_zm(k), &
+ rho_ds_zm(km1) * Km_zm(km1), nu, &
gr%invrs_dzm(km1), gr%invrs_dzm(k), &
gr%invrs_dzt(k), diff_k_in )
ztscr04(k) = -tmp(3)
@@ -1625,7 +1619,7 @@ subroutine windm_edsclrm_lhs( dt, nu, wm_zt, Kh_zm, wind_speed, u_star_sqd, &
end subroutine windm_edsclrm_lhs
!=============================================================================
- function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
+ function windm_edsclrm_rhs( solve_type, dt, nu, Km_zm, xm, xm_tndcy, &
rho_ds_zm, invrs_rho_ds_zt, &
l_imp_sfc_momentum_flux, xpwp_sfc ) &
result( rhs )
@@ -1640,8 +1634,7 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
!-----------------------------------------------------------------------
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use diffusion, only: &
diffusion_zt_lhs ! Procedure(s)
@@ -1649,10 +1642,10 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
use stats_variables, only: &
ium_ta, & ! Variable(s)
ivm_ta, &
- zt, &
+ stats_zt, &
l_stats_samp
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update_pt, & ! Procedure(s)
stat_modify_pt
@@ -1668,14 +1661,14 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
integer, intent(in) :: &
solve_type ! Description of what is being solved for
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
nu ! Background constant coef. of eddy diffusivity [m^2/s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
- Kh_zm, & ! Eddy diffusivity on momentum levels [m^2/s]
+ Km_zm, & ! Eddy diffusivity on momentum levels [m^2/s]
xm, & ! Eddy-scalar variable, xm (thermo. levels) [units vary]
xm_tndcy, & ! The explicit time-tendency acting on xm [units vary]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
@@ -1738,8 +1731,8 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
endif
rhs_diff(1:3) &
= 0.5_core_rknd * invrs_rho_ds_zt(k) &
- * diffusion_zt_lhs( rho_ds_zm(k) * Kh_zm(k), &
- rho_ds_zm(km1) * Kh_zm(km1), nu, &
+ * diffusion_zt_lhs( rho_ds_zm(k) * Km_zm(k), &
+ rho_ds_zm(km1) * Km_zm(km1), nu, &
gr%invrs_dzm(km1), gr%invrs_dzm(k), &
gr%invrs_dzt(k), diff_k_in )
rhs(k) = rhs(k) &
@@ -1751,7 +1744,7 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
rhs(k) = rhs(k) + xm_tndcy(k)
! RHS time tendency
- rhs(k) = rhs(k) + 1.0_core_rknd / real ( dt, kind = core_rknd ) * xm(k)
+ rhs(k) = rhs(k) + 1.0_core_rknd / dt * xm(k)
if ( l_stats_samp ) then
@@ -1765,7 +1758,7 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
call stat_begin_update_pt( ixm_ta, k, &
rhs_diff(3) * xm(km1) &
+ rhs_diff(2) * xm(k) &
- + rhs_diff(1) * xm(kp1), zt )
+ + rhs_diff(1) * xm(kp1), stats_zt )
endif
endif ! l_stats_samp
@@ -1811,7 +1804,7 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
+ invrs_rho_ds_zt(2) &
* gr%invrs_dzt(2) &
* rho_ds_zm(1) * xpwp_sfc, &
- zt )
+ stats_zt )
endif
endif ! l_stats_samp
@@ -1831,8 +1824,8 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
! upper boundary.
rhs_diff(1:3) &
= 0.5_core_rknd * invrs_rho_ds_zt(k) &
- * diffusion_zt_lhs( rho_ds_zm(k) * Kh_zm(k), &
- rho_ds_zm(km1) * Kh_zm(km1), nu, &
+ * diffusion_zt_lhs( rho_ds_zm(k) * Km_zm(k), &
+ rho_ds_zm(km1) * Km_zm(km1), nu, &
gr%invrs_dzm(km1), gr%invrs_dzm(k), &
gr%invrs_dzt(k), k )
rhs(k) = rhs(k) &
@@ -1843,7 +1836,7 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
rhs(k) = rhs(k) + xm_tndcy(k)
! RHS time tendency term at the upper boundary.
- rhs(k) = rhs(k) + 1.0_core_rknd / real( dt, kind = core_rknd ) * xm(k)
+ rhs(k) = rhs(k) + 1.0_core_rknd / dt * xm(k)
if ( l_stats_samp ) then
@@ -1856,7 +1849,7 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
if ( ixm_ta > 0 ) then
call stat_begin_update_pt( ixm_ta, k, &
rhs_diff(3) * xm(km1) &
- + rhs_diff(2) * xm(k), zt )
+ + rhs_diff(2) * xm(k), stats_zt )
endif
endif ! l_stats_samp
@@ -1866,7 +1859,7 @@ function windm_edsclrm_rhs( solve_type, dt, nu, Kh_zm, xm, xm_tndcy, &
end function windm_edsclrm_rhs
!===============================================================================
- elemental function xpwp_fnc( Kh_zm, xm, xmp1, invrs_dzm )
+ elemental function xpwp_fnc( Km_zm, xm, xmp1, invrs_dzm )
! Description:
! Compute x'w' from x, x, Kh and invrs_dzm
@@ -1882,7 +1875,7 @@ elemental function xpwp_fnc( Kh_zm, xm, xmp1, invrs_dzm )
! Input variables
real( kind = core_rknd ), intent(in) :: &
- Kh_zm, & ! Eddy diff. (k momentum level) [m^2/s]
+ Km_zm, & ! Eddy diff. (k momentum level) [m^2/s]
xm, & ! x (k thermo level) [units vary]
xmp1, & ! x (k+1 thermo level) [units vary]
invrs_dzm ! Inverse of the grid spacing (k thermo level) [1/m]
@@ -1895,7 +1888,7 @@ elemental function xpwp_fnc( Kh_zm, xm, xmp1, invrs_dzm )
! --- Begin Code ---
! Solve for x'w' at all intermediate model levels.
- xpwp_fnc = Kh_zm * invrs_dzm * ( xmp1 - xm )
+ xpwp_fnc = Km_zm * invrs_dzm * ( xmp1 - xm )
return
end function xpwp_fnc
diff --git a/models/atm/cam/src/physics/clubb/advance_wp2_wp3_module.F90 b/models/atm/cam/src/physics/clubb/advance_wp2_wp3_module.F90
index 46f5073f332c..2d55d44266c5 100644
--- a/models/atm/cam/src/physics/clubb/advance_wp2_wp3_module.F90
+++ b/models/atm/cam/src/physics/clubb/advance_wp2_wp3_module.F90
@@ -1,5 +1,5 @@
!------------------------------------------------------------------------
-! $Id: advance_wp2_wp3_module.F90 5623 2012-01-17 17:55:26Z connork@uwm.edu $
+! $Id: advance_wp2_wp3_module.F90 7380 2014-11-11 20:34:25Z schemena@uwm.edu $
!===============================================================================
module advance_wp2_wp3_module
@@ -41,9 +41,9 @@ module advance_wp2_wp3_module
subroutine advance_wp2_wp3( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
a3, a3_zt, wp3_on_wp2, &
wpthvp, wp2thvp, um, vm, upwp, vpwp, &
- up2, vp2, Kh_zm, Kh_zt, tau_zm, tau_zt, &
+ up2, vp2, Kh_zm, Kh_zt, tau_zm, tau_zt, tau_C1_zm, &
Skw_zm, Skw_zt, rho_ds_zm, rho_ds_zt, &
- invrs_rho_ds_zm, invrs_rho_ds_zt, &
+ invrs_rho_ds_zm, invrs_rho_ds_zt, radf, &
thv_ds_zm, thv_ds_zt, mixt_frac, &
wp2, wp3, wp3_zm, wp2_zt, err_code )
@@ -76,36 +76,35 @@ subroutine advance_wp2_wp3( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
c_K1, &
c_K8
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_update_var
use stats_variables, only: &
iC1_Skw_fnc, &
iC11_Skw_fnc, &
- zm, &
- zt, &
+ stats_zm, &
+ stats_zt, &
l_stats_samp
use constants_clubb, only: &
fstderr ! Variable(s)
- use model_flags, only: &
- l_hyper_dfsn ! Variable(s)
-
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use error_code, only: &
fatal_error, & ! Procedure(s)
clubb_at_least_debug_level
+ use error_code, only: &
+ clubb_var_out_of_range ! Constant(s)
+
implicit none
intrinsic :: exp
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
real( kind = core_rknd ), intent(in) :: &
@@ -130,12 +129,14 @@ subroutine advance_wp2_wp3( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
Kh_zt, & ! Eddy diffusivity on thermodynamic levels [m^2/s]
tau_zm, & ! Time-scale tau on momentum levels [s]
tau_zt, & ! Time-scale tau on thermodynamic levels [s]
+ tau_C1_zm, & ! Tau values used for the C1 (dp1) term in wp2 [s]
Skw_zm, & ! Skewness of w on momentum levels [-]
Skw_zt, & ! Skewness of w on thermodynamic levels [-]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
rho_ds_zt, & ! Dry, static density on thermo. levels [kg/m^3]
invrs_rho_ds_zm, & ! Inv. dry, static density @ momentum levs. [m^3/kg]
invrs_rho_ds_zt, & ! Inv. dry, static density @ thermo. levs. [m^3/kg]
+ radf, & ! Buoyancy production at the CL top [m^2/s^3]
thv_ds_zm, & ! Dry, base-state theta_v on momentum levs. [K]
thv_ds_zt, & ! Dry, base-state theta_v on thermo. levs. [K]
mixt_frac ! Weight of 1st normal distribution [-]
@@ -216,10 +217,6 @@ subroutine advance_wp2_wp3( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
C11_Skw_fnc(1:gr%nz) = C11b
end if
-#ifdef CLUBB_CAM
- C11_Skw_fnc(1:gr%nz) = 0.65_core_rknd
-#endif
-
! The if..then here is only for computational efficiency -dschanen 2 Sept 08
if ( C1 /= C1b ) then
C1_Skw_fnc(1:gr%nz) = &
@@ -231,9 +228,18 @@ subroutine advance_wp2_wp3( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
!C11_Skw_fnc = C11
!C1_Skw_fnc = C1
+ if ( clubb_at_least_debug_level( 2 ) ) then
+ ! Assertion check for C11_Skw_fnc
+ if ( any( C11_Skw_fnc(:) > 1._core_rknd ) .or. any( C11_Skw_fnc(:) < 0._core_rknd ) ) then
+ write(fstderr,*) "The C11_Skw_fnc is outside the valid range for this variable"
+ err_code = clubb_var_out_of_range
+ return
+ end if
+ end if
+
if ( l_stats_samp ) then
- call stat_update_var( iC11_Skw_fnc, C11_Skw_fnc, zt )
- call stat_update_var( iC1_Skw_fnc, C1_Skw_fnc, zm )
+ call stat_update_var( iC11_Skw_fnc, C11_Skw_fnc, stats_zt )
+ call stat_update_var( iC1_Skw_fnc, C1_Skw_fnc, stats_zm )
endif
! Define the Coefficent of Eddy Diffusivity for the wp2 and wp3.
@@ -252,26 +258,19 @@ subroutine advance_wp2_wp3( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
enddo
- ! Declare the number of subdiagonals and superdiagonals in the LHS matrix.
- if ( l_hyper_dfsn ) then
- ! There are nine overall diagonals (including four subdiagonals
- ! and four superdiagonals).
- nsub = 4
- nsup = 4
- else
- ! There are five overall diagonals (including two subdiagonals
- ! and two superdiagonals).
- nsub = 2
- nsup = 2
- endif
+ ! There are five overall diagonals (including two subdiagonals
+ ! and two superdiagonals).
+ nsub = 2
+ nsup = 2
+
! Solve semi-implicitly
call wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, & ! Intent(in)
a3, a3_zt, wp3_on_wp2, & ! Intent(in)
wpthvp, wp2thvp, um, vm, upwp, vpwp, & ! Intent(in)
- up2, vp2, Kw1, Kw8, Kh_zt, Skw_zt, tau_zm, tauw3t, & ! Intent(in)
+ up2, vp2, Kw1, Kw8, Kh_zt, Skw_zt, tau_zm, tauw3t, tau_C1_zm, & ! Intent(in)
C1_Skw_fnc, C11_Skw_fnc, rho_ds_zm, rho_ds_zt, & ! Intent(in)
- invrs_rho_ds_zm, invrs_rho_ds_zt, thv_ds_zm, & ! Intent(in)
+ invrs_rho_ds_zm, invrs_rho_ds_zt, radf, thv_ds_zm, & ! Intent(in)
thv_ds_zt, nsub, nsup, & ! Intent(in)
wp2, wp3, wp3_zm, wp2_zt, wp2_wp3_err_code ) ! Intent(inout)
@@ -324,9 +323,9 @@ end subroutine advance_wp2_wp3
subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
a3, a3_zt, wp3_on_wp2, &
wpthvp, wp2thvp, um, vm, upwp, vpwp, &
- up2, vp2, Kw1, Kw8, Kh_zt, Skw_zt, tau1m, tauw3t, &
+ up2, vp2, Kw1, Kw8, Kh_zt, Skw_zt, tau1m, tauw3t, tau_C1_zm, &
C1_Skw_fnc, C11_Skw_fnc, rho_ds_zm, rho_ds_zt, &
- invrs_rho_ds_zm, invrs_rho_ds_zt, thv_ds_zm, &
+ invrs_rho_ds_zm, invrs_rho_ds_zt, radf, thv_ds_zm, &
thv_ds_zt, nsub, nsup, &
wp2, wp3, wp3_zm, wp2_zt, err_code )
@@ -347,41 +346,37 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
use constants_clubb, only: &
w_tol_sqd, & ! Variables(s)
- eps, &
- zero_threshold, &
- fstderr
+ zero_threshold
use model_flags, only: &
l_tke_aniso, & ! Variable(s)
- l_hyper_dfsn, &
l_hole_fill, &
l_gmres
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use lapack_wrap, only: &
band_solve, & ! Procedure(s)
band_solvex
use fill_holes, only: &
- fill_holes_driver
+ fill_holes_vertical
use clip_explicit, only: &
clip_variance, & ! Procedure(s)
clip_skewness
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update, & ! Procedure(s)
stat_update_var_pt, &
stat_end_update, &
stat_end_update_pt
use stats_variables, only: &
- zm, & ! Variable(s)
- zt, &
- sfc, &
+ stats_zm, & ! Variable(s)
+ stats_zt, &
+ stats_sfc, &
l_stats_samp, &
iwp2_ta, &
iwp2_ma, &
@@ -391,7 +386,6 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
iwp2_dp2, &
iwp2_pr1, &
iwp2_pr2, &
- iwp2_4hd, &
iwp3_ta, &
iwp3_ma, &
iwp3_tp, &
@@ -399,7 +393,6 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
iwp3_dp1, &
iwp3_pr1, &
iwp3_pr2, &
- iwp3_4hd, &
iwp23_matrix_condt_num
use stats_variables, only: &
@@ -415,13 +408,10 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
zmscr10, &
zmscr11, &
zmscr12, &
- zmscr13, &
- zmscr14, &
- zmscr15, &
- zmscr16, &
- zmscr17, &
ztscr01, &
- ztscr02, &
+ ztscr02
+
+ use stats_variables, only: &
ztscr03, &
ztscr04, &
ztscr05, &
@@ -435,12 +425,7 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
ztscr13, &
ztscr14, &
ztscr15, &
- ztscr16, &
- ztscr17, &
- ztscr18, &
- ztscr19, &
- ztscr20, &
- ztscr21
+ ztscr16
implicit none
@@ -452,7 +437,7 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
nrhs = 1 ! Number of RHS vectors
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep [s]
real( kind = core_rknd ), intent(in) :: &
@@ -479,12 +464,14 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
Skw_zt, & ! Skewness of w on thermodynamic levels [-]
tau1m, & ! Time-scale tau on momentum levels [s]
tauw3t, & ! Time-scale tau on thermodynamic levels [s]
+ tau_C1_zm, & ! Tau values used for the C1 (dp1) term in wp2 [s]
C1_Skw_fnc, & ! C_1 parameter with Sk_w applied [-]
C11_Skw_fnc, & ! C_11 parameter with Sk_w applied [-]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
rho_ds_zt, & ! Dry, static density on thermo. levels [kg/m^3]
invrs_rho_ds_zm, & ! Inv. dry, static density @ momentum levs. [m^3/kg]
invrs_rho_ds_zt, & ! Inv. dry, static density @ thermo. levs. [m^3/kg]
+ radf, & ! Buoyancy production at CL top [m^2/s^3]
thv_ds_zm, & ! Dry, base-state theta_v on momentum levs. [K]
thv_ds_zt ! Dry, base-state theta_v on thermo. levs. [K]
@@ -525,7 +512,7 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
rcond ! Est. of the reciprocal of the condition #
! Array indices
- integer :: k, km1, km2, kp1, kp2, k_wp2, k_wp3
+ integer :: k, km1, kp1, k_wp2, k_wp3
! Set logical to true for Crank-Nicholson diffusion scheme
! or to false for completely implicit diffusion scheme.
@@ -552,15 +539,15 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
call wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
a3, a3_zt, wp3_on_wp2, wpthvp, wp2thvp, um, vm, &
upwp, vpwp, up2, vp2, Kw1, Kw8, Kh_zt, &
- Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
- C11_Skw_fnc, rho_ds_zm, invrs_rho_ds_zt, &
+ Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
+ C11_Skw_fnc, rho_ds_zm, invrs_rho_ds_zt, radf, &
thv_ds_zm, thv_ds_zt, l_crank_nich_diff, &
rhs )
if (l_gmres) then
call wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, nsup, nsub, nrhs, &
rhs, &
@@ -570,7 +557,7 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
! Build the left-hand side matrix.
call wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, nsub, nsup, &
lhs )
@@ -584,7 +571,7 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
lhs, rhs, solut, rcond, err_code )
! Est. of the condition number of the w'^2/w^3 LHS matrix
- call stat_update_var_pt( iwp23_matrix_condt_num, 1, 1.0_core_rknd / rcond, sfc )
+ call stat_update_var_pt( iwp23_matrix_condt_num, 1, 1.0_core_rknd / rcond, stats_sfc )
else
! Perform LU decomp and solve system (LAPACK)
@@ -611,21 +598,19 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
end do
- if (l_stats_samp) then
+ if ( l_stats_samp ) then
! Finalize implicit contributions for wp2
do k = 2, gr%nz-1
km1 = max( k-1, 1 )
- km2 = max( k-2, 1 )
kp1 = min( k+1, gr%nz )
- kp2 = min( k+2, gr%nz )
! w'^2 term dp1 has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( iwp2_dp1, k, &
- zmscr01(k) * wp2(k), zm )
+ zmscr01(k) * wp2(k), stats_zm )
! w'^2 term dp2 has both implicit and explicit components (if the
! Crank-Nicholson scheme is selected); call stat_end_update_pt.
@@ -635,50 +620,41 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
call stat_end_update_pt( iwp2_dp2, k, &
zmscr02(k) * wp2(km1) &
+ zmscr03(k) * wp2(k) &
- + zmscr04(k) * wp2(kp1), zm )
+ + zmscr04(k) * wp2(kp1), stats_zm )
else
call stat_update_var_pt( iwp2_dp2, k, &
zmscr02(k) * wp2(km1) &
+ zmscr03(k) * wp2(k) &
- + zmscr04(k) * wp2(kp1), zm )
+ + zmscr04(k) * wp2(kp1), stats_zm )
endif
! w'^2 term ta is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwp2_ta, k, &
zmscr05(k) * wp3(k) &
- + zmscr06(k) * wp3(kp1), zm )
+ + zmscr06(k) * wp3(kp1), stats_zm )
! w'^2 term ma is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwp2_ma, k, &
zmscr07(k) * wp2(km1) &
+ zmscr08(k) * wp2(k) &
- + zmscr09(k) * wp2(kp1), zm )
+ + zmscr09(k) * wp2(kp1), stats_zm )
! w'^2 term ac is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwp2_ac, k, &
- zmscr10(k) * wp2(k), zm )
+ zmscr10(k) * wp2(k), stats_zm )
! w'^2 term pr1 has both implicit and explicit components;
! call stat_end_update_pt.
if ( l_tke_aniso ) then
call stat_end_update_pt( iwp2_pr1, k, &
- zmscr12(k) * wp2(k), zm )
+ zmscr12(k) * wp2(k), stats_zm )
endif
! w'^2 term pr2 has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( iwp2_pr2, k, &
- zmscr11(k) * wp2(k), zm )
-
- ! w'^2 term 4hd is completely implicit; call stat_update_var_pt.
- if ( l_hyper_dfsn ) then
- call stat_update_var_pt( iwp2_4hd, k, &
- zmscr13(k) * wp2(km2) &
- + zmscr14(k) * wp2(km1) &
- + zmscr15(k) * wp2(k) &
- + zmscr16(k) * wp2(kp1) &
- + zmscr17(k) * wp2(kp2), zm )
- endif
+ zmscr11(k) * wp2(k), stats_zm )
+
enddo
! Finalize implicit contributions for wp3
@@ -686,14 +662,12 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
do k = 2, gr%nz-1, 1
km1 = max( k-1, 1 )
- km2 = max( k-2, 1 )
kp1 = min( k+1, gr%nz )
- kp2 = min( k+2, gr%nz )
! w'^3 term pr1 has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( iwp3_pr1, k, &
- ztscr01(k) * wp3(k), zt )
+ ztscr01(k) * wp3(k), stats_zt )
! w'^3 term dp1 has both implicit and explicit components (if the
! Crank-Nicholson scheme is selected); call stat_end_update_pt.
@@ -703,12 +677,12 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
call stat_end_update_pt( iwp3_dp1, k, &
ztscr02(k) * wp3(km1) &
+ ztscr03(k) * wp3(k) &
- + ztscr04(k) * wp3(kp1), zt )
+ + ztscr04(k) * wp3(kp1), stats_zt )
else
call stat_update_var_pt( iwp3_dp1, k, &
ztscr02(k) * wp3(km1) &
+ ztscr03(k) * wp3(k) &
- + ztscr04(k) * wp3(kp1), zt )
+ + ztscr04(k) * wp3(kp1), stats_zt )
endif
! w'^3 term ta has both implicit and explicit components;
@@ -718,38 +692,29 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
+ ztscr06(k) * wp2(km1) &
+ ztscr07(k) * wp3(k) &
+ ztscr08(k) * wp2(k) &
- + ztscr09(k) * wp3(kp1), zt )
+ + ztscr09(k) * wp3(kp1), stats_zt )
! w'^3 term tp has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( iwp3_tp, k, &
ztscr10(k) * wp2(km1) &
- + ztscr11(k) * wp2(k), zt )
+ + ztscr11(k) * wp2(k), stats_zt )
! w'^3 term ma is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwp3_ma, k, &
ztscr12(k) * wp3(km1) &
+ ztscr13(k) * wp3(k) &
- + ztscr14(k) * wp3(kp1), zt )
+ + ztscr14(k) * wp3(kp1), stats_zt )
! w'^3 term ac is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwp3_ac, k, &
- ztscr15(k) * wp3(k), zt )
+ ztscr15(k) * wp3(k), stats_zt )
! w'^3 term pr2 has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( iwp3_pr2, k, &
- ztscr16(k) * wp3(k), zt )
-
- ! w'^3 term 4hd is completely implicit; call stat_update_var_pt.
- if ( l_hyper_dfsn ) then
- call stat_update_var_pt( iwp3_4hd, k, &
- ztscr17(k) * wp3(km2) &
- + ztscr18(k) * wp3(km1) &
- + ztscr19(k) * wp3(k) &
- + ztscr20(k) * wp3(kp1) &
- + ztscr21(k) * wp3(kp2), zt )
- endif
+ ztscr16(k) * wp3(k), stats_zt )
+
enddo
endif ! l_stats_samp
@@ -757,15 +722,15 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
if ( l_stats_samp ) then
! Store previous value for effect of the positive definite scheme
- call stat_begin_update( iwp2_pd, wp2 / real( dt, kind = core_rknd ), zm )
+ call stat_begin_update( iwp2_pd, wp2 / dt, stats_zm )
endif
if ( l_hole_fill .and. any( wp2 < w_tol_sqd ) ) then
! Use a simple hole filling algorithm
- call fill_holes_driver( 2, w_tol_sqd, "zm", &
- rho_ds_zt, rho_ds_zm, &
- wp2 )
+ call fill_holes_vertical( 2, w_tol_sqd, "zm", &
+ rho_ds_zt, rho_ds_zm, &
+ wp2 )
endif ! wp2
@@ -777,7 +742,7 @@ subroutine wp23_solve( dt, sfc_elevation, sigma_sqd_w, wm_zm, wm_zt, &
if ( l_stats_samp ) then
! Store updated value for effect of the positive definite scheme
- call stat_end_update( iwp2_pd, wp2 / real( dt, kind = core_rknd ), zm )
+ call stat_end_update( iwp2_pd, wp2 / dt, stats_zm )
endif
@@ -800,7 +765,7 @@ end subroutine wp23_solve
subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, nsup, nsub, nrhs, &
rhs, &
@@ -817,8 +782,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
gr ! Variable(s)
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
#ifdef MKL
use error_code, only: &
@@ -827,7 +791,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
use stats_variables, only: &
iwp23_matrix_condt_num, & ! Variable(s)
l_stats_samp, &
- sfc
+ stats_sfc
use constants_clubb, only: &
fstderr ! Variable(s)
@@ -836,10 +800,10 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
band_solve, & ! Procedure(s)
band_solvex
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_update_var_pt ! Procedure(s)
- use csr_matrix_class, only: &
+ use csr_matrix_module, only: &
csr_intlc_5b_5b_ia, & ! Variables
csr_intlc_5b_5b_ja, &
intlc_5d_5d_ja_size
@@ -860,7 +824,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
implicit none
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
@@ -879,6 +843,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
Skw_zt, & ! Skewness of w on thermodynamic levels [-]
tau1m, & ! Time-scale tau on momentum levels [s]
tauw3t, & ! Time-scale tau on thermodynamic levels [s]
+ tau_C1_zm, & ! Tau values used for the C1 (dp1) term in wp2 [s]
C1_Skw_fnc, & ! C_1 parameter with Sk_w applied [-]
C11_Skw_fnc, & ! C_11 parameter with Sk_w applied [-]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
@@ -922,14 +887,9 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! Begin code
- if (nsup > 2) then
- write (fstderr, *) "WARNING: CSR-format solvers currently do not", &
- "support solving with hyper diffusion", &
- "at this time. l_hyper_dfsn ignored."
- end if
call wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, &
lhs_a_csr )
@@ -937,7 +897,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
if ( .not. l_gmres_soln_ok(gmres_idx_wp2wp3) ) then
call wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, nsub, nsup, &
lhs )
@@ -969,7 +929,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! Generate the LHS in LAPACK format
call wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, nsub, nsup, &
lhs )
@@ -985,7 +945,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
lhs, rhs, solut, rcond, err_code )
! Est. of the condition number of the w'^2/w^3 LHS matrix
- call stat_update_var_pt( iwp23_matrix_condt_num, 1, 1.0_core_rknd / rcond, sfc )
+ call stat_update_var_pt( iwp23_matrix_condt_num, 1, 1.0_core_rknd / rcond, stats_sfc )
else
! Perform LU decomp and solve system (LAPACK)
@@ -1016,6 +976,7 @@ subroutine wp23_gmres( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
solut(1:gr%nz) = Skw_zt
solut(1:gr%nz) = tau1m
solut(1:gr%nz) = tauw3t
+ solut(1:gr%nz) = tau_C1_zm
solut(1:gr%nz) = wm_zt
solut(1:gr%nz) = wm_zm
solut(1:gr%nz) = wp2
@@ -1032,7 +993,7 @@ end subroutine wp23_gmres
!=============================================================================
subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, nsub, nsup, &
lhs )
@@ -1059,17 +1020,14 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
C8b, &
C12, &
nu1_vert_res_dep, &
- nu8_vert_res_dep, &
- nu_hd_vert_res_dep
+ nu8_vert_res_dep
use constants_clubb, only: &
- eps, & ! Variable(s)
three_halves, &
gamma_over_implicit_ts
use model_flags, only: &
- l_tke_aniso, & ! Variable(s)
- l_hyper_dfsn
+ l_tke_aniso ! Variable(s)
use diffusion, only: &
diffusion_zm_lhs, & ! Procedures
@@ -1079,12 +1037,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
term_ma_zm_lhs, & ! Procedures
term_ma_zt_lhs
- use hyper_diffusion_4th_ord, only: &
- hyper_dfsn_4th_ord_zm_lhs, &
- hyper_dfsn_4th_ord_zt_lhs
-
use clubb_precision, only: &
- time_precision, &
core_rknd
use stats_variables, only: &
@@ -1100,13 +1053,10 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
zmscr11, &
zmscr10, &
zmscr12, &
- zmscr13, &
- zmscr14, &
- zmscr15, &
- zmscr16, &
- zmscr17, &
ztscr01, &
- ztscr02, &
+ ztscr02
+
+ use stats_variables, only: &
ztscr03, &
ztscr04, &
ztscr05, &
@@ -1120,12 +1070,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
ztscr13, &
ztscr14, &
ztscr15, &
- ztscr16, &
- ztscr17, &
- ztscr18, &
- ztscr19, &
- ztscr20, &
- ztscr21
+ ztscr16
use stats_variables, only: &
l_stats_samp, &
@@ -1136,15 +1081,13 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
iwp2_ac, &
iwp2_pr2, &
iwp2_pr1, &
- iwp2_4hd, &
iwp3_ta, &
iwp3_tp, &
iwp3_ma, &
iwp3_ac, &
iwp3_pr2, &
iwp3_pr1, &
- iwp3_dp1, &
- iwp3_4hd
+ iwp3_dp1
use advance_helper_module, only: set_boundary_conditions_lhs ! Procedure(s)
@@ -1154,31 +1097,27 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! Left-hand side matrix diagonal identifiers for
! momentum-level variable, w'^2.
integer, parameter :: &
- m_kp2_mdiag = 1, & ! Momentum super-super diagonal index for w'^2.
!m_kp2_tdiag = 2, & ! Thermodynamic super-super diagonal index for w'^2.
m_kp1_mdiag = 3, & ! Momentum super diagonal index for w'^2.
m_kp1_tdiag = 4, & ! Thermodynamic super diagonal index for w'^2.
m_k_mdiag = 5, & ! Momentum main diagonal index for w'^2.
m_k_tdiag = 6, & ! Thermodynamic sub diagonal index for w'^2.
- m_km1_mdiag = 7, & ! Momentum sub diagonal index for w'^2.
+ m_km1_mdiag = 7 ! Momentum sub diagonal index for w'^2.
!m_km1_tdiag = 8, & ! Thermodynamic sub-sub diagonal index for w'^2.
- m_km2_mdiag = 9 ! Momentum sub-sub diagonal index for w'^2.
! Left-hand side matrix diagonal identifiers for
! thermodynamic-level variable, w'^3.
integer, parameter :: &
- t_kp2_tdiag = 1, & ! Thermodynamic super-super diagonal index for w'^3.
!t_kp1_mdiag = 2, & ! Momentum super-super diagonal index for w'^3.
t_kp1_tdiag = 3, & ! Thermodynamic super diagonal index for w'^3.
!t_k_mdiag = 4, & ! Momentum super diagonal index for w'^3.
t_k_tdiag = 5, & ! Thermodynamic main diagonal index for w'^3.
!t_km1_mdiag = 6, & ! Momentum sub diagonal index for w'^3.
- t_km1_tdiag = 7, & ! Thermodynamic sub diagonal index for w'^3.
+ t_km1_tdiag = 7 ! Thermodynamic sub diagonal index for w'^3.
!t_km2_mdiag = 8, & ! Momentum sub-sub diagonal index for w'^3.
- t_km2_tdiag = 9 ! Thermodynamic sub-sub diagonal index for w'^3.
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep length [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
@@ -1195,6 +1134,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
Skw_zt, & ! Skewness of w on thermodynamic levels [-]
tau1m, & ! Time-scale tau on momentum levels [s]
tauw3t, & ! Time-scale tau on thermodynamic levels [s]
+ tau_C1_zm, & ! Tau values used for the C1 (dp1) term in wp2 [s]
C1_Skw_fnc, & ! C_1 parameter with Sk_w applied [-]
C11_Skw_fnc, & ! C_11 parameter with Sk_w applied [-]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
@@ -1208,7 +1148,6 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
integer, intent(in) :: &
nsub, & ! Number of subdiagonals in the LHS matrix.
nsup ! Number of superdiagonals in the LHS matrix.
-
! Output Variable
real( kind = core_rknd ), dimension(5-nsup:5+nsub,2*gr%nz), intent(out) :: &
lhs ! Implicit contributions to wp2/wp3 (band diag. matrix)
@@ -1216,7 +1155,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! Local Variables
! Array indices
- integer :: k, km1, km2, kp1, kp2, k_wp2, k_wp3, k_wp2_low, k_wp2_high, &
+ integer :: k, km1, kp1, k_wp2, k_wp3, k_wp2_low, k_wp2_high, &
k_wp3_low, k_wp3_high
real( kind = core_rknd ), dimension(5) :: tmp
@@ -1230,9 +1169,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! Define indices
km1 = max( k-1, 1 )
- km2 = max( k-2, 1 )
kp1 = min( k+1, gr%nz )
- kp2 = min( k+2, gr%nz )
k_wp3 = 2*k - 1
k_wp2 = 2*k
@@ -1260,10 +1197,9 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! [ x wp3(k+2,) ]
! Momentum super-super diagonal (lhs index: m_kp2_mdiag)
! [ x wp2(k+2,) ]
-
! LHS time tendency.
lhs(m_k_mdiag,k_wp2) &
- = + 1.0_core_rknd / real( dt, kind = core_rknd )
+ = + 1.0_core_rknd / dt
! LHS mean advection (ma) term.
lhs((/m_kp1_mdiag,m_k_mdiag,m_km1_mdiag/),k_wp2) &
@@ -1289,7 +1225,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
lhs(m_k_mdiag,k_wp2) &
= lhs(m_k_mdiag,k_wp2) &
+ gamma_over_implicit_ts &
- * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau1m(k) )
+ * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau_C1_zm(k) )
! LHS eddy diffusion term: dissipation term 2 (dp2).
if ( l_crank_nich_diff ) then
@@ -1322,19 +1258,6 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
* wp2_term_pr1_lhs( C4, tau1m(k) )
endif
- ! LHS 4th-order hyper-diffusion (4hd).
- if ( l_hyper_dfsn ) then
- ! Note: w'^2 uses fixed-point boundary conditions.
- lhs( (/m_kp2_mdiag,m_kp1_mdiag,m_k_mdiag,m_km1_mdiag,m_km2_mdiag/), &
- k_wp2 ) &
- = lhs( (/m_kp2_mdiag,m_kp1_mdiag,m_k_mdiag,m_km1_mdiag,m_km2_mdiag/), &
- k_wp2 ) &
- + hyper_dfsn_4th_ord_zm_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzm(k), &
- gr%invrs_dzt(kp1), gr%invrs_dzt(k), &
- gr%invrs_dzm(kp1), gr%invrs_dzm(km1), &
- gr%invrs_dzt(kp2), gr%invrs_dzt(km1), k )
- endif
-
if ( l_stats_samp ) then
! Statistics: implicit contributions for wp2.
@@ -1346,7 +1269,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
if ( iwp2_dp1 > 0 ) then
zmscr01(k) &
= - gamma_over_implicit_ts &
- * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau1m(k) )
+ * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau_C1_zm(k) )
endif
if ( iwp2_dp2 > 0 ) then
@@ -1412,19 +1335,6 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
* wp2_term_pr1_lhs( C4, tau1m(k) )
endif
- if ( iwp2_4hd > 0 .and. l_hyper_dfsn ) then
- tmp(1:5) = &
- hyper_dfsn_4th_ord_zm_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzm(k), &
- gr%invrs_dzt(kp1), gr%invrs_dzt(k), &
- gr%invrs_dzm(kp1), gr%invrs_dzm(km1), &
- gr%invrs_dzt(kp2), gr%invrs_dzt(km1), k )
- zmscr13(k) = -tmp(5)
- zmscr14(k) = -tmp(4)
- zmscr15(k) = -tmp(3)
- zmscr16(k) = -tmp(2)
- zmscr17(k) = -tmp(1)
- endif
-
endif
@@ -1454,7 +1364,7 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! LHS time tendency.
lhs(t_k_tdiag,k_wp3) &
- = + 1.0_core_rknd / real( dt, kind = core_rknd )
+ = + 1.0_core_rknd / dt
! LHS mean advection (ma) term.
lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k_wp3) &
@@ -1520,19 +1430,6 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
gr%invrs_dzt(k), k )
endif
- ! LHS 4th-order hyper-diffusion (4hd).
- if ( l_hyper_dfsn ) then
- ! Note: w'^3 uses fixed-point boundary conditions.
- lhs( (/t_kp2_tdiag,t_kp1_tdiag,t_k_tdiag,t_km1_tdiag,t_km2_tdiag/), &
- k_wp3 ) &
- = lhs( (/t_kp2_tdiag,t_kp1_tdiag,t_k_tdiag,t_km1_tdiag,t_km2_tdiag/), &
- k_wp3 ) &
- + hyper_dfsn_4th_ord_zt_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzt(k), &
- gr%invrs_dzm(k), gr%invrs_dzm(km1), &
- gr%invrs_dzt(kp1), gr%invrs_dzt(km1), &
- gr%invrs_dzm(kp1), gr%invrs_dzm(km2), k )
- endif
-
if ( l_stats_samp ) then
! Statistics: implicit contributions for wp3.
@@ -1643,19 +1540,6 @@ subroutine wp23_lhs( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
endif
- if ( iwp3_4hd > 0 .and. l_hyper_dfsn ) then
- tmp(1:5) = &
- hyper_dfsn_4th_ord_zt_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzt(k), &
- gr%invrs_dzm(k), gr%invrs_dzm(km1), &
- gr%invrs_dzt(kp1), gr%invrs_dzt(km1), &
- gr%invrs_dzm(kp1), gr%invrs_dzm(km2), k )
- ztscr17(k) = -tmp(5)
- ztscr18(k) = -tmp(4)
- ztscr19(k) = -tmp(3)
- ztscr20(k) = -tmp(2)
- ztscr21(k) = -tmp(1)
- endif
-
endif
enddo ! k = 2, gr%nz-1, 1
@@ -1701,7 +1585,7 @@ end subroutine wp23_lhs
!=============================================================================
subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
wp3_on_wp2, &
- Kw1, Kw8, Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
+ Kw1, Kw8, Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
C11_Skw_fnc, rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, l_crank_nich_diff, &
lhs_a_csr )
@@ -1730,8 +1614,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
C8b, &
C12, &
nu1_vert_res_dep, &
- nu8_vert_res_dep, &
- nu_hd_vert_res_dep
+ nu8_vert_res_dep
use constants_clubb, only: &
eps, & ! Variable(s)
@@ -1739,8 +1622,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
gamma_over_implicit_ts
use model_flags, only: &
- l_tke_aniso, & ! Variable(s)
- l_hyper_dfsn
+ l_tke_aniso ! Variable(s)
use diffusion, only: &
diffusion_zm_lhs, & ! Procedures
@@ -1750,12 +1632,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
term_ma_zm_lhs, & ! Procedures
term_ma_zt_lhs
- use hyper_diffusion_4th_ord, only: &
- hyper_dfsn_4th_ord_zm_lhs, &
- hyper_dfsn_4th_ord_zt_lhs
-
use clubb_precision, only: &
- time_precision, &
core_rknd
use stats_variables, only: &
@@ -1771,13 +1648,10 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
zmscr11, &
zmscr10, &
zmscr12, &
- zmscr13, &
- zmscr14, &
- zmscr15, &
- zmscr16, &
- zmscr17, &
ztscr01, &
- ztscr02, &
+ ztscr02
+
+ use stats_variables, only: &
ztscr03, &
ztscr04, &
ztscr05, &
@@ -1791,12 +1665,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
ztscr13, &
ztscr14, &
ztscr15, &
- ztscr16, &
- ztscr17, &
- ztscr18, &
- ztscr19, &
- ztscr20, &
- ztscr21
+ ztscr16
use stats_variables, only: &
l_stats_samp, &
@@ -1807,17 +1676,15 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
iwp2_ac, &
iwp2_pr2, &
iwp2_pr1, &
- iwp2_4hd, &
iwp3_ta, &
iwp3_tp, &
iwp3_ma, &
iwp3_ac, &
iwp3_pr2, &
iwp3_pr1, &
- iwp3_dp1, &
- iwp3_4hd
+ iwp3_dp1
- use csr_matrix_class, only: &
+ use csr_matrix_module, only: &
intlc_5d_5d_ja_size ! Variable
implicit none
@@ -1853,7 +1720,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
!t_km2_tdiag ! Thermodynamic sub-sub diagonal index for w'^3.
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep length [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
@@ -1870,6 +1737,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
Skw_zt, & ! Skewness of w on thermodynamic levels [-]
tau1m, & ! Time-scale tau on momentum levels [s]
tauw3t, & ! Time-scale tau on thermodynamic levels [s]
+ tau_C1_zm, & ! Tau values used for the C1 (dp1) term in wp2 [s]
C1_Skw_fnc, & ! C_1 parameter with Sk_w applied [-]
C11_Skw_fnc, & ! C_11 parameter with Sk_w applied [-]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
@@ -1891,7 +1759,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! Local Variables
! Array indices
- integer :: k, km1, km2, kp1, kp2, k_wp2, k_wp3, wp2_cur_row, wp3_cur_row
+ integer :: k, km1, kp1, k_wp2, k_wp3, wp2_cur_row, wp3_cur_row
real( kind = core_rknd ), dimension(5) :: tmp
@@ -1904,9 +1772,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
! Define indices
km1 = max( k-1, 1 )
- km2 = max( k-2, 1 )
kp1 = min( k+1, gr%nz )
- kp2 = min( k+2, gr%nz )
k_wp3 = 2*k - 1
k_wp2 = 2*k
@@ -1996,7 +1862,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
lhs_a_csr(m_k_mdiag) &
= lhs_a_csr(m_k_mdiag) &
+ gamma_over_implicit_ts &
- * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau1m(k) )
+ * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau_C1_zm(k) )
! LHS eddy diffusion term: dissipation term 2 (dp2).
if ( l_crank_nich_diff ) then
@@ -2029,21 +1895,6 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
* wp2_term_pr1_lhs( C4, tau1m(k) )
endif
- ! LHS 4th-order hyper-diffusion (4hd).
- ! NOTE: 4th-order hyper-diffusion is not yet supported in CSR-format.
- ! As such, this needs to remain commented out.
- !if ( l_hyper_dfsn ) then
- ! ! Note: w'^2 uses fixed-point boundary conditions.
- ! lhs( (/m_kp2_mdiag,m_kp1_mdiag,m_k_mdiag,m_km1_mdiag,m_km2_mdiag/), &
- ! k_wp2) &
- ! = lhs( (/m_kp2_mdiag,m_kp1_mdiag,m_k_mdiag,m_km1_mdiag,m_km2_mdiag/), &
- ! k_wp2) &
- ! + hyper_dfsn_4th_ord_zm_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzm(k), &
- ! gr%invrs_dzt(kp1), gr%invrs_dzt(k), &
- ! gr%invrs_dzm(kp1), gr%invrs_dzm(km1), &
- ! gr%invrs_dzt(kp2), gr%invrs_dzt(km1), k )
- !endif
-
if ( l_stats_samp ) then
! Statistics: implicit contributions for wp2.
@@ -2055,7 +1906,7 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
if ( iwp2_dp1 > 0 ) then
zmscr01(k) &
= - gamma_over_implicit_ts &
- * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau1m(k) )
+ * wp2_term_dp1_lhs( C1_Skw_fnc(k), tau_C1_zm(k) )
endif
if ( iwp2_dp2 > 0 ) then
@@ -2121,19 +1972,6 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
* wp2_term_pr1_lhs( C4, tau1m(k) )
endif
- if ( iwp2_4hd > 0 .and. l_hyper_dfsn ) then
- tmp(1:5) = &
- hyper_dfsn_4th_ord_zm_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzm(k), &
- gr%invrs_dzt(kp1), gr%invrs_dzt(k), &
- gr%invrs_dzm(kp1), gr%invrs_dzm(km1), &
- gr%invrs_dzt(kp2), gr%invrs_dzt(km1), k )
- zmscr13(k) = -tmp(5)
- zmscr14(k) = -tmp(4)
- zmscr15(k) = -tmp(3)
- zmscr16(k) = -tmp(2)
- zmscr17(k) = -tmp(1)
- endif
-
endif
@@ -2260,20 +2098,6 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
gr%invrs_dzt(k), k )
endif
- ! LHS 4th-order hyper-diffusion (4hd).
- ! NOTE: 4th-order hyper-diffusion is not yet supported in CSR-format.
- ! As such, this needs to remain commented out.
- !if ( l_hyper_dfsn ) then
- ! ! Note: w'^3 uses fixed-point boundary conditions.
- ! lhs( (/t_kp2_tdiag,t_kp1_tdiag,t_k_tdiag,t_km1_tdiag,t_km2_tdiag/), &
- ! k_wp3) &
- ! = lhs( (/t_kp2_tdiag,t_kp1_tdiag,t_k_tdiag,t_km1_tdiag,t_km2_tdiag/), &
- ! k_wp3) &
- ! + hyper_dfsn_4th_ord_zt_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzt(k), &
- ! gr%invrs_dzm(k), gr%invrs_dzm(km1), &
- ! gr%invrs_dzt(kp1), gr%invrs_dzt(km1), &
- ! gr%invrs_dzm(kp1), gr%invrs_dzm(km2), k )
- !endif
if (l_stats_samp) then
@@ -2385,19 +2209,6 @@ subroutine wp23_lhs_csr( dt, wp2, wm_zm, wm_zt, a1, a1_zt, a3, a3_zt, &
endif
- if ( iwp3_4hd > 0 .and. l_hyper_dfsn ) then
- tmp(1:5) = &
- hyper_dfsn_4th_ord_zt_lhs( 'fixed-point', nu_hd_vert_res_dep, gr%invrs_dzt(k), &
- gr%invrs_dzm(k), gr%invrs_dzm(km1), &
- gr%invrs_dzt(kp1), gr%invrs_dzt(km1), &
- gr%invrs_dzm(kp1), gr%invrs_dzm(km2), k )
- ztscr17(k) = -tmp(5)
- ztscr18(k) = -tmp(4)
- ztscr19(k) = -tmp(3)
- ztscr20(k) = -tmp(2)
- ztscr21(k) = -tmp(1)
- endif
-
endif
enddo ! k = 2, gr%nz-1, 1
@@ -2472,8 +2283,8 @@ end subroutine wp23_lhs_csr
subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
a3, a3_zt, wp3_on_wp2, wpthvp, wp2thvp, um, vm, &
upwp, vpwp, up2, vp2, Kw1, Kw8, Kh_zt, &
- Skw_zt, tau1m, tauw3t, C1_Skw_fnc, &
- C11_Skw_fnc, rho_ds_zm, invrs_rho_ds_zt, &
+ Skw_zt, tau1m, tauw3t, tau_C1_zm, C1_Skw_fnc, &
+ C11_Skw_fnc, rho_ds_zm, invrs_rho_ds_zt, radf, &
thv_ds_zm, thv_ds_zt, l_crank_nich_diff, &
rhs )
@@ -2503,7 +2314,6 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
use constants_clubb, only: &
w_tol_sqd, & ! Variable(s)
- eps, &
three_halves, &
gamma_over_implicit_ts
@@ -2515,15 +2325,14 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
diffusion_zt_lhs
use clubb_precision, only: &
- time_precision, & ! Variable
- core_rknd
+ core_rknd ! Variable
use stats_variables, only: &
- l_stats_samp, iwp2_dp1, iwp2_dp2, zm, iwp2_bp, & ! Variable(s)
- iwp2_pr1, iwp2_pr2, iwp2_pr3, iwp3_ta, zt, &
+ l_stats_samp, iwp2_dp1, iwp2_dp2, stats_zm, iwp2_bp, & ! Variable(s)
+ iwp2_pr1, iwp2_pr2, iwp2_pr3, iwp3_ta, stats_zt, &
iwp3_tp, iwp3_bp1, iwp3_pr2, iwp3_pr1, iwp3_dp1, iwp3_bp2
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_update_var_pt, & ! Procedure(s)
stat_begin_update_pt, &
stat_modify_pt
@@ -2538,7 +2347,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
l_wp3_2nd_buoyancy_term = .true.
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep length [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
@@ -2563,10 +2372,12 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
Skw_zt, & ! Skewness of w on thermodynamic levels [-]
tau1m, & ! Time-scale tau on momentum levels [s]
tauw3t, & ! Time-scale tau on thermodynamic levels [s]
+ tau_C1_zm, & ! Tau values used for the C1 (dp1) term in wp2 [s]
C1_Skw_fnc, & ! C_1 parameter with Sk_w applied [-]
C11_Skw_fnc, & ! C_11 parameter with Sk_w applied [-]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
invrs_rho_ds_zt, & ! Inv. dry, static density @ thermo. levs. [m^3/kg]
+ radf, & ! Buoyancy production at the CL top [m^2/s^3]
thv_ds_zm, & ! Dry, base-state theta_v on momentum levs. [K]
thv_ds_zt ! Dry, base-state theta_v on thermo. levs. [K]
@@ -2630,13 +2441,16 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
! RHS time tendency.
rhs(k_wp2) &
- = + ( 1.0_core_rknd / real( dt, kind = core_rknd ) ) * wp2(k)
+ = + ( 1.0_core_rknd / dt ) * wp2(k)
! RHS buoyancy production (bp) term and pressure term 2 (pr2).
rhs(k_wp2) &
= rhs(k_wp2) &
+ wp2_terms_bp_pr2_rhs( C5, thv_ds_zm(k), wpthvp(k) )
+ ! RHS buoyancy production at CL top due to LW radiative cooling
+ rhs(k_wp2) = rhs(k_wp2) + radf(k)
+
! RHS pressure term 3 (pr3).
rhs(k_wp2) &
= rhs(k_wp2) &
@@ -2646,7 +2460,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
! RHS dissipation term 1 (dp1).
rhs(k_wp2) &
= rhs(k_wp2) &
- + wp2_term_dp1_rhs( C1_Skw_fnc(k), tau1m(k), w_tol_sqd )
+ + wp2_term_dp1_rhs( C1_Skw_fnc(k), tau_C1_zm(k), w_tol_sqd )
! RHS contribution from "over-implicit" weighted time step
! for LHS dissipation term 1 (dp1).
@@ -2656,7 +2470,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
! more numerically stable (see note below for w'^3 RHS turbulent
! advection (ta) and turbulent production (tp) terms).
lhs_fnc_output(1) &
- = wp2_term_dp1_lhs( C1_Skw_fnc(k), tau1m(k) )
+ = wp2_term_dp1_lhs( C1_Skw_fnc(k), tau_C1_zm(k) )
rhs(k_wp2) &
= rhs(k_wp2) &
+ ( 1.0_core_rknd - gamma_over_implicit_ts ) &
@@ -2714,21 +2528,21 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
call stat_begin_update_pt( iwp2_dp2, k, &
rhs_diff(3) * wp2(km1) &
+ rhs_diff(2) * wp2(k) &
- + rhs_diff(1) * wp2(kp1), zm )
+ + rhs_diff(1) * wp2(kp1), stats_zm )
endif
! w'^2 term bp is completely explicit; call stat_update_var_pt.
! Note: To find the contribution of w'^2 term bp, substitute 0 for the
! C_5 input to function wp2_terms_bp_pr2_rhs.
call stat_update_var_pt( iwp2_bp, k, &
- wp2_terms_bp_pr2_rhs( 0.0_core_rknd, thv_ds_zm(k), wpthvp(k) ), zm )
+ wp2_terms_bp_pr2_rhs( 0.0_core_rknd, thv_ds_zm(k), wpthvp(k) ), stats_zm )
! w'^2 term pr1 has both implicit and explicit components; call
! stat_begin_update_pt. Since stat_begin_update_pt automatically
! subtracts the value sent in, reverse the sign on wp2_term_pr1_rhs.
if ( l_tke_aniso ) then
call stat_begin_update_pt( iwp2_pr1, k, &
- -wp2_term_pr1_rhs( C4, up2(k), vp2(k), tau1m(k) ), zm )
+ -wp2_term_pr1_rhs( C4, up2(k), vp2(k), tau1m(k) ), stats_zm )
! Note: An "over-implicit" weighted time step is applied to this
! term. A weighting factor of greater than 1 may be used to
@@ -2739,7 +2553,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
= wp2_term_pr1_lhs( C4, tau1m(k) )
call stat_modify_pt( iwp2_pr1, k, &
+ ( 1.0_core_rknd - gamma_over_implicit_ts ) &
- * ( - lhs_fnc_output(1) * wp2(k) ), zm )
+ * ( - lhs_fnc_output(1) * wp2(k) ), stats_zm )
endif
! w'^2 term pr2 has both implicit and explicit components; call
@@ -2748,29 +2562,29 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
! Note: To find the contribution of w'^2 term pr2, add 1 to the
! C_5 input to function wp2_terms_bp_pr2_rhs.
call stat_begin_update_pt( iwp2_pr2, k, &
- -wp2_terms_bp_pr2_rhs( (1.0_core_rknd+C5), thv_ds_zm(k), wpthvp(k) ), zm )
+ -wp2_terms_bp_pr2_rhs( (1.0_core_rknd+C5), thv_ds_zm(k), wpthvp(k) ), stats_zm )
! w'^2 term dp1 has both implicit and explicit components; call
! stat_begin_update_pt. Since stat_begin_update_pt automatically
! subtracts the value sent in, reverse the sign on wp2_term_dp1_rhs.
call stat_begin_update_pt( iwp2_dp1, k, &
- -wp2_term_dp1_rhs( C1_Skw_fnc(k), tau1m(k), w_tol_sqd ), zm )
+ -wp2_term_dp1_rhs( C1_Skw_fnc(k), tau_C1_zm(k), w_tol_sqd ), stats_zm )
! Note: An "over-implicit" weighted time step is applied to this term.
! A weighting factor of greater than 1 may be used to make the
! term more numerically stable (see note below for w'^3 RHS
! turbulent advection (ta) and turbulent production (tp) terms).
lhs_fnc_output(1) &
- = wp2_term_dp1_lhs( C1_Skw_fnc(k), tau1m(k) )
+ = wp2_term_dp1_lhs( C1_Skw_fnc(k), tau_C1_zm(k) )
call stat_modify_pt( iwp2_dp1, k, &
+ ( 1.0_core_rknd - gamma_over_implicit_ts ) &
- * ( - lhs_fnc_output(1) * wp2(k) ), zm )
+ * ( - lhs_fnc_output(1) * wp2(k) ), stats_zm )
! w'^2 term pr3 is completely explicit; call stat_update_var_pt.
call stat_update_var_pt( iwp2_pr3, k, &
wp2_term_pr3_rhs( C5, thv_ds_zm(k), wpthvp(k), upwp(k), um(kp1), &
um(k), vpwp(k), vm(kp1), vm(k), gr%invrs_dzm(k) ), &
- zm )
+ stats_zm )
endif
@@ -2782,7 +2596,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
! RHS time tendency.
rhs(k_wp3) = &
- + ( 1.0_core_rknd / real( dt, kind = core_rknd ) * wp3(k) )
+ + ( 1.0_core_rknd / dt * wp3(k) )
! RHS turbulent advection (ta) and turbulent production (tp) terms.
! rhs(k_wp3) &
@@ -2896,8 +2710,8 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
! invrs_rho_ds_zt(k), &
! 0.0_core_rknd, &
! gr%invrs_dzt(k) ), &
-! zt )
- call stat_begin_update_pt( iwp3_ta, k, 0.0_core_rknd, zt )
+! stats_zt )
+ call stat_begin_update_pt( iwp3_ta, k, 0.0_core_rknd, stats_zt )
! Note: An "over-implicit" weighted time step is applied to this term.
! A weighting factor of greater than 1 may be used to make the
@@ -2919,7 +2733,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
- lhs_fnc_output(2) * wp2(k) &
- lhs_fnc_output(3) * wp3(k) &
- lhs_fnc_output(4) * wp2(km1) &
- - lhs_fnc_output(5) * wp3(km1) ), zt )
+ - lhs_fnc_output(5) * wp3(km1) ), stats_zt )
! w'^3 term tp has both implicit and explicit components; call
! stat_begin_update_pt. Since stat_begin_update_pt automatically
@@ -2938,8 +2752,8 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
! invrs_rho_ds_zt(k), &
! three_halves, &
! gr%invrs_dzt(k) ), &
-! zt )
- call stat_begin_update_pt( iwp3_tp, k, 0.0_core_rknd, zt )
+! stats_zt )
+ call stat_begin_update_pt( iwp3_tp, k, 0.0_core_rknd, stats_zt )
! Note: An "over-implicit" weighted time step is applied to this term.
! A weighting factor of greater than 1 may be used to make the
@@ -2958,13 +2772,13 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
call stat_modify_pt( iwp3_tp, k, &
+ ( 1.0_core_rknd - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(2) * wp2(k) &
- - lhs_fnc_output(4) * wp2(km1) ), zt )
+ - lhs_fnc_output(4) * wp2(km1) ), stats_zt )
! w'^3 term bp is completely explicit; call stat_update_var_pt.
! Note: To find the contribution of w'^3 term bp, substitute 0 for the
! C_11 skewness function input to function wp3_terms_bp1_pr2_rhs.
call stat_update_var_pt( iwp3_bp1, k, &
- wp3_terms_bp1_pr2_rhs( 0.0_core_rknd, thv_ds_zt(k), wp2thvp(k) ), zt )
+ wp3_terms_bp1_pr2_rhs( 0.0_core_rknd, thv_ds_zt(k), wp2thvp(k) ), stats_zt )
! w'^3 term pr2 has both implicit and explicit components; call
! stat_begin_update_pt. Since stat_begin_update_pt automatically
@@ -2974,14 +2788,14 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
call stat_begin_update_pt( iwp3_pr2, k, &
-wp3_terms_bp1_pr2_rhs( (1.0_core_rknd+C11_Skw_fnc(k)), thv_ds_zt(k), &
wp2thvp(k) ), &
- zt )
+ stats_zt )
! w'^3 term pr1 has both implicit and explicit components; call
! stat_begin_update_pt. Since stat_begin_update_pt automatically
! subtracts the value sent in, reverse the sign on wp3_term_pr1_rhs.
call stat_begin_update_pt( iwp3_pr1, k, &
-wp3_term_pr1_rhs( C8, C8b, tauw3t(k), Skw_zt(k), wp3(k) ), &
- zt )
+ stats_zt )
! Note: An "over-implicit" weighted time step is applied to this term.
! A weighting factor of greater than 1 may be used to make the
@@ -2991,7 +2805,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
= wp3_term_pr1_lhs( C8, C8b, tauw3t(k), Skw_zt(k) )
call stat_modify_pt( iwp3_pr1, k, &
+ ( 1.0_core_rknd - gamma_over_implicit_ts ) &
- * ( - lhs_fnc_output(1) * wp3(k) ), zt )
+ * ( - lhs_fnc_output(1) * wp3(k) ), stats_zt )
! w'^3 term dp1 has both implicit and explicit components (if the
! Crank-Nicholson scheme is selected); call stat_begin_update_pt.
@@ -3003,7 +2817,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
call stat_begin_update_pt( iwp3_dp1, k, &
rhs_diff(3) * wp3(km1) &
+ rhs_diff(2) * wp3(k) &
- + rhs_diff(1) * wp3(kp1), zt )
+ + rhs_diff(1) * wp3(kp1), stats_zt )
endif
if ( l_wp3_2nd_buoyancy_term ) then
@@ -3011,7 +2825,7 @@ subroutine wp23_rhs( dt, wp2, wp3, a1, a1_zt, &
dum_dz(k), dum_dz(km1), dvm_dz(k), dvm_dz(km1), &
upwp(k), upwp(km1), vpwp(k), vpwp(km1), &
thv_ds_zt(k), gr%invrs_dzt(k) )
- call stat_update_var_pt( iwp3_bp2, k, temp, zt )
+ call stat_update_var_pt( iwp3_bp2, k, temp, stats_zt )
end if
endif ! l_stats_samp
@@ -3694,9 +3508,6 @@ pure function wp3_terms_ta_tp_lhs( wp2, wp2m1, &
use grid_class, only: &
gr ! Variable gr%weights_zt2zm
- use constants_clubb, only: &
- w_tol_sqd
-
use model_flags, only: &
l_standard_term_ta
diff --git a/models/atm/cam/src/physics/clubb/advance_xm_wpxp_module.F90 b/models/atm/cam/src/physics/clubb/advance_xm_wpxp_module.F90
index a8b70f8a43a3..838fbbad8e5c 100644
--- a/models/atm/cam/src/physics/clubb/advance_xm_wpxp_module.F90
+++ b/models/atm/cam/src/physics/clubb/advance_xm_wpxp_module.F90
@@ -1,5 +1,5 @@
!-----------------------------------------------------------------------
-! $Id: advance_xm_wpxp_module.F90 5623 2012-01-17 17:55:26Z connork@uwm.edu $
+! $Id: advance_xm_wpxp_module.F90 7373 2014-11-08 00:44:20Z dschanen@uwm.edu $
!===============================================================================
module advance_xm_wpxp_module
@@ -41,12 +41,14 @@ module advance_xm_wpxp_module
!=============================================================================
subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
- Lscale, wp3_on_wp2, wp3_on_wp2_zt, &
- Kh_zt, tau_zm, Skw_zm, rtpthvp, rtm_forcing, &
- thlpthvp, rtm_ref, thlm_ref, thlm_forcing, &
+ Lscale, wp3_on_wp2, wp3_on_wp2_zt, Kh_zt, Kh_zm, &
+ tau_C6_zm, Skw_zm, rtpthvp, rtm_forcing, &
+ wprtp_forcing, rtm_ref, thlpthvp, &
+ thlm_forcing, wpthlp_forcing, thlm_ref, &
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
invrs_rho_ds_zt, thv_ds_zm, rtp2, thlp2, &
- pdf_params, l_implemented, &
+ w_1_zm, w_2_zm, varnce_w_1_zm, varnce_w_2_zm, &
+ mixt_frac_zm, l_implemented, em, &
sclrpthvp, sclrm_forcing, sclrp2, &
rtm, wprtp, thlm, wpthlp, &
err_code, &
@@ -89,6 +91,9 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
thl_tol_mfl, &
rt_tol_mfl, &
max_mag_correlation, &
+ one, &
+ one_half, &
+ zero, &
zero_threshold
use parameters_model, only: &
@@ -98,9 +103,9 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
use grid_class, only: &
gr ! Variable(s)
- use grid_class, only: &
- zm2zt, & ! Procedure(s)
- zt2zm
+ use grid_class, only: &
+ zm2zt, & ! Procedure(s)
+ zt2zm
use model_flags, only: &
l_clip_semi_implicit ! Variable(s)
@@ -108,26 +113,25 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
use mono_flux_limiter, only: &
calc_turb_adv_range ! Procedure(s)
- use pdf_parameter_module, only: &
- pdf_parameter ! Type
-
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
+
+ use error_code, only: &
+ clubb_at_least_debug_level, & ! Procedure(s)
+ report_error, &
+ fatal_error
use error_code, only: &
- clubb_at_least_debug_level, & ! Procedure(s)
- reportError, &
- fatal_error
+ clubb_var_out_of_range ! Constant(s)
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update, & ! Procedure(s)
stat_end_update, &
stat_update_var
use stats_variables, only: &
- zt, &
- zm, &
+ stats_zt, &
+ stats_zm, &
irtm_matrix_condt_num, & ! Variables
ithlm_matrix_condt_num, &
irtm_sdmp, ithlm_sdmp, &
@@ -138,11 +142,11 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
l_stats_samp
use sponge_layer_damping, only: &
- rtm_sponge_damp_settings, &
- thlm_sponge_damp_settings, &
- rtm_sponge_damp_profile, &
- thlm_sponge_damp_profile, &
- sponge_damp_xm ! Procedure(s)
+ rtm_sponge_damp_settings, &
+ thlm_sponge_damp_settings, &
+ rtm_sponge_damp_profile, &
+ thlm_sponge_damp_profile, &
+ sponge_damp_xm ! Procedure(s)
implicit none
@@ -154,7 +158,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
l_iter = .true. ! True when the means and fluxes are prognosed
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep [s]
real( kind = core_rknd ), intent(in), dimension(gr%nz) :: &
@@ -163,17 +167,21 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
wm_zt, & ! w wind component on thermodynamic levels [m/s]
wp2, & ! w'^2 (momentum levels) [m^2/s^2]
Lscale, & ! Turbulent mixing length [m]
+ em, & ! Turbulent Kinetic Energy (TKE) [m^2/s^2]
wp3_on_wp2, & ! Smoothed wp3 / wp2 on momentum levels [m/s]
wp3_on_wp2_zt, & ! Smoothed wp3 / wp2 on thermo. levels [m/s]
Kh_zt, & ! Eddy diffusivity on thermodynamic levels [m^2/s]
- tau_zm, & ! Time-scale tau on momentum levels [s]
+ Kh_zm, & ! Eddy diffusivity on momentum levels
+ tau_C6_zm, & ! Time-scale tau on momentum levels applied to C6 term [s]
Skw_zm, & ! Skewness of w on momentum levels [-]
rtpthvp, & ! r_t'th_v' (momentum levels) [(kg/kg) K]
- rtm_ref, & ! rtm for nudging
- thlm_ref, & ! thlm for nudging
rtm_forcing, & ! r_t forcing (thermodynamic levels) [(kg/kg)/s]
+ wprtp_forcing, & ! forcing (momentum levels) [(kg/kg)/s^2]
+ rtm_ref, & ! rtm for nudging [kg/kg]
thlpthvp, & ! th_l'th_v' (momentum levels) [K^2]
thlm_forcing, & ! th_l forcing (thermodynamic levels) [K/s]
+ wpthlp_forcing, & ! forcing (momentum levels) [K/s^2]
+ thlm_ref, & ! thlm for nudging [K]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
rho_ds_zt, & ! Dry, static density on thermo. levels [kg/m^3]
invrs_rho_ds_zm, & ! Inv. dry, static density @ moment. levs. [m^3/kg]
@@ -181,11 +189,13 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
thv_ds_zm, & ! Dry, base-state theta_v on moment. levs. [K]
! Added for clipping by Vince Larson 29 Sep 2007
rtp2, & ! r_t'^2 (momentum levels) [(kg/kg)^2]
- thlp2 ! th_l'^2 (momentum levels) [K^2]
+ thlp2, & ! th_l'^2 (momentum levels) [K^2]
! End of Vince Larson's addition.
-
- type(pdf_parameter), dimension(gr%nz), intent(in) :: &
- pdf_params ! PDF parameters [units vary]
+ w_1_zm, & ! Mean w (1st PDF component) [m/s]
+ w_2_zm, & ! Mean w (2nd PDF component) [m/s]
+ varnce_w_1_zm, & ! Variance of w (1st PDF component) [m^2/s^2]
+ varnce_w_2_zm, & ! Variance of w (2nd PDF component) [m^2/s^2]
+ mixt_frac_zm ! Weight of 1st PDF component (Sk_w dependent) [-]
logical, intent(in) :: &
l_implemented ! Flag for CLUBB being implemented in a larger model.
@@ -270,25 +280,29 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
allocate( rhs(2*gr%nz,nrhs) )
allocate( solution(2*gr%nz,nrhs) )
+ ! This is initialized solely for the purpose of avoiding a compiler
+ ! warning about uninitialized variables.
+ dummy_1d = zero
+
! Compute C6 and C7 as a function of Skw
! The if...then is just here to save compute time
if ( C6rt /= C6rtb ) then
C6rt_Skw_fnc(1:gr%nz) = C6rtb + (C6rt-C6rtb) &
- *EXP( -0.5_core_rknd * (Skw_zm(1:gr%nz)/C6rtc)**2 )
+ *EXP( -one_half * (Skw_zm(1:gr%nz)/C6rtc)**2 )
else
C6rt_Skw_fnc(1:gr%nz) = C6rtb
endif
if ( C6thl /= C6thlb ) then
C6thl_Skw_fnc(1:gr%nz) = C6thlb + (C6thl-C6thlb) &
- *EXP( -0.5_core_rknd * (Skw_zm(1:gr%nz)/C6thlc)**2 )
+ *EXP( -one_half * (Skw_zm(1:gr%nz)/C6thlc)**2 )
else
C6thl_Skw_fnc(1:gr%nz) = C6thlb
endif
if ( C7 /= C7b ) then
C7_Skw_fnc(1:gr%nz) = C7b + (C7-C7b) &
- *EXP( -0.5_core_rknd * (Skw_zm(1:gr%nz)/C7c)**2 )
+ *EXP( -one_half * (Skw_zm(1:gr%nz)/C7c)**2 )
else
C7_Skw_fnc(1:gr%nz) = C7b
endif
@@ -307,11 +321,20 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( l_stats_samp ) then
- call stat_update_var( iC7_Skw_fnc, C7_Skw_fnc, zm )
- call stat_update_var( iC6rt_Skw_fnc, C6rt_Skw_fnc, zm )
- call stat_update_var( iC6thl_Skw_fnc, C6thl_Skw_fnc, zm )
+ call stat_update_var( iC7_Skw_fnc, C7_Skw_fnc, stats_zm )
+ call stat_update_var( iC6rt_Skw_fnc, C6rt_Skw_fnc, stats_zm )
+ call stat_update_var( iC6thl_Skw_fnc, C6thl_Skw_fnc, stats_zm )
- endif
+ end if
+
+ if ( clubb_at_least_debug_level( 2 ) ) then
+ ! Assertion check for C7_Skw_fnc
+ if ( any( C7_Skw_fnc(:) > one ) .or. any( C7_Skw_fnc(:) < zero ) ) then
+ write(fstderr,*) "The C7_Skw_fnc variable is outside the valid range"
+ err_code = clubb_var_out_of_range
+ return
+ end if
+ end if
! Define the Coefficent of Eddy Diffusivity for the wpthlp and wprtp.
! Kw6 is used for wpthlp and wprtp, which are located on momentum levels.
@@ -324,14 +347,15 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
! have an effect on the central thermodynamic level during the course of
! one time step due to turbulent advection. This is used as part of the
! monotonic turbulent advection scheme.
- call calc_turb_adv_range( dt, pdf_params, &
- low_lev_effect, high_lev_effect )
+ call calc_turb_adv_range( dt, w_1_zm, w_2_zm, varnce_w_1_zm, varnce_w_2_zm, & ! In
+ mixt_frac_zm, & ! In
+ low_lev_effect, high_lev_effect ) ! Out
! Define a_1 (located on momentum levels).
! It is a variable that is a function of sigma_sqd_w (where sigma_sqd_w is
! located on momentum levels).
- a1(1:gr%nz) = 1.0_core_rknd / ( 1.0_core_rknd - sigma_sqd_w(1:gr%nz) )
+ a1(1:gr%nz) = one / ( one - sigma_sqd_w(1:gr%nz) )
! Interpolate a_1 from momentum levels to thermodynamic levels. This will
! be used for the w'x' turbulent advection (ta) term.
@@ -352,23 +376,24 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
! Compute the implicit portion of the r_t and w'r_t' equations.
! Build the left-hand side matrix.
- call xm_wpxp_lhs( l_iter, dt, wprtp, a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
+ call xm_wpxp_lhs( l_iter, dt, Kh_zm, wprtp, a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
wp2, wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- Kw6, tau_zm, C7_Skw_fnc, & ! Intent(in)
+ Kw6, tau_C6_zm, C7_Skw_fnc, & ! Intent(in)
C6rt_Skw_fnc, rho_ds_zm, rho_ds_zt, & ! Intent(in)
invrs_rho_ds_zm, invrs_rho_ds_zt, & ! Intent(in)
wpxp_upper_lim, wpxp_lower_lim, l_implemented, & ! Intent(in)
+ em, Lscale, thlm, & ! Intent(in)
lhs ) ! Intent(out)
! Compute the explicit portion of the r_t and w'r_t' equations.
! Build the right-hand side vector.
- call xm_wpxp_rhs( xm_wpxp_rtm, l_iter, dt, rtm, wprtp, & ! Intent(in)
- rtm_forcing, C7_Skw_fnc, rtpthvp, & ! Intent(in)
- C6rt_Skw_fnc, tau_zm, a1, a1_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- thv_ds_zm, wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
- rhs(:,1) ) ! Intent(out)
+ call xm_wpxp_rhs( xm_wpxp_rtm, l_iter, dt, rtm, wprtp, & ! Intent(in)
+ rtm_forcing, wprtp_forcing, C7_Skw_fnc, & ! Intent(in)
+ rtpthvp, C6rt_Skw_fnc, tau_C6_zm, a1, a1_zt, & ! Intent(in)
+ wp3_on_wp2, wp3_on_wp2_zt, rho_ds_zt, & ! Intent(in)
+ rho_ds_zm, invrs_rho_ds_zm, thv_ds_zm, & ! Intent(in)
+ wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
+ rhs(:,1) ) ! Intent(out)
! Solve r_t / w'r_t'
if ( l_stats_samp .and. irtm_matrix_condt_num > 0 ) then
@@ -384,7 +409,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,'(a)') "Mean total water & total water flux LU decomp. failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -405,7 +430,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,'(a)') "rtm monotonic flux limiter: tridag failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -425,23 +450,24 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
! Compute the implicit portion of the th_l and w'th_l' equations.
! Build the left-hand side matrix.
- call xm_wpxp_lhs( l_iter, dt, wpthlp, a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
+ call xm_wpxp_lhs( l_iter, dt, Kh_zm, wpthlp, a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
wp2, wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- Kw6, tau_zm, C7_Skw_fnc, & ! Intent(in)
+ Kw6, tau_C6_zm, C7_Skw_fnc, & ! Intent(in)
C6thl_Skw_fnc, rho_ds_zm, rho_ds_zt, & ! Intent(in)
invrs_rho_ds_zm, invrs_rho_ds_zt, & ! Intent(in)
wpxp_upper_lim, wpxp_lower_lim, l_implemented, & ! Intent(in)
+ em, Lscale, thlm, & ! Intent(in)
lhs ) ! Intent(out)
! Compute the explicit portion of the th_l and w'th_l' equations.
! Build the right-hand side vector.
- call xm_wpxp_rhs( xm_wpxp_thlm, l_iter, dt, thlm, wpthlp, & ! Intent(in)
- thlm_forcing, C7_Skw_fnc, thlpthvp, & ! Intent(in)
- C6thl_Skw_fnc, tau_zm, a1, a1_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- thv_ds_zm, wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
- rhs(:,1) ) ! Intent(out)
+ call xm_wpxp_rhs( xm_wpxp_thlm, l_iter, dt, thlm, wpthlp, & ! Intent(in)
+ thlm_forcing, wpthlp_forcing, C7_Skw_fnc, & ! Intent(in)
+ thlpthvp, C6thl_Skw_fnc, tau_C6_zm, a1, a1_zt, & ! Intent(in)
+ wp3_on_wp2, wp3_on_wp2_zt, rho_ds_zt, & ! Intent(in)
+ rho_ds_zm, invrs_rho_ds_zm, thv_ds_zm, & ! Intent(in)
+ wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
+ rhs(:,1) ) ! Intent(out)
! Solve for th_l / w'th_l'
if ( l_stats_samp .and. ithlm_matrix_condt_num > 0 ) then
@@ -457,7 +483,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,'(a)') "Liquid pot. temp & thetal flux LU decomp. failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -478,7 +504,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,'(a)') "thlm monotonic flux limiter: tridag failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -509,23 +535,24 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
! Compute the implicit portion of the sclr and w'sclr' equations.
! Build the left-hand side matrix.
- call xm_wpxp_lhs( l_iter, dt, wpsclrp(:,i), a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
+ call xm_wpxp_lhs( l_iter, dt, Kh_zm, wpsclrp(:,i), a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
wp2, wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- Kw6, tau_zm, C7_Skw_fnc, & ! Intent(in)
+ Kw6, tau_C6_zm, C7_Skw_fnc, & ! Intent(in)
C6rt_Skw_fnc, rho_ds_zm, rho_ds_zt, & ! Intent(in)
invrs_rho_ds_zm, invrs_rho_ds_zt, & ! Intent(in)
wpxp_upper_lim, wpxp_lower_lim, l_implemented, & ! Intent(in)
+ em, Lscale, thlm, & ! Intent(in)
lhs ) ! Intent(out)
! Compute the explicit portion of the sclrm and w'sclr' equations.
! Build the right-hand side vector.
call xm_wpxp_rhs( xm_wpxp_scalar, l_iter, dt, sclrm(:,i), wpsclrp(:,i), & ! Intent(in)
- sclrm_forcing(:,i), C7_Skw_fnc, sclrpthvp(:,i), & ! Intent(in)
- C6rt_Skw_fnc, tau_zm, a1, a1_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- thv_ds_zm, wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
- rhs(:,1) ) ! Intent(out)
+ sclrm_forcing(:,i), dummy_1d, C7_Skw_fnc, & ! Intent(in)
+ sclrpthvp(:,i), C6rt_Skw_fnc, tau_C6_zm, a1, a1_zt, & ! Intent(in)
+ wp3_on_wp2, wp3_on_wp2_zt, rho_ds_zt, & ! Intent(in)
+ rho_ds_zm, invrs_rho_ds_zm, thv_ds_zm, & ! Intent(in)
+ wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
+ rhs(:,1) ) ! Intent(out)
! Solve for sclrm / w'sclr'
call xm_wpxp_solve( nrhs, & ! Intent(in)
@@ -535,7 +562,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) "Passive scalar # ", i, " LU decomp. failed."
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -557,7 +584,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) "sclrm # ", i, "monotonic flux limiter: tridag failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -569,38 +596,35 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
else ! Simple case, where l_clip_semi_implicit is false
- ! This is initialized solely for the purpose of avoiding a compiler
- ! warning about uninitialized variables.
- dummy_1d = 0._core_rknd
-
! Create the lhs once
- call xm_wpxp_lhs( l_iter, dt, dummy_1d, a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
+ call xm_wpxp_lhs( l_iter, dt, Kh_zm, dummy_1d, a1, a1_zt, wm_zm, wm_zt, & ! Intent(in)
wp2, wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- Kw6, tau_zm, C7_Skw_fnc, & ! Intent(in)
+ Kw6, tau_C6_zm, C7_Skw_fnc, & ! Intent(in)
C6rt_Skw_fnc, rho_ds_zm, rho_ds_zt, & ! Intent(in)
invrs_rho_ds_zm, invrs_rho_ds_zt, & ! Intent(in)
dummy_1d, dummy_1d, l_implemented, & ! Intent(in)
+ em, Lscale, thlm, & ! Intent(in)
lhs ) ! Intent(out)
! Compute the explicit portion of the r_t and w'r_t' equations.
! Build the right-hand side vector.
- call xm_wpxp_rhs( xm_wpxp_rtm, l_iter, dt, rtm, wprtp, & ! Intent(in)
- rtm_forcing, C7_Skw_fnc, rtpthvp, & ! Intent(in)
- C6rt_Skw_fnc, tau_zm, a1, a1_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- thv_ds_zm, wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
- rhs(:,1) ) ! Intent(out)
+ call xm_wpxp_rhs( xm_wpxp_rtm, l_iter, dt, rtm, wprtp, & ! Intent(in)
+ rtm_forcing, wprtp_forcing, C7_Skw_fnc, & ! Intent(in)
+ rtpthvp, C6rt_Skw_fnc, tau_C6_zm, a1, a1_zt, & ! Intent(in)
+ wp3_on_wp2, wp3_on_wp2_zt, rho_ds_zt, & ! Intent(in)
+ rho_ds_zm, invrs_rho_ds_zm, thv_ds_zm, & ! Intent(in)
+ wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
+ rhs(:,1) ) ! Intent(out)
! Compute the explicit portion of the th_l and w'th_l' equations.
! Build the right-hand side vector.
- call xm_wpxp_rhs( xm_wpxp_thlm, l_iter, dt, thlm, wpthlp, & ! Intent(in)
- thlm_forcing, C7_Skw_fnc, thlpthvp, & ! Intent(in)
- C6thl_Skw_fnc, tau_zm, a1, a1_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- thv_ds_zm, wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
- rhs(:,2) ) ! Intent(out)
+ call xm_wpxp_rhs( xm_wpxp_thlm, l_iter, dt, thlm, wpthlp, & ! Intent(in)
+ thlm_forcing, wpthlp_forcing, C7_Skw_fnc, & ! Intent(in)
+ thlpthvp, C6thl_Skw_fnc, tau_C6_zm, a1, a1_zt, & ! Intent(in)
+ wp3_on_wp2, wp3_on_wp2_zt, rho_ds_zt, & ! Intent(in)
+ rho_ds_zm, invrs_rho_ds_zm, thv_ds_zm, & ! Intent(in)
+ wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
+ rhs(:,2) ) ! Intent(out)
! ---> h1g, 2010-06-15
! scalar transport, e.g, droplet and ice number concentration
@@ -613,12 +637,13 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
! <--- h1g, 2010-06-15
call xm_wpxp_rhs( xm_wpxp_scalar, l_iter, dt, sclrm(:,i), wpsclrp(:,i), & ! Intent(in)
- sclrm_forcing(:,i), C7_Skw_fnc, sclrpthvp(:,i), & ! Intent(in)
- C6rt_Skw_fnc, tau_zm, a1, a1_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- thv_ds_zm, wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
- rhs(:,2+i) ) ! Intent(out)
+ sclrm_forcing(:,i), dummy_1d, C7_Skw_fnc, & ! Intent(in)
+ sclrpthvp(:,i), C6rt_Skw_fnc, tau_C6_zm, a1, a1_zt, & ! Intent(in)
+ wp3_on_wp2, wp3_on_wp2_zt, rho_ds_zt, & ! Intent(in)
+ rho_ds_zm, invrs_rho_ds_zm, thv_ds_zm, & ! Intent(in)
+ wpxp_upper_lim, wpxp_lower_lim, & ! Intent(in)
+ rhs(:,2+i) ) ! Intent(out)
+
enddo
! Solve for all fields
@@ -635,7 +660,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,'(a)') "xm_wpxp matrix LU decomp. failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -656,7 +681,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,'(a)') "rtm monotonic flux limiter: tridag failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -677,7 +702,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,'(a)') "thlm monotonic flux limiter: tridag failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -709,7 +734,7 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( fatal_error( err_code_xm_wpxp ) ) then
if ( clubb_at_least_debug_level( 1 ) ) then
write(fstderr,*) "sclrm # ", i, "monotonic flux limiter: tridag failed"
- call reportError( err_code_xm_wpxp )
+ call report_error( err_code_xm_wpxp )
end if
! Overwrite the current error status with the new fatal error
@@ -740,14 +765,16 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
write(fstderr,*) "wp3_on_wp2 = ", wp3_on_wp2
write(fstderr,*) "wp3_on_wp2_zt = ", wp3_on_wp2_zt
write(fstderr,*) "Kh_zt = ", Kh_zt
- write(fstderr,*) "tau_zm = ", tau_zm
+ write(fstderr,*) "tau_C6_zm = ", tau_C6_zm
write(fstderr,*) "Skw_zm = ", Skw_zm
write(fstderr,*) "rtpthvp = ", rtpthvp
- write(fstderr,*) "rtm_ref = ", rtm_ref
- write(fstderr,*) "thlm_ref = ", thlm_ref
write(fstderr,*) "rtm_forcing = ", rtm_forcing
+ write(fstderr,*) "wprtp_forcing = ", wprtp_forcing
+ write(fstderr,*) "rtm_ref = ", rtm_ref
write(fstderr,*) "thlpthvp = ", thlpthvp
write(fstderr,*) "thlm_forcing = ", thlm_forcing
+ write(fstderr,*) "wpthlp_forcing = ", wpthlp_forcing
+ write(fstderr,*) "thlm_ref = ", thlm_ref
write(fstderr,*) "rho_ds_zm = ", rho_ds_zm
write(fstderr,*) "rho_ds_zt = ", rho_ds_zt
write(fstderr,*) "invrs_rho_ds_zm = ", invrs_rho_ds_zm
@@ -755,11 +782,11 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
write(fstderr,*) "thv_ds_zm = ", thv_ds_zm
write(fstderr,*) "rtp2 = ", rtp2
write(fstderr,*) "thlp2 = ", thlp2
- write(fstderr,*) "pdf_params%w1 = ", pdf_params%w1
- write(fstderr,*) "pdf_params%w2 = ", pdf_params%w2
- write(fstderr,*) "pdf_params%sw1 = ", pdf_params%varnce_w1
- write(fstderr,*) "pdf_params%sw2 = ", pdf_params%varnce_w2
- write(fstderr,*) "pdf_params%mixt_frac = ", pdf_params%mixt_frac
+ write(fstderr,*) "w_1_zm = ", w_1_zm
+ write(fstderr,*) "w_2_zm = ", w_2_zm
+ write(fstderr,*) "varnce_w_1_zm = ", varnce_w_1_zm
+ write(fstderr,*) "varnce_w_2_zm = ", varnce_w_2_zm
+ write(fstderr,*) "mixt_frac_zm = ", mixt_frac_zm
write(fstderr,*) "l_implemented = ", l_implemented
if ( sclr_dim > 0 ) then
@@ -784,24 +811,24 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
if ( rtm_sponge_damp_settings%l_sponge_damping ) then
if( l_stats_samp ) then
- call stat_begin_update( irtm_sdmp, rtm / real( dt, kind = core_rknd ), zt )
+ call stat_begin_update( irtm_sdmp, rtm / dt, stats_zt )
end if
rtm(1:gr%nz) = sponge_damp_xm( dt, rtm_ref(1:gr%nz), rtm(1:gr%nz), &
rtm_sponge_damp_profile )
if( l_stats_samp ) then
- call stat_end_update( irtm_sdmp, rtm / real( dt, kind = core_rknd ), zt )
+ call stat_end_update( irtm_sdmp, rtm / dt, stats_zt )
end if
endif
if ( thlm_sponge_damp_settings%l_sponge_damping ) then
if( l_stats_samp ) then
- call stat_begin_update( ithlm_sdmp, thlm / real( dt, kind = core_rknd ), zt )
+ call stat_begin_update( ithlm_sdmp, thlm / dt, stats_zt )
end if
thlm(1:gr%nz) = sponge_damp_xm( dt, thlm_ref(1:gr%nz), thlm(1:gr%nz), &
thlm_sponge_damp_profile )
if( l_stats_samp ) then
- call stat_end_update( ithlm_sdmp, thlm / real( dt, kind = core_rknd ), zt )
+ call stat_end_update( ithlm_sdmp, thlm / dt, stats_zt )
end if
endif
@@ -810,12 +837,13 @@ subroutine advance_xm_wpxp( dt, sigma_sqd_w, wm_zm, wm_zt, wp2, &
end subroutine advance_xm_wpxp
!=============================================================================
- subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
+ subroutine xm_wpxp_lhs( l_iter, dt, Kh_zm, wpxp, a1, a1_zt, wm_zm, wm_zt, &
wp2, wp3_on_wp2, wp3_on_wp2_zt, &
- Kw6, tau_zm, C7_Skw_fnc, &
+ Kw6, tau_C6_zm, C7_Skw_fnc, &
C6x_Skw_fnc, rho_ds_zm, rho_ds_zt, &
invrs_rho_ds_zm, invrs_rho_ds_zt, &
wpxp_upper_lim, wpxp_lower_lim, l_implemented, &
+ em, Lscale, thlm, &
lhs )
! Description:
@@ -832,21 +860,26 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
use grid_class, only: &
gr, & ! Variable(s)
- zm2zt ! Procedure(s)
+ zm2zt, & ! Procedure(s)
+ ddzt
use constants_clubb, only: &
- gamma_over_implicit_ts ! Variable(s)
+ gamma_over_implicit_ts, & ! Constant(s)
+ one, &
+ zero
use model_flags, only: &
l_clip_semi_implicit, & ! Variable(s)
- l_upwind_wpxp_ta
+ l_upwind_wpxp_ta, &
+ l_diffuse_rtm_and_thlm, &
+ l_stability_correct_Kh_N2_zm
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use diffusion, only: &
- diffusion_zm_lhs ! Procedure(s)
+ diffusion_zt_lhs, &! Procedure(s)
+ diffusion_zm_lhs
use mean_adv, only: &
term_ma_zt_lhs, & ! Procedure(s)
@@ -900,8 +933,9 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
iwprtp_dp1, &
iwprtp_sicl
- use advance_helper_module, only: set_boundary_conditions_lhs ! Procedure(s)
-
+ use advance_helper_module, only: &
+ set_boundary_conditions_lhs, & ! Procedure(s)
+ calc_stability_correction
implicit none
@@ -930,20 +964,24 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
! Input variables
logical, intent(in) :: l_iter
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep [s]
real( kind = core_rknd ), intent(in), dimension(gr%nz) :: &
wpxp, & ! w'x' (momentum levels) at timestep (t) [{xm units} m/s]
+ Kh_zm, & ! Eddy diffusivity on momentum levels [m^2/s]
a1, & ! a_1 (momentum levels) [-]
a1_zt, & ! a_1 interpolated to thermodynamic levels [-]
+ Lscale, & ! Turbulent mixing length [m]
+ em, & ! Turbulent Kinetic Energy (TKE) [m^2/s^2]
+ thlm, & ! th_l (thermo. levels) [K]
wm_zm, & ! w wind component on momentum levels [m/s]
wm_zt, & ! w wind component on thermodynamic levels [m/s]
wp2, & ! w'^2 (momentum levels) [m^2/s^2]
wp3_on_wp2, & ! Smoothed wp3 / wp2 on momentum levels [m/s]
wp3_on_wp2_zt, & ! Smoothed wp3 / wp2 on thermo. levels [m/s]
Kw6, & ! Coefficient of eddy diffusivity for w'x' [m^2/s]
- tau_zm, & ! Time-scale tau on momentum levels [s]
+ tau_C6_zm, & ! Time-scale tau on momentum levels applied to the C6 term [s]
C7_Skw_fnc, & ! C_7 parameter with Sk_w applied [-]
C6x_Skw_fnc, & ! C_6x parameter with Sk_w applied [-]
rho_ds_zm, & ! Dry, static density on momentum levels [kg/m^3]
@@ -971,9 +1009,28 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
logical :: l_upper_thresh, l_lower_thresh ! flags for clip_semi_imp_lhs
+ ! These variables are used to change the amount
+ ! of diffusion applied towards rtm and thlm. They are only used when
+ ! l_diffuse_rtm_and_thlm = .true.
+ real (kind = core_rknd), dimension(gr%nz) :: &
+ zero_nu, &
+ Kh_N2_zm
+
+ real (kind = core_rknd) :: &
+ constant_nu ! controls the magnitude of diffusion
+
+ ! Setting up variables used for diffusion
+ zero_nu = 0.0_core_rknd
+ constant_nu = 0.1_core_rknd
+
+ if ( l_stability_correct_Kh_N2_zm ) then
+ Kh_N2_zm = Kh_zm / calc_stability_correction( thlm, Lscale, em)
+ else
+ Kh_N2_zm = Kh_zm
+ end if
! Initialize the left-hand side matrix to 0.
- lhs = 0.0_core_rknd
+ lhs = zero
! The xm loop runs between k = 2 and k = gr%nz. The value of xm at
! level k = 1, which is below the model surface, is simply set equal to the
@@ -987,7 +1044,15 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
k_xm = 2*k - 1
! k_wpxp is 2*k
-
+
+ if ( l_diffuse_rtm_and_thlm ) then
+ lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k) &
+ = lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k) &
+ + invrs_rho_ds_zt(k) &
+ * diffusion_zt_lhs( rho_ds_zm(k) * ( Kh_N2_zm(k) + constant_nu ), &
+ rho_ds_zm(km1) * ( Kh_N2_zm(km1) + constant_nu ), zero_nu, &
+ gr%invrs_dzm(km1), gr%invrs_dzm(k), gr%invrs_dzt(k), k )
+ end if
!!!!!***** xm *****!!!!!
@@ -1014,7 +1079,7 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
else
lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k_xm) &
- = lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k_xm) + 0.0_core_rknd
+ = lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k_xm) + zero
endif
@@ -1026,7 +1091,7 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
! LHS time tendency.
lhs(t_k_tdiag,k_xm) &
- = lhs(t_k_tdiag,k_xm) + 1.0_core_rknd / real( dt, kind = core_rknd )
+ = lhs(t_k_tdiag,k_xm) + one / dt
if (l_stats_samp) then
@@ -1040,9 +1105,9 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
ztscr02(k) = - tmp(2)
ztscr03(k) = - tmp(1)
else
- ztscr01(k) = 0.0_core_rknd
- ztscr02(k) = 0.0_core_rknd
- ztscr03(k) = 0.0_core_rknd
+ ztscr01(k) = zero
+ ztscr02(k) = zero
+ ztscr03(k) = zero
endif
endif
@@ -1143,7 +1208,7 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
lhs(m_k_mdiag,k_wpxp) &
= lhs(m_k_mdiag,k_wpxp) &
+ gamma_over_implicit_ts &
- * wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_zm(k) )
+ * wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_C6_zm(k) )
! LHS eddy diffusion term: dissipation term 1 (dp1).
lhs((/m_kp1_mdiag,m_k_mdiag,m_km1_mdiag/),k_wpxp) &
@@ -1154,8 +1219,9 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
! LHS time tendency.
if ( l_iter ) then
- lhs(m_k_mdiag,k_wpxp) = lhs(m_k_mdiag,k_wpxp) + 1.0_core_rknd / real(dt, kind = core_rknd)
- end if
+ lhs(m_k_mdiag,k_wpxp) &
+ = lhs(m_k_mdiag,k_wpxp) + one / dt
+ endif
! LHS portion of semi-implicit clipping term.
if ( l_clip_semi_implicit ) then
@@ -1221,7 +1287,7 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
! C_7 skewness function input to function wpxp_terms_ac_pr2_lhs.
if ( iwprtp_ac > 0 .or. iwpthlp_ac > 0 ) then
zmscr09(k) = &
- - wpxp_terms_ac_pr2_lhs( 0.0_core_rknd, &
+ - wpxp_terms_ac_pr2_lhs( zero, &
wm_zt(kp1), wm_zt(k), gr%invrs_dzm(k) )
endif
@@ -1232,14 +1298,14 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
if ( iwprtp_pr1 > 0 .or. iwpthlp_pr1 > 0 ) then
zmscr10(k) &
= - gamma_over_implicit_ts &
- * wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_zm(k) )
+ * wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_C6_zm(k) )
endif
! Note: To find the contribution of w'x' term pr2, add 1 to the
! C_7 skewness function input to function wpxp_terms_ac_pr2_lhs.
if ( iwprtp_pr2 > 0 .or. iwpthlp_pr2 > 0 ) then
zmscr11(k) = &
- - wpxp_terms_ac_pr2_lhs( (1.0_core_rknd+C7_Skw_fnc(k)), &
+ - wpxp_terms_ac_pr2_lhs( (one+C7_Skw_fnc(k)), &
wm_zt(kp1), wm_zt(k), gr%invrs_dzm(k) )
endif
@@ -1293,11 +1359,44 @@ subroutine xm_wpxp_lhs( l_iter, dt, wpxp, a1, a1_zt, wm_zm, wm_zt, &
k_xm = 2*k - 1
k_wpxp_low = 2*k
+ if ( l_diffuse_rtm_and_thlm ) then
+ ! xm
+ lhs(:,k_xm) = 0.0_core_rknd
+ lhs(t_k_tdiag,k_xm) = 1.0_core_rknd
+ ! w'x'
+ lhs(:,k_wpxp) = 0.0_core_rknd
+ lhs(m_k_mdiag,k_wpxp) = 1.0_core_rknd
+
+ km1 = max( k-1, 1 )
+
+ lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k) &
+ = lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k) &
+ + invrs_rho_ds_zt(k) &
+ * diffusion_zt_lhs( rho_ds_zm(k) * ( Kh_N2_zm(k) + constant_nu ), &
+ rho_ds_zm(km1) * ( Kh_N2_zm(km1) + constant_nu ), zero_nu, &
+ gr%invrs_dzm(km1), gr%invrs_dzm(k), gr%invrs_dzt(k), k )
+ end if
+
! Upper boundary
k = gr%nz
!k_xm is 2*k - 1
k_wpxp_high = 2*k
+ if ( l_diffuse_rtm_and_thlm ) then
+ ! w'x'
+ lhs(:,k_wpxp) = 0.0_core_rknd
+ lhs(m_k_mdiag,k_wpxp) = 1.0_core_rknd
+
+ km1 = max( k-1, 1 )
+
+ lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k) &
+ = lhs((/t_kp1_tdiag,t_k_tdiag,t_km1_tdiag/),k) &
+ + invrs_rho_ds_zt(k) &
+ * diffusion_zt_lhs( rho_ds_zm(k) * ( Kh_N2_zm(k) + constant_nu ), &
+ rho_ds_zm(km1) * ( Kh_N2_zm(km1) + constant_nu ), zero_nu, &
+ gr%invrs_dzm(km1), gr%invrs_dzm(k), gr%invrs_dzt(k), k )
+ end if
+
call set_boundary_conditions_lhs( m_k_mdiag, k_wpxp_low, k_wpxp_high, lhs, &
t_k_tdiag, k_xm)
@@ -1307,12 +1406,13 @@ end subroutine xm_wpxp_lhs
!=============================================================================
subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
- xm_forcing, C7_Skw_fnc, xpthvp, &
- C6x_Skw_fnc, tau_zm, a1, a1_zt, &
- wp3_on_wp2, wp3_on_wp2_zt, &
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, &
- thv_ds_zm, wpxp_upper_lim, wpxp_lower_lim, &
+ xm_forcing, wpxp_forcing, C7_Skw_fnc, &
+ xpthvp, C6x_Skw_fnc, tau_C6_zm, a1, a1_zt, &
+ wp3_on_wp2, wp3_on_wp2_zt, rho_ds_zt, &
+ rho_ds_zm, invrs_rho_ds_zm, thv_ds_zm, &
+ wpxp_upper_lim, wpxp_lower_lim, &
rhs )
+
! Description:
! Compute RHS vector for xm and w'x'.
! This subroutine computes the explicit portion of
@@ -1325,38 +1425,41 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
gr ! Variable(s)
use constants_clubb, only: &
- gamma_over_implicit_ts ! Variable(s)
+ gamma_over_implicit_ts, & ! Constant(s)
+ one, &
+ zero
use model_flags, only: &
l_clip_semi_implicit, & ! Variable(s)
l_upwind_wpxp_ta
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use clip_semi_implicit, only: &
clip_semi_imp_rhs ! Procedure(s)
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_update_var_pt, &
stat_begin_update_pt
use stats_variables, only: &
- zt, & ! Variable(s)
- zm, &
+ stats_zt, & ! Variable(s)
+ stats_zm, &
irtm_forcing, &
ithlm_forcing, &
iwprtp_bp, &
- iwprtp_pr3, &
+ iwprtp_pr3, &
iwprtp_sicl, &
iwprtp_ta, &
iwprtp_pr1, &
+ iwprtp_forcing, &
iwpthlp_bp, &
iwpthlp_pr3, &
iwpthlp_sicl, &
iwpthlp_ta, &
iwpthlp_pr1, &
+ iwpthlp_forcing, &
l_stats_samp
use advance_helper_module, only: set_boundary_conditions_rhs
@@ -1369,17 +1472,18 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
logical, intent(in) :: l_iter
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
xm, & ! xm (thermodynamic levels) [{xm units}]
- wpxp, & ! w'x' (momentum levels) [{xm units} m/s]
+ wpxp, & ! (momentum levels) [{xm units} m/s]
xm_forcing, & ! xm forcings (thermodynamic levels) [{xm units}/s]
+ wpxp_forcing, & ! forcing (momentum levels) [{xm units} m/s^2]
C7_Skw_fnc, & ! C_7 parameter with Sk_w applied [-]
xpthvp, & ! x'th_v' (momentum levels) [{xm units} K]
C6x_Skw_fnc, & ! C_6x parameter with Sk_w applied [-]
- tau_zm, & ! Time-scale tau on momentum levels [s]
+ tau_C6_zm, & ! Time-scale tau on momentum levels applied to the C6 term [s]
a1_zt, & ! a_1 interpolated to thermodynamic levels [-]
a1, & ! a_1 [-]
wp3_on_wp2, & ! Smoothed wp3 / wp2 on moment. levels [m/s]
@@ -1413,7 +1517,8 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
integer :: &
ixm_f, &
iwpxp_bp, &
- iwpxp_pr3, &
+ iwpxp_pr3, &
+ iwpxp_f, &
iwpxp_sicl, &
iwpxp_ta, &
iwpxp_pr1
@@ -1427,6 +1532,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
ixm_f = irtm_forcing
iwpxp_bp = iwprtp_bp
iwpxp_pr3 = iwprtp_pr3
+ iwpxp_f = iwprtp_forcing
iwpxp_sicl = iwprtp_sicl
iwpxp_ta = iwprtp_ta
iwpxp_pr1 = iwprtp_pr1
@@ -1434,6 +1540,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
ixm_f = ithlm_forcing
iwpxp_bp = iwpthlp_bp
iwpxp_pr3 = iwpthlp_pr3
+ iwpxp_f = iwpthlp_forcing
iwpxp_sicl = iwpthlp_sicl
iwpxp_ta = iwpthlp_ta
iwpxp_pr1 = iwpthlp_pr1
@@ -1441,6 +1548,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
ixm_f = 0
iwpxp_bp = 0
iwpxp_pr3 = 0
+ iwpxp_f = 0
iwpxp_sicl = 0
iwpxp_ta = 0
iwpxp_pr1 = 0
@@ -1448,7 +1556,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
! Initialize the right-hand side vector to 0.
- rhs = 0.0_core_rknd
+ rhs = zero
! The xm loop runs between k = 2 and k = gr%nz. The value of xm at
! level k = 1, which is below the model surface, is simply set equal to the
@@ -1467,7 +1575,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
! xm: Right-hand side (explicit xm portion of the code).
! RHS time tendency.
- rhs(k_xm) = rhs(k_xm) + xm(k) / real( dt, kind = core_rknd )
+ rhs(k_xm) = rhs(k_xm) + xm(k) / dt
! RHS xm forcings.
! Note: xm forcings include the effects of microphysics,
@@ -1481,7 +1589,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
! (including microphysics/radiation).
! xm forcings term is completely explicit; call stat_update_var_pt.
- call stat_update_var_pt( ixm_f, k, xm_forcing(k), zt )
+ call stat_update_var_pt( ixm_f, k, xm_forcing(k), stats_zt )
endif ! l_stats_samp
@@ -1514,9 +1622,13 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
! RHS time tendency.
if ( l_iter ) then
- rhs(k_wpxp) = rhs(k_wpxp) + wpxp(k) / real( dt, kind = core_rknd )
+ rhs(k_wpxp) = rhs(k_wpxp) + wpxp(k) / dt
end if
+ ! RHS forcing.
+ ! Note: forcing includes the effects of microphysics on .
+ rhs(k_wpxp) = rhs(k_wpxp) + wpxp_forcing(k)
+
! RHS portion of semi-implicit clipping (sicl) term.
if ( l_clip_semi_implicit ) then
l_upper_thresh = .true.
@@ -1564,7 +1676,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
rhs(k_wpxp) &
= rhs(k_wpxp) &
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) &
+ + ( one - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(1) * wpxp(kp1) &
- lhs_fnc_output(2) * wpxp(k) &
- lhs_fnc_output(3) * wpxp(km1) )
@@ -1574,10 +1686,10 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
!
! Note: An "over-implicit" weighted time step is applied to this term.
lhs_fnc_output(1) &
- = wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_zm(k) )
+ = wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_C6_zm(k) )
rhs(k_wpxp) &
= rhs(k_wpxp) &
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) &
+ + ( one - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(1) * wpxp(k) )
@@ -1589,15 +1701,18 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
! Note: To find the contribution of w'x' term bp, substitute 0 for the
! C_7 skewness function input to function wpxp_terms_bp_pr3_rhs.
call stat_update_var_pt( iwpxp_bp, k, &
- wpxp_terms_bp_pr3_rhs( 0.0_core_rknd, thv_ds_zm(k), xpthvp(k) ), zm )
+ wpxp_terms_bp_pr3_rhs( zero, thv_ds_zm(k), xpthvp(k) ), stats_zm )
! w'x' term pr3 is completely explicit; call stat_update_var_pt.
! Note: To find the contribution of w'x' term pr3, add 1 to the
! C_7 skewness function input to function wpxp_terms_bp_pr2_rhs.
call stat_update_var_pt( iwpxp_pr3, k, &
- wpxp_terms_bp_pr3_rhs( (1.0_core_rknd+C7_Skw_fnc(k)), thv_ds_zm(k), &
+ wpxp_terms_bp_pr3_rhs( (one+C7_Skw_fnc(k)), thv_ds_zm(k), &
xpthvp(k) ), &
- zm )
+ stats_zm )
+
+ ! w'x' forcing term is completely explicit; call stat_update_var_pt.
+ call stat_update_var_pt( iwpxp_f, k, wpxp_forcing(k), stats_zm )
! w'x' term sicl has both implicit and explicit components; call
! stat_begin_update_pt. Since stat_begin_update_pt automatically
@@ -1608,7 +1723,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
call stat_begin_update_pt( iwpxp_sicl, k, &
-clip_semi_imp_rhs( dt, wpxp(k), &
l_upper_thresh, wpxp_upper_lim(k), &
- l_lower_thresh, wpxp_lower_lim(k) ), zm )
+ l_lower_thresh, wpxp_lower_lim(k) ), stats_zm )
endif
if ( l_upwind_wpxp_ta ) then ! Use upwind differencing
@@ -1638,10 +1753,10 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
endif
call stat_begin_update_pt( iwpxp_ta, k, &
- - ( 1.0_core_rknd - gamma_over_implicit_ts ) &
+ - ( one - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(1) * wpxp(kp1) &
- lhs_fnc_output(2) * wpxp(k) &
- - lhs_fnc_output(3) * wpxp(km1) ), zm )
+ - lhs_fnc_output(3) * wpxp(km1) ), stats_zm )
! w'x' term pr1 is normally completely implicit. However, there is a
! RHS contribution from the "over-implicit" weighted time step. A
@@ -1653,10 +1768,10 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
! automatically subtracts the value sent in, reverse the sign on the
! input value.
lhs_fnc_output(1) &
- = wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_zm(k) )
+ = wpxp_term_pr1_lhs( C6x_Skw_fnc(k), tau_C6_zm(k) )
call stat_begin_update_pt( iwpxp_pr1, k, &
- - ( 1.0_core_rknd - gamma_over_implicit_ts ) &
- * ( - lhs_fnc_output(1) * wpxp(k) ), zm )
+ - ( one - gamma_over_implicit_ts ) &
+ * ( - lhs_fnc_output(1) * wpxp(k) ), stats_zm )
endif ! l_stats_samp
@@ -1698,7 +1813,7 @@ subroutine xm_wpxp_rhs( solve_type, l_iter, dt, xm, wpxp, &
! The value of w'x' at the upper boundary will be 0.
call set_boundary_conditions_rhs( &
- wpxp(1), k_wpxp_low, 0.0_core_rknd, k_wpxp_high, &
+ wpxp(1), k_wpxp_low, zero, k_wpxp_high, &
rhs, &
xm(1), k_xm_low )
@@ -1792,8 +1907,7 @@ subroutine xm_wpxp_clipping_and_stats &
l_clip_semi_implicit ! Variable(s)
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use mono_flux_limiter, only: &
monotonic_turbulent_flux_limit ! Procedure(s)
@@ -1808,21 +1922,23 @@ subroutine xm_wpxp_clipping_and_stats &
clip_wpsclrp
use model_flags, only: &
- l_pos_def, & ! Logical for whether to apply the positive definite scheme to rtm
- l_hole_fill, & ! Logical for whether to apply the hole filling scheme to thlm/rtm
- l_clip_turb_adv ! Logical for whether to clip xm when wpxp is clipped
+ l_pos_def, & ! Logical for whether to apply the positive definite scheme to rtm
+ l_hole_fill, & ! Logical for whether to apply the hole filling scheme to thlm/rtm
+ l_clip_turb_adv ! Logical for whether to clip xm when wpxp is clipped
use constants_clubb, only: &
- fstderr ! Standard error i/o unit
+ fstderr, & ! Constant(s)
+ one, &
+ zero
use fill_holes, only: &
- fill_holes_driver ! Procedure
+ fill_holes_vertical ! Procedure
use error_code, only: &
clubb_at_least_debug_level, & ! Procedure(s)
clubb_no_error ! Constant
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update, & ! Procedure(s)
stat_update_var_pt, &
stat_end_update_pt, &
@@ -1831,9 +1947,9 @@ subroutine xm_wpxp_clipping_and_stats &
stat_modify
use stats_variables, only: &
- zt, & ! Variable(s)
- zm, &
- sfc, &
+ stats_zt, & ! Variable(s)
+ stats_zm, &
+ stats_sfc, &
irtm_ta, &
irtm_ma, &
irtm_matrix_condt_num, &
@@ -1849,7 +1965,9 @@ subroutine xm_wpxp_clipping_and_stats &
iwprtp_dp1, &
iwprtp_pd, &
iwprtp_sicl, &
- ithlm_ta, &
+ ithlm_ta
+
+ use stats_variables, only: &
ithlm_ma, &
ithlm_cl, &
ithlm_matrix_condt_num, &
@@ -1899,7 +2017,7 @@ subroutine xm_wpxp_clipping_and_stats &
integer, intent(in) :: &
solve_type ! Variables being solved for.
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep [s]
real( kind = core_rknd ), intent(in), dimension(gr%nz) :: &
@@ -2063,7 +2181,7 @@ subroutine xm_wpxp_clipping_and_stats &
if ( ixm_matrix_condt_num > 0 ) then
! Est. of the condition number of the mean/flux LHS matrix
- call stat_update_var_pt( ixm_matrix_condt_num, 1, 1.0_core_rknd / rcond, sfc )
+ call stat_update_var_pt( ixm_matrix_condt_num, 1, one / rcond, stats_sfc )
end if
@@ -2083,12 +2201,12 @@ subroutine xm_wpxp_clipping_and_stats &
call stat_update_var_pt( ixm_ma, k, &
ztscr01(k) * xm(km1) &
+ ztscr02(k) * xm(k) &
- + ztscr03(k) * xm(kp1), zt )
+ + ztscr03(k) * xm(kp1), stats_zt )
! xm term ta is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( ixm_ta, k, &
ztscr04(k) * wpxp(km1) &
- + ztscr05(k) * wpxp(k), zt )
+ + ztscr05(k) * wpxp(k), stats_zt )
enddo ! xm loop: 2..gr%nz
@@ -2109,7 +2227,7 @@ subroutine xm_wpxp_clipping_and_stats &
call stat_update_var_pt( iwpxp_ma, k, &
zmscr01(k) * wpxp(km1) &
+ zmscr02(k) * wpxp(k) &
- + zmscr03(k) * wpxp(kp1), zm )
+ + zmscr03(k) * wpxp(kp1), stats_zm )
! if( .not. l_upwind_wpxp_ta ) then
! w'x' term ta is normally completely implicit. However, due to the
@@ -2119,40 +2237,40 @@ subroutine xm_wpxp_clipping_and_stats &
call stat_end_update_pt( iwpxp_ta, k, &
zmscr04(k) * wpxp(km1) &
+ zmscr05(k) * wpxp(k) &
- + zmscr06(k) * wpxp(kp1), zm )
+ + zmscr06(k) * wpxp(kp1), stats_zm )
! endif
! w'x' term tp is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwpxp_tp, k, &
zmscr07(k) * xm(k) &
- + zmscr08(k) * xm(kp1), zm )
+ + zmscr08(k) * xm(kp1), stats_zm )
! w'x' term ac is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwpxp_ac, k, &
- zmscr09(k) * wpxp(k), zm )
+ zmscr09(k) * wpxp(k), stats_zm )
! w'x' term pr1 is normally completely implicit. However, due to the
! RHS contribution from the "over-implicit" weighted time step,
! w'x' term pr1 has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( iwpxp_pr1, k, &
- zmscr10(k) * wpxp(k), zm )
+ zmscr10(k) * wpxp(k), stats_zm )
! w'x' term pr2 is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwpxp_pr2, k, &
- zmscr11(k) * wpxp(k), zm )
+ zmscr11(k) * wpxp(k), stats_zm )
! w'x' term dp1 is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( iwpxp_dp1, k, &
zmscr12(k) * wpxp(km1) &
+ zmscr13(k) * wpxp(k) &
- + zmscr14(k) * wpxp(kp1), zm )
+ + zmscr14(k) * wpxp(kp1), stats_zm )
! w'x' term sicl has both implicit and explicit components;
! call stat_end_update_pt.
if ( l_clip_semi_implicit ) then
call stat_end_update_pt( iwpxp_sicl, k, &
- zmscr15(k) * wpxp(k), zm )
+ zmscr15(k) * wpxp(k), stats_zm )
endif
enddo ! wpxp loop: 2..gr%nz-1
@@ -2174,30 +2292,30 @@ subroutine xm_wpxp_clipping_and_stats &
! Apply a flux limiting positive definite scheme if the solution
! for the mean field is negative and we're determining total water
- if ( solve_type == xm_wpxp_rtm .and. l_pos_def .and. any( xm < 0.0_core_rknd ) ) then
+ if ( solve_type == xm_wpxp_rtm .and. l_pos_def .and. any( xm < zero ) ) then
call pos_definite_adj( dt, "zt", xm, wpxp, &
xm_n, xm_pd, wpxp_pd )
else
! For stats purposes
- xm_pd = 0.0_core_rknd
- wpxp_pd = 0.0_core_rknd
+ xm_pd = zero
+ wpxp_pd = zero
end if ! l_pos_def and solve_type == "rtm" and rtm less than 0
if ( l_stats_samp ) then
- call stat_update_var( iwpxp_pd, wpxp_pd(1:gr%nz), zm )
+ call stat_update_var( iwpxp_pd, wpxp_pd(1:gr%nz), stats_zm )
- call stat_update_var( ixm_pd, xm_pd(1:gr%nz), zt )
+ call stat_update_var( ixm_pd, xm_pd(1:gr%nz), stats_zt )
end if
! Computed value before clipping
if ( l_stats_samp ) then
- call stat_begin_update( ixm_cl, xm / real( dt, kind = core_rknd ), & ! Intent(in)
- zt ) ! Intent(inout)
+ call stat_begin_update( ixm_cl, xm / dt, & ! Intent(in)
+ stats_zt ) ! Intent(inout)
end if
if ( any( xm < xm_threshold ) .and. l_hole_fill ) then
@@ -2213,22 +2331,22 @@ subroutine xm_wpxp_clipping_and_stats &
if ( clubb_at_least_debug_level( 1 ) ) then
do k = 1, gr%nz
- if ( xm(k) < 0.0_core_rknd ) then
+ if ( xm(k) < zero ) then
write(fstderr,*) solve_type_str//" < ", xm_threshold, &
" in advance_xm_wpxp_module at k= ", k
end if
end do
end if
- call fill_holes_driver( 2, xm_threshold, "zt", &
- rho_ds_zt, rho_ds_zm, &
- xm )
+ call fill_holes_vertical( 2, xm_threshold, "zt", &
+ rho_ds_zt, rho_ds_zm, &
+ xm )
end if ! any( xm < xm_threshold ) .and. l_hole_fill
if ( l_stats_samp ) then
- call stat_end_update( ixm_cl, xm / real( dt, kind = core_rknd ), & ! Intent(in)
- zt ) ! Intent(inout)
+ call stat_end_update( ixm_cl, xm / dt, & ! Intent(in)
+ stats_zt ) ! Intent(inout)
end if
! Use solve_type to find solve_type_cl, which is used
@@ -2279,7 +2397,7 @@ subroutine xm_wpxp_clipping_and_stats &
wpxp, wpxp_chnge ) ! In/Out
! Adjusting xm based on clipping for w'x'.
- if ( any( wpxp_chnge /= 0.0_core_rknd ) .and. l_clip_turb_adv ) then
+ if ( any( wpxp_chnge /= zero ) .and. l_clip_turb_adv ) then
call xm_correction_wpxp_cl( solve_type, dt, wpxp_chnge, gr%invrs_dzt, &
xm )
endif
@@ -2287,7 +2405,7 @@ subroutine xm_wpxp_clipping_and_stats &
if ( l_stats_samp ) then
! wpxp time tendency
- call stat_modify( iwpxp_bt, wpxp / real( dt, kind = core_rknd ), zm )
+ call stat_modify( iwpxp_bt, wpxp / dt, stats_zm )
! Brian Griffin; July 5, 2008.
endif
@@ -2346,7 +2464,7 @@ pure function xm_term_ta_lhs( rho_ds_zm, rho_ds_zmm1, &
!-----------------------------------------------------------------------
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2365,6 +2483,7 @@ pure function xm_term_ta_lhs( rho_ds_zm, rho_ds_zmm1, &
! Return Variable
real( kind = core_rknd ), dimension(2) :: lhs
+
! Momentum superdiagonal [ x wpxp(k,) ]
lhs(k_mdiag) &
= + invrs_rho_ds_zt * invrs_dzt * rho_ds_zm
@@ -2373,6 +2492,7 @@ pure function xm_term_ta_lhs( rho_ds_zm, rho_ds_zmm1, &
lhs(km1_mdiag) &
= - invrs_rho_ds_zt * invrs_dzt * rho_ds_zmm1
+
return
end function xm_term_ta_lhs
@@ -2453,7 +2573,7 @@ pure function wpxp_term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
!-----------------------------------------------------------------------
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
use grid_class, only: &
gr ! Variable; gr%weights_zm2zt
@@ -2512,6 +2632,7 @@ pure function wpxp_term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! sclr'^2 (found in advance_xp2_xpyp_module.F90). Brian.
! if ( l_standard_term_ta ) then
+
! Always use the standard discretization for the w'x' turbulent advection
! term. Brian.
@@ -2550,6 +2671,7 @@ pure function wpxp_term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
* gr%weights_zm2zt(m_below,tk)
! else
+
! This discretization very similar to what Brian did for the xp2_ta terms
! and is intended to stabilize the simulation by pulling a1 out of the
! derivative. It didn't seem to work very well. -dschanen 17 Jan 2010
@@ -2582,7 +2704,8 @@ pure function wpxp_term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! * wp3_on_wp2_zt &
! * gr%weights_zm2zt(m_below,tk)
-! end if ! l_standard_term_ta
+! endif ! l_standard_term_ta
+
return
end function wpxp_term_ta_lhs
@@ -2600,8 +2723,11 @@ pure function wpxp_term_ta_lhs_upwind( a1_zm, a1_zm_p1, a1_zm_m1, &
! References:
!-----------------------------------------------------------------------
+ use constants_clubb, only: &
+ zero ! Constant(s)
+
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2629,28 +2755,34 @@ pure function wpxp_term_ta_lhs_upwind( a1_zm, a1_zm_p1, a1_zm_m1, &
! Return Variable
real( kind = core_rknd ), dimension(3) :: lhs
- if ( wp3_on_wp2 > 0._core_rknd ) then ! "Wind" is blowing upwards (a1_zm > 0 and wp2 > 0 always)
- lhs(kp1_mdiag) = 0.0_core_rknd
+
+ if ( wp3_on_wp2 > zero ) then
+
+ ! "Wind" is blowing upwards (a1_zm > 0 and wp2 > 0 always)
+ lhs(kp1_mdiag) = zero
lhs(k_mdiag) &
= + invrs_dzt * invrs_rho_ds_zm &
- * rho_ds_zm * a1_zm * wp3_on_wp2
+ * rho_ds_zm * a1_zm * wp3_on_wp2
lhs(km1_mdiag) &
= - invrs_dzt * invrs_rho_ds_zm &
- * rho_ds_zmm1 * a1_zm_m1 * wp3_on_wp2_m1
+ * rho_ds_zmm1 * a1_zm_m1 * wp3_on_wp2_m1
else ! "Wind" is blowing downward
+
lhs(kp1_mdiag) &
= + invrs_dztkp1 * invrs_rho_ds_zm &
- * rho_ds_zmp1 * a1_zm_p1 * wp3_on_wp2_p1
+ * rho_ds_zmp1 * a1_zm_p1 * wp3_on_wp2_p1
lhs(k_mdiag) &
= - invrs_dztkp1 * invrs_rho_ds_zm &
- * rho_ds_zm * a1_zm * wp3_on_wp2
+ * rho_ds_zm * a1_zm * wp3_on_wp2
+
+ lhs(km1_mdiag) = zero
+
+ endif
- lhs(km1_mdiag) = 0.0_core_rknd
- end if
return
end function wpxp_term_ta_lhs_upwind
@@ -2701,7 +2833,7 @@ pure function wpxp_term_tp_lhs( wp2, invrs_dzm ) &
!-----------------------------------------------------------------------
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2718,6 +2850,7 @@ pure function wpxp_term_tp_lhs( wp2, invrs_dzm ) &
! Return Variable
real( kind = core_rknd ), dimension(2) :: lhs
+
! Thermodynamic superdiagonal [ x xm(k+1,) ]
lhs(kp1_tdiag) &
= + wp2 * invrs_dzm
@@ -2726,6 +2859,7 @@ pure function wpxp_term_tp_lhs( wp2, invrs_dzm ) &
lhs(k_tdiag) &
= - wp2 * invrs_dzm
+
return
end function wpxp_term_tp_lhs
@@ -2784,8 +2918,11 @@ pure function wpxp_terms_ac_pr2_lhs( C7_Skw_fnc, &
! References:
!-----------------------------------------------------------------------
+ use constants_clubb, only: &
+ one ! Constant(s)
+
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2800,15 +2937,16 @@ pure function wpxp_terms_ac_pr2_lhs( C7_Skw_fnc, &
! Return Variable
real( kind = core_rknd ) :: lhs
+
! Momentum main diagonal: [ x wpxp(k,) ]
- lhs &
- = + ( 1.0_core_rknd - C7_Skw_fnc ) * invrs_dzm * ( wm_ztp1 - wm_zt )
+ lhs = ( one - C7_Skw_fnc ) * invrs_dzm * ( wm_ztp1 - wm_zt )
+
return
end function wpxp_terms_ac_pr2_lhs
!=============================================================================
- pure function wpxp_term_pr1_lhs( C6x_Skw_fnc, tau_zm ) &
+ pure function wpxp_term_pr1_lhs( C6x_Skw_fnc, tau_C6_zm ) &
result( lhs )
! Description
@@ -2838,21 +2976,22 @@ pure function wpxp_term_pr1_lhs( C6x_Skw_fnc, tau_zm ) &
!-----------------------------------------------------------------------
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
! Input Variables
real( kind = core_rknd ), intent(in) :: &
- C6x_Skw_fnc, & ! C_6x parameter with Sk_w applied (k) [-]
- tau_zm ! Time-scale tau at momentum level (k) [s]
+ C6x_Skw_fnc, & ! C_6x parameter with Sk_w applied (k) [-]
+ tau_C6_zm ! Time-scale tau at momentum level (k) applied to C6 term [s]
! Return Variable
real( kind = core_rknd ) :: lhs
+
! Momentum main diagonal: [ x wpxp(k,) ]
- lhs &
- = + C6x_Skw_fnc / tau_zm
+ lhs = C6x_Skw_fnc / tau_C6_zm
+
return
end function wpxp_term_pr1_lhs
@@ -2883,10 +3022,11 @@ pure function wpxp_terms_bp_pr3_rhs( C7_Skw_fnc, thv_ds_zm, xpthvp ) &
!-----------------------------------------------------------------------
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
- use constants_clubb, only: & ! Variable(s)
- grav ! Gravitational acceleration [m/s^2]
+ use constants_clubb, only: & ! Constants(s)
+ grav, & ! Gravitational acceleration [m/s^2]
+ one
implicit none
@@ -2899,8 +3039,9 @@ pure function wpxp_terms_bp_pr3_rhs( C7_Skw_fnc, thv_ds_zm, xpthvp ) &
! Return Variable
real( kind = core_rknd ) :: rhs
- rhs &
- = ( grav / thv_ds_zm ) * ( 1.0_core_rknd - C7_Skw_fnc ) * xpthvp
+
+ rhs = ( grav / thv_ds_zm ) * ( one - C7_Skw_fnc ) * xpthvp
+
return
end function wpxp_terms_bp_pr3_rhs
@@ -3023,15 +3164,14 @@ subroutine xm_correction_wpxp_cl( solve_type, dt, wpxp_chnge, invrs_dzt, &
gr ! Variable(s); gr%nz only.
use clubb_precision, only: &
- time_precision, &
- core_rknd
+ core_rknd ! Variable(s)
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_update_var ! Procedure(s)
use stats_variables, only: &
l_stats_samp, & ! Variable(s)
- zt, &
+ stats_zt, &
ithlm_tacl, &
irtm_tacl
@@ -3041,7 +3181,7 @@ subroutine xm_correction_wpxp_cl( solve_type, dt, wpxp_chnge, invrs_dzt, &
integer, intent(in) :: &
solve_type ! Variable that is being solved for.
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
@@ -3075,13 +3215,13 @@ subroutine xm_correction_wpxp_cl( solve_type, dt, wpxp_chnge, invrs_dzt, &
! highest.
do k = 2, gr%nz, 1
xm_tndcy_wpxp_cl(k) = - invrs_dzt(k) * ( wpxp_chnge(k) - wpxp_chnge(k-1) )
- xm(k) = xm(k) + xm_tndcy_wpxp_cl(k) * real( dt, kind = core_rknd )
+ xm(k) = xm(k) + xm_tndcy_wpxp_cl(k) * dt
enddo
if ( l_stats_samp ) then
! The adjustment to xm due to turbulent advection term clipping
! (xm term tacl) is completely explicit; call stat_update_var.
- call stat_update_var( ixm_tacl, xm_tndcy_wpxp_cl, zt )
+ call stat_update_var( ixm_tacl, xm_tndcy_wpxp_cl, stats_zt )
endif
@@ -3091,16 +3231,19 @@ end subroutine xm_correction_wpxp_cl
!=============================================================================
-
- pure function damp_coefficient( coefficient, Cx_Skw_fnc, max_coeff_value, threshold, Lscale ) &
+ pure function damp_coefficient( coefficient, Cx_Skw_fnc, max_coeff_value, &
+ threshold, Lscale ) &
result( damped_value )
! Description:
! Damps a given coefficient linearly based on the value of Lscale.
! For additional information see CLUBB ticket #431.
+ use constants_clubb, only: &
+ one_hundred ! Constant(s)
+
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
use grid_class, only: &
gr ! Variable(s)
@@ -3112,6 +3255,7 @@ pure function damp_coefficient( coefficient, Cx_Skw_fnc, max_coeff_value, thresh
coefficient, & ! The coefficient to be damped
max_coeff_value, & ! Maximum value the damped coefficient should have
threshold ! Value of Lscale below which the damping should occur
+
real( kind = core_rknd ), dimension(gr%nz), intent(in) :: &
Lscale, & ! Current value of Lscale
Cx_Skw_fnc ! Initial skewness function before damping
@@ -3119,7 +3263,7 @@ pure function damp_coefficient( coefficient, Cx_Skw_fnc, max_coeff_value, thresh
! Local variables
real( kind = core_rknd ), parameter :: &
! Added to prevent large damping at low altitudes where Lscale is small
- altitude_threshold = 100.0_core_rknd ! Altitude above which damping should occur
+ altitude_threshold = one_hundred ! Altitude above which damping should occur
! Return Variable
real( kind = core_rknd ), dimension(gr%nz) :: damped_value
@@ -3127,7 +3271,9 @@ pure function damp_coefficient( coefficient, Cx_Skw_fnc, max_coeff_value, thresh
damped_value = Cx_Skw_fnc
where( Lscale < threshold .and. gr%zt > altitude_threshold)
- damped_value = max_coeff_value + ( ( coefficient - max_coeff_value ) / threshold ) * Lscale
+ damped_value = max_coeff_value &
+ + ( ( coefficient - max_coeff_value ) / threshold ) &
+ * Lscale
end where
return
diff --git a/models/atm/cam/src/physics/clubb/advance_xp2_xpyp_module.F90 b/models/atm/cam/src/physics/clubb/advance_xp2_xpyp_module.F90
index 90e239ae73bb..e32312ab6f05 100644
--- a/models/atm/cam/src/physics/clubb/advance_xp2_xpyp_module.F90
+++ b/models/atm/cam/src/physics/clubb/advance_xp2_xpyp_module.F90
@@ -1,5 +1,5 @@
!-----------------------------------------------------------------------
-! $Id: advance_xp2_xpyp_module.F90 5623 2012-01-17 17:55:26Z connork@uwm.edu $
+! $Id: advance_xp2_xpyp_module.F90 7315 2014-09-30 20:49:54Z schemena@uwm.edu $
!===============================================================================
module advance_xp2_xpyp_module
@@ -9,7 +9,8 @@ module advance_xp2_xpyp_module
implicit none
- public :: advance_xp2_xpyp
+ public :: advance_xp2_xpyp, &
+ update_xp2_mc
private :: xp2_xpyp_lhs, &
xp2_xpyp_solve, &
@@ -43,17 +44,16 @@ module advance_xp2_xpyp_module
contains
!=============================================================================
- subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
- thlm, wpthlp, wpthvp, um, vm, &
- wp2, wp2_zt, wp3, upwp, vpwp, &
- sigma_sqd_w, Skw_zm, Kh_zt, &
- rho_ds_zm, rho_ds_zt, &
+ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, thlm, &
+ wpthlp, wpthvp, um, vm, wp2, wp2_zt, &
+ wp3, upwp, vpwp, sigma_sqd_w, Skw_zm, &
+ Kh_zt, rtp2_forcing, thlp2_forcing, &
+ rtpthlp_forcing, rho_ds_zm, rho_ds_zt, &
invrs_rho_ds_zm, thv_ds_zm, &
Lscale, wp3_on_wp2, wp3_on_wp2_zt, &
l_iter, dt, &
sclrm, wpsclrp, &
- rtp2, thlp2, rtpthlp, &
- up2, vp2, &
+ rtp2, thlp2, rtpthlp, up2, vp2, &
err_code, &
sclrp2, sclrprtp, sclrpthlp )
@@ -72,11 +72,16 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!-----------------------------------------------------------------------
use constants_clubb, only: &
- w_tol_sqd, & ! Variable(s)
+ w_tol_sqd, & ! Constant(s)
rt_tol, &
thl_tol, &
w_tol_sqd, &
fstderr, &
+ one, &
+ two_thirds, &
+ one_half, &
+ one_third, &
+ zero, &
zero_threshold
use model_flags, only: &
@@ -108,26 +113,21 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
zm2zt ! Procedure(s)
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use clip_explicit, only: &
clip_covar, & ! Procedure(s)
clip_variance, &
- clip_rtp2, & ! Variable(s)
- clip_thlp2, &
- clip_rtpthlp, &
- clip_up2, &
- clip_vp2, &
clip_sclrp2, &
clip_sclrprtp, &
clip_sclrpthlp
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_modify
use error_code, only: &
clubb_no_error, & ! Variable(s)
+ clubb_var_out_of_range, &
clubb_singular_matrix
use error_code, only: &
@@ -135,7 +135,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
clubb_at_least_debug_level
use stats_variables, only: &
- zm, &
+ stats_zm, &
irtp2_cl, &
l_stats_samp
@@ -154,38 +154,41 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
l_clip_large_rtp2 = .true. ! Clip rtp2 to be < rtm^2 * coef
real( kind = core_rknd ), parameter :: &
- rtp2_clip_coef = 0.5_core_rknd ! Coefficient appled the clipping threshold on rtp2 [-]
+ rtp2_clip_coef = one_half ! Coefficient appled the clipping threshold on rtp2 [-]
! Input variables
real( kind = core_rknd ), intent(in), dimension(gr%nz) :: &
tau_zm, & ! Time-scale tau on momentum levels [s]
wm_zm, & ! w-wind component on momentum levels [m/s]
rtm, & ! Total water mixing ratio (t-levs) [kg/kg]
- wprtp, & ! w' r_t' (momentum levels) [(m/s)(kg/kg)]
+ wprtp, & ! (momentum levels) [(m/s)(kg/kg)]
thlm, & ! Liquid potential temp. (t-levs) [K]
- wpthlp, & ! w' th_l' (momentum levels) [(m K)/s]
- wpthvp, & ! w' th_v' (momentum levels) [(m K)/s]
+ wpthlp, & ! (momentum levels) [(m K)/s]
+ wpthvp, & ! (momentum levels) [(m K)/s]
um, & ! u wind (thermodynamic levels) [m/s]
vm, & ! v wind (thermodynamic levels) [m/s]
- wp2, & ! w'^2 (momentum levels) [m^2/s^2]
- wp2_zt, & ! w'^2 interpolated to thermo. levels [m^2/s^2]
- wp3, & ! w'^3 (thermodynamic levels) [m^3/s^3]
- upwp, & ! u'w' (momentum levels) [m^2/s^2]
- vpwp, & ! v'w' (momentum levels) [m^2/s^2]
+ wp2, & ! (momentum levels) [m^2/s^2]
+ wp2_zt, & ! interpolated to thermo. levels [m^2/s^2]
+ wp3, & ! (thermodynamic levels) [m^3/s^3]
+ upwp, & ! (momentum levels) [m^2/s^2]
+ vpwp, & ! (momentum levels) [m^2/s^2]
sigma_sqd_w, & ! sigma_sqd_w (momentum levels) [-]
Skw_zm, & ! Skewness of w on momentum levels [-]
Kh_zt, & ! Eddy diffusivity on thermo. levels [m^2/s]
+ rtp2_forcing, & ! forcing (momentum levels) [(kg/kg)^2/s]
+ thlp2_forcing, & ! forcing (momentum levels) [K^2/s]
+ rtpthlp_forcing, & ! forcing (momentum levels) [(kg/kg)K/s]
rho_ds_zm, & ! Dry, static density on momentum levs. [kg/m^3]
rho_ds_zt, & ! Dry, static density on thermo. levels [kg/m^3]
invrs_rho_ds_zm, & ! Inv. dry, static density @ mom. levs. [m^3/kg]
thv_ds_zm, & ! Dry, base-state theta_v on mom. levs. [K]
Lscale, & ! Mixing length [m]
- wp3_on_wp2, & ! Smoothed version of w'^3 / w'^2 zm [m/s]
- wp3_on_wp2_zt ! Smoothed version of w'^3 / w'^2 zt [m/s]
+ wp3_on_wp2, & ! Smoothed version of / zm [m/s]
+ wp3_on_wp2_zt ! Smoothed version of / zt [m/s]
logical, intent(in) :: l_iter ! Whether variances are prognostic
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
! Passive scalar input
@@ -196,11 +199,11 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! An attribute of (inout) is also needed to import the value of the variances
! at the surface. Brian. 12/18/05.
real( kind = core_rknd ), intent(inout), dimension(gr%nz) :: &
- rtp2, & ! r_t'^2 [(kg/kg)^2]
- thlp2, & ! th_l'^2 [K^2]
- rtpthlp, & ! r_t' th_l' [(kg K)/kg]
- up2, & ! u'^2 [m^2/s^2]
- vp2 ! v'^2 [m^2/s^2]
+ rtp2, & ! [(kg/kg)^2]
+ thlp2, & ! [K^2]
+ rtpthlp, & ! [(kg K)/kg]
+ up2, & ! [m^2/s^2]
+ vp2 ! [m^2/s^2]
! Output variable for singular matrices
integer, intent(inout) :: err_code
@@ -218,9 +221,9 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
a1 ! a_1 (momentum levels); See eqn. 24 in `Equations for CLUBB' [-]
real( kind = core_rknd ), dimension(gr%nz) :: &
- upwp_zt, & ! u'w' interpolated to thermodynamic levels [m^2/s^2]
- vpwp_zt, & ! v'w' interpolated to thermodynamic levels [m^2/s^2]
- wpsclrp_zt ! w'sclr' interpolated to thermodynamic levels [m/s {sclrm units}]
+ upwp_zt, & ! interpolated to thermodynamic levels [m^2/s^2]
+ vpwp_zt, & ! interpolated to thermodynamic levels [m^2/s^2]
+ wpsclrp_zt ! interp. to thermo. levels [m/s {sclrm units}]
real( kind = core_rknd ) :: &
threshold ! Minimum value for variances [units vary]
@@ -259,6 +262,11 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
sclrprtp_chnge, & ! Net change in sclr'r_t' due to clipping [{units vary}]
sclrpthlp_chnge ! Net change in sclr'th_l' due to clipping [{units vary}]
+ real( kind = core_rknd ), dimension(gr%nz) :: &
+ sclrp2_forcing, & ! forcing (momentum levels) [units vary]
+ sclrprtp_forcing, & ! forcing (momentum levels) [units vary]
+ sclrpthlp_forcing ! forcing (momentum levels) [units vary]
+
logical :: l_scalar_calc, l_first_clip_ts, l_last_clip_ts
! Loop indices
@@ -266,10 +274,19 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!---------------------------- Begin Code ----------------------------------
+ if ( clubb_at_least_debug_level( 2 ) ) then
+ ! Assertion check for C5
+ if ( C5 > one .or. C5 < zero ) then
+ write(fstderr,*) "The C5 variable is outside the valid range"
+ err_code = clubb_var_out_of_range
+ return
+ end if
+ end if
+
if ( l_single_C2_Skw ) then
! Use a single value of C2 for all equations.
C2rt_1d(1:gr%nz) &
- = C2b + (C2-C2b) *exp( -0.5_core_rknd * (Skw_zm(1:gr%nz)/C2c)**2 )
+ = C2b + (C2-C2b) *exp( -one_half * (Skw_zm(1:gr%nz)/C2c)**2 )
C2thl_1d = C2rt_1d
C2rtthl_1d = C2rt_1d
@@ -285,8 +302,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
end if
! Combine C4 and C14 for simplicity
- C4_C14_1d(1:gr%nz) = ( 2.0_core_rknd/3.0_core_rknd * C4 ) + &
- ( 1.0_core_rknd/3.0_core_rknd * C14 )
+ C4_C14_1d(1:gr%nz) = ( two_thirds * C4 ) + ( one_third * C14 )
! Are we solving for passive scalars as well?
if ( sclr_dim > 0 ) then
@@ -299,7 +315,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! Define a_1 (located on momentum levels).
! It is a variable that is a function of sigma_sqd_w (where sigma_sqd_w is
! located on the momentum levels).
- a1(1:gr%nz) = 1.0_core_rknd / ( 1.0_core_rknd - sigma_sqd_w(1:gr%nz) )
+ a1(1:gr%nz) = one / ( one - sigma_sqd_w(1:gr%nz) )
! Interpolate a_1, w'r_t', w'th_l', u'w', and v'w' from the momentum levels
@@ -336,8 +352,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!!!!!***** r_t'^2 *****!!!!!
! Implicit contributions to term rtp2
- call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, & ! Intent(in)
- wp3_on_wp2, & ! Intent(in)
+ call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, wp3_on_wp2, & ! Intent(in)
a1, a1_zt, tau_zm, wm_zm, Kw2, & ! Intent(in)
rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
C2rt_1d, nu2_vert_res_dep, beta, & ! Intent(in)
@@ -345,9 +360,9 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
call xp2_xpyp_rhs( xp2_xpyp_rtp2, dt, l_iter, a1, a1_zt, & ! Intent(in)
- wp2_zt, wprtp, wprtp_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- wprtp, wprtp_zt, rtm, rtm, rtp2, & ! Intent(in)
+ wp2_zt, wprtp, wprtp_zt, wp3_on_wp2, & ! Intent(in)
+ wp3_on_wp2_zt, wprtp, wprtp_zt, & ! Intent(in)
+ rtm, rtm, rtp2, rtp2_forcing, & ! Intent(in)
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! Intent(in)
C2rt_1d, tau_zm, rt_tol**2, beta, & ! Intent(in)
rhs ) ! Intent(out)
@@ -364,18 +379,17 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!!!!!***** th_l'^2 *****!!!!!
! Implicit contributions to term thlp2
- call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, & ! Intent(in)
- wp3_on_wp2, & ! Intent(in)
- a1, a1_zt, tau_zm, wm_zm, Kw2, & ! Intent(in)
+ call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, wp3_on_wp2, & ! Intent(in)
+ a1, a1_zt, tau_zm, wm_zm, Kw2, & ! Intent(in)
rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
C2thl_1d, nu2_vert_res_dep, beta, & ! Intent(in)
lhs ) ! Intent(out)
! Explicit contributions to thlp2
call xp2_xpyp_rhs( xp2_xpyp_thlp2, dt, l_iter, a1, a1_zt, & ! Intent(in)
- wp2_zt, wpthlp, wpthlp_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- wpthlp, wpthlp_zt, thlm, thlm, thlp2, & ! Intent(in)
+ wp2_zt, wpthlp, wpthlp_zt, wp3_on_wp2, & ! Intent(in)
+ wp3_on_wp2_zt, wpthlp, wpthlp_zt, & ! Intent(in)
+ thlm, thlm, thlp2, thlp2_forcing, & ! Intent(in)
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! Intent(in)
C2thl_1d, tau_zm, thl_tol**2, beta, & ! Intent(in)
rhs ) ! Intent(out)
@@ -393,8 +407,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!!!!!***** r_t'th_l' *****!!!!!
! Implicit contributions to term rtpthlp
- call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, & ! Intent(in)
- wp3_on_wp2, & ! Intent(in)
+ call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, wp3_on_wp2, & ! Intent(in)
a1, a1_zt, tau_zm, wm_zm, Kw2, & ! Intent(in)
rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
C2rtthl_1d, nu2_vert_res_dep, beta, & ! Intent(in)
@@ -402,9 +415,9 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! Explicit contributions to rtpthlp
call xp2_xpyp_rhs( xp2_xpyp_rtpthlp, dt, l_iter, a1, a1_zt, & ! Intent(in)
- wp2_zt, wprtp, wprtp_zt, & ! Intent(in)
- wp3_on_wp2, wp3_on_wp2_zt, & ! Intent(in)
- wpthlp, wpthlp_zt, rtm, thlm, rtpthlp, & ! Intent(in)
+ wp2_zt, wprtp, wprtp_zt, wp3_on_wp2, & ! Intent(in)
+ wp3_on_wp2_zt, wpthlp, wpthlp_zt, & ! Intent(in)
+ rtm, thlm, rtpthlp, rtpthlp_forcing, & ! Intent(in)
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! Intent(in)
C2rtthl_1d, tau_zm, zero_threshold, beta, & ! Intent(in)
rhs ) ! Intent(out)
@@ -422,12 +435,11 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!!!!!***** u'^2 / v'^2 *****!!!!!
! Implicit contributions to term up2/vp2
- call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, & ! Intent(in)
- wp3_on_wp2, & ! Intent(in)
- a1, a1_zt, tau_zm, wm_zm, Kw9, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- C4_C14_1d, nu9_vert_res_dep, beta, & ! Intent(in)
- lhs ) ! Intent(out)
+ call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, wp3_on_wp2, & ! Intent(in)
+ a1, a1_zt, tau_zm, wm_zm, Kw9, & ! Intent(in)
+ rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
+ C4_C14_1d, nu9_vert_res_dep, beta, & ! Intent(in)
+ lhs ) ! Intent(out)
! Explicit contributions to up2
call xp2_xpyp_uv_rhs( xp2_xpyp_up2, dt, l_iter, a1, a1_zt, wp2, & ! Intent(in)
@@ -482,7 +494,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! Clipping for r_t'^2
- !threshold = 0.0_core_rknd
+ !threshold = zero_threshold
!
!where ( wp2 >= w_tol_sqd ) &
! threshold = rt_tol*rt_tol
@@ -501,7 +513,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! This overwrites stats clipping data from clip_variance
if ( l_stats_samp ) then
- call stat_modify( irtp2_cl, -rtp2 / real( dt, kind = core_rknd ), zm )
+ call stat_modify( irtp2_cl, -rtp2 / dt, stats_zm )
endif
do k = 1, gr%nz
@@ -512,7 +524,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
end do ! k = 1..gr%nz
if ( l_stats_samp ) then
- call stat_modify( irtp2_cl, rtp2 / real( dt, kind = core_rknd ), zm )
+ call stat_modify( irtp2_cl, rtp2 / dt, stats_zm )
endif
end if ! l_clip_large_rtp2
@@ -521,7 +533,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! Clipping for th_l'^2
- !threshold = 0.0_core_rknd
+ !threshold = zero_threshold
!
!where ( wp2 >= w_tol_sqd ) &
! threshold = thl_tol*thl_tol
@@ -534,7 +546,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! Clipping for u'^2
- !threshold = 0.0_core_rknd
+ !threshold = zero_threshold
threshold = w_tol_sqd
call clip_variance( xp2_xpyp_up2, dt, threshold, & ! Intent(in)
@@ -543,7 +555,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! Clipping for v'^2
- !threshold = 0.0_core_rknd
+ !threshold = zero_threshold
threshold = w_tol_sqd
call clip_variance( xp2_xpyp_vp2, dt, threshold, & ! Intent(in)
@@ -569,12 +581,11 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!!!!!***** sclr'^2, sclr'r_t', sclr'th_l' *****!!!!!
- call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, & ! Intent(in)
- wp3_on_wp2, & ! Intent(in)
- a1, a1_zt, tau_zm, wm_zm, Kw2, & ! Intent(in)
- rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
- C2sclr_1d, nu2_vert_res_dep, beta, & ! Intent(in)
- lhs ) ! Intent(out)
+ call xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, wp3_on_wp2, & ! Intent(in)
+ a1, a1_zt, tau_zm, wm_zm, Kw2, & ! Intent(in)
+ rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, & ! Intent(in)
+ C2sclr_1d, nu2_vert_res_dep, beta, & ! Intent(in)
+ lhs ) ! Intent(out)
! Explicit contributions to passive scalars
@@ -586,12 +597,15 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! terms in each equation.
wpsclrp_zt = zm2zt( wpsclrp(:,i) )
+ ! Forcing for .
+ sclrp2_forcing = zero
+
!!!!!***** sclr'^2 *****!!!!!
call xp2_xpyp_rhs( xp2_xpyp_sclrp2, dt, l_iter, a1, a1_zt, & ! In
- wp2_zt, wpsclrp(:,i), wpsclrp_zt, & ! In
- wp3_on_wp2, wp3_on_wp2_zt, & ! In
- wpsclrp(:,i), wpsclrp_zt, sclrm(:,i), sclrm(:,i), sclrp2(:,i), & ! In
+ wp2_zt, wpsclrp(:,i), wpsclrp_zt, wp3_on_wp2, & ! In
+ wp3_on_wp2_zt, wpsclrp(:,i), wpsclrp_zt, & ! In
+ sclrm(:,i), sclrm(:,i), sclrp2(:,i), sclrp2_forcing, & ! In
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! In
C2sclr_1d, tau_zm, sclr_tol(i)**2, beta, & ! In
sclr_rhs(:,i) ) ! Out
@@ -599,41 +613,47 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
!!!!!***** sclr'r_t' *****!!!!!
if ( i == iisclr_rt ) then
- ! In this case we're trying to emulate rt'^2 with sclr'rt', so we
- ! handle this as we would a variance, even though generally speaking
- ! the scalar is not rt
- threshold = rt_tol**2
+ ! In this case we're trying to emulate rt'^2 with sclr'rt', so we
+ ! handle this as we would a variance, even though generally speaking
+ ! the scalar is not rt
+ sclrprtp_forcing = rtp2_forcing
+ threshold = rt_tol**2
else
- threshold = 0.0_core_rknd
- end if
+ sclrprtp_forcing = zero
+ threshold = zero_threshold
+ endif
call xp2_xpyp_rhs( xp2_xpyp_sclrprtp, dt, l_iter, a1, a1_zt, & ! In
- wp2_zt, wpsclrp(:,i), wpsclrp_zt, & ! In
- wp3_on_wp2, wp3_on_wp2_zt, & ! In
- wprtp, wprtp_zt, sclrm(:,i), rtm, sclrprtp(:,i), & ! In
+ wp2_zt, wpsclrp(:,i), wpsclrp_zt, wp3_on_wp2, & ! In
+ wp3_on_wp2_zt, wprtp, wprtp_zt, & ! In
+ sclrm(:,i), rtm, sclrprtp(:,i), sclrprtp_forcing, & ! In
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! In
C2sclr_1d, tau_zm, threshold, beta, & ! In
- sclr_rhs(:,i+sclr_dim) ) ! In
+ sclr_rhs(:,i+sclr_dim) ) ! Out
!!!!!***** sclr'th_l' *****!!!!!
if ( i == iisclr_thl ) then
- ! In this case we're trying to emulate thl'^2 with sclr'thl', so we
- ! handle this as we did with sclr_rt, above.
- threshold = thl_tol**2
+ ! In this case we're trying to emulate thl'^2 with sclr'thl', so we
+ ! handle this as we did with sclr_rt, above.
+ sclrpthlp_forcing = thlp2_forcing
+ threshold = thl_tol**2
else
- threshold = 0.0_core_rknd
- end if
+ sclrpthlp_forcing = zero
+ threshold = zero_threshold
+ endif
call xp2_xpyp_rhs( xp2_xpyp_sclrpthlp, dt, l_iter, a1, a1_zt, & ! In
- wp2_zt, wpsclrp(:,i), wpsclrp_zt, & ! In
- wp3_on_wp2, wp3_on_wp2_zt, & ! In
- wpthlp, wpthlp_zt, sclrm(:,i), thlm, sclrpthlp(:,i), & ! In
+ wp2_zt, wpsclrp(:,i), wpsclrp_zt, wp3_on_wp2, & ! In
+ wp3_on_wp2_zt, wpthlp, wpthlp_zt, & ! In
+ sclrm(:,i), thlm, sclrpthlp(:,i), sclrpthlp_forcing, & ! In
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, & ! In
C2sclr_1d, tau_zm, threshold, beta, & ! In
sclr_rhs(:,i+2*sclr_dim) ) ! Out
- end do ! 1..sclr_dim
+
+
+ enddo ! 1..sclr_dim
! Solve the tridiagonal system
@@ -673,7 +693,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
! Clipping for sclr'^2
do i = 1, sclr_dim, 1
-! threshold = 0.0_core_rknd
+! threshold = zero_threshold
!
! where ( wp2 >= w_tol_sqd ) &
! threshold = sclr_tol(i)*sclr_tol(i)
@@ -764,6 +784,9 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
write(fstderr,*) "sigma_sqd_w = ", sigma_sqd_w
write(fstderr,*) "Skw_zm = ", Skw_zm
write(fstderr,*) "Kh_zt = ", Kh_zt
+ write(fstderr,*) "rtp2_forcing = ", rtp2_forcing
+ write(fstderr,*) "thlp2_forcing = ", thlp2_forcing
+ write(fstderr,*) "rtpthlp_forcing = ", rtpthlp_forcing
write(fstderr,*) "rho_ds_zm = ", rho_ds_zm
write(fstderr,*) "rho_ds_zt = ", rho_ds_zt
write(fstderr,*) "invrs_rho_ds_zm = ", invrs_rho_ds_zm
@@ -795,8 +818,7 @@ subroutine advance_xp2_xpyp( tau_zm, wm_zm, rtm, wprtp, &
end subroutine advance_xp2_xpyp
!=============================================================================
- subroutine xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, &
- wp3_on_wp2, &
+ subroutine xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, wp3_on_wp2, &
a1, a1_zt, tau_zm, wm_zm, Kw, &
rho_ds_zt, rho_ds_zm, invrs_rho_ds_zm, &
Cn, nu, beta, lhs )
@@ -812,14 +834,15 @@ subroutine xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, &
gr ! Variable(s)
use constants_clubb, only: &
- gamma_over_implicit_ts ! Constant(s)
+ gamma_over_implicit_ts, & ! Constant(s)
+ one, &
+ zero
use model_flags, only: &
- l_upwind_xpyp_ta ! Constant(s)
+ l_upwind_xpyp_ta ! Constant(s)
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
use diffusion, only: &
diffusion_zm_lhs ! Procedure(s)
@@ -828,34 +851,34 @@ subroutine xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, &
term_ma_zm_lhs ! Procedure(s)
use stats_variables, only: &
- zmscr01, &
- zmscr02, &
- zmscr03, &
- zmscr04, &
- zmscr05, &
- zmscr06, &
- zmscr07, &
- zmscr08, &
- zmscr09, &
- zmscr10, &
- l_stats_samp, &
- irtp2_ma, &
- irtp2_ta, &
- irtp2_dp1, &
- irtp2_dp2, &
- ithlp2_ma, &
- ithlp2_ta, &
- ithlp2_dp1, &
- ithlp2_dp2, &
- irtpthlp_ma, &
- irtpthlp_ta, &
- irtpthlp_dp1, &
- irtpthlp_dp2, &
- iup2_ma, &
- iup2_ta, &
- iup2_dp2, &
- ivp2_ma, &
- ivp2_ta, &
+ zmscr01, &
+ zmscr02, &
+ zmscr03, &
+ zmscr04, &
+ zmscr05, &
+ zmscr06, &
+ zmscr07, &
+ zmscr08, &
+ zmscr09, &
+ zmscr10, &
+ l_stats_samp, &
+ irtp2_ma, &
+ irtp2_ta, &
+ irtp2_dp1, &
+ irtp2_dp2, &
+ ithlp2_ma, &
+ ithlp2_ta, &
+ ithlp2_dp1, &
+ ithlp2_dp2, &
+ irtpthlp_ma, &
+ irtpthlp_ta, &
+ irtpthlp_dp1, &
+ irtpthlp_dp2, &
+ iup2_ma, &
+ iup2_ta, &
+ iup2_dp2, &
+ ivp2_ma, &
+ ivp2_ta, &
ivp2_dp2
use advance_helper_module, only: set_boundary_conditions_lhs
@@ -870,7 +893,7 @@ subroutine xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, &
km1_mdiag = 3 ! Momentum subdiagonal index.
! Input Variables
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Timestep length [s]
logical, intent(in) :: &
@@ -907,7 +930,7 @@ subroutine xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, &
tmp
! Initialize LHS matrix to 0.
- lhs = 0.0_core_rknd
+ lhs = zero
! Setup LHS of the tridiagonal system
do k = 2, gr%nz-1, 1
@@ -970,7 +993,7 @@ subroutine xp2_xpyp_lhs( dt, l_iter, wp3_on_wp2_zt, &
! LHS time tendency.
if ( l_iter ) then
- lhs(k_mdiag,k) = lhs(k_mdiag,k) + ( 1.0_core_rknd / real( dt, kind = core_rknd ) )
+ lhs(k_mdiag,k) = lhs(k_mdiag,k) + ( one / dt )
endif
if ( l_stats_samp ) then
@@ -1070,30 +1093,33 @@ subroutine xp2_xpyp_solve( solve_type, nrhs, rhs, lhs, xapxbp, err_code )
! None
!-----------------------------------------------------------------------
+ use constants_clubb, only: &
+ one ! Constant(s)
+
use lapack_wrap, only: &
- tridag_solve, & ! Variable(s)
- tridag_solvex !, &
-! band_solve
+ tridag_solve, & ! Variable(s)
+ tridag_solvex !, &
+! band_solve
use grid_class, only: &
- gr ! Variable(s)
+ gr ! Variable(s)
- use stats_type, only: &
- stat_update_var_pt ! Procedure(s)
+ use stats_type_utilities, only: &
+ stat_update_var_pt ! Procedure(s)
use stats_variables, only: &
- sfc, & ! Derived type
- irtp2_matrix_condt_num, & ! Stat index Variables
- ithlp2_matrix_condt_num, &
- irtpthlp_matrix_condt_num, &
- iup2_vp2_matrix_condt_num, &
- l_stats_samp ! Logical
+ stats_sfc, & ! Derived type
+ irtp2_matrix_condt_num, & ! Stat index Variables
+ ithlp2_matrix_condt_num, &
+ irtpthlp_matrix_condt_num, &
+ iup2_vp2_matrix_condt_num, &
+ l_stats_samp ! Logical
use error_code, only: &
- clubb_no_error ! Constant
+ clubb_no_error ! Constant
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -1167,8 +1193,8 @@ subroutine xp2_xpyp_solve( solve_type, nrhs, rhs, lhs, xapxbp, err_code )
xapxbp(:,1:nrhs), rcond, err_code ) ! Intent(out)
! Est. of the condition number of the variance LHS matrix
- call stat_update_var_pt( ixapxbp_matrix_condt_num, 1, 1.0_core_rknd / rcond, & ! Intent(in)
- sfc ) ! Intent(inout)
+ call stat_update_var_pt( ixapxbp_matrix_condt_num, 1, one / rcond, & ! Intent(in)
+ stats_sfc ) ! Intent(inout)
else
call tridag_solve &
@@ -1194,44 +1220,46 @@ subroutine xp2_xpyp_implicit_stats( solve_type, xapxbp )
use grid_class, only: &
gr ! Derived type variable
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_end_update_pt, & ! Procedure(s)
stat_update_var_pt
- use stats_variables, only: &
- zm, & ! Variable(s)
- irtp2_dp1, &
- irtp2_dp2, &
- irtp2_ta, &
- irtp2_ma, &
- ithlp2_dp1, &
- ithlp2_dp2, &
- ithlp2_ta, &
- ithlp2_ma, &
- irtpthlp_dp1, &
- irtpthlp_dp2, &
- irtpthlp_ta, &
- irtpthlp_ma, &
- iup2_dp1, &
- iup2_dp2, &
- iup2_ta, &
- iup2_ma, &
- iup2_pr1, &
- ivp2_dp1, &
- ivp2_dp2, &
- ivp2_ta, &
- ivp2_ma, &
- ivp2_pr1, &
- zmscr01, &
- zmscr02, &
- zmscr03, &
- zmscr04, &
- zmscr05, &
- zmscr06, &
- zmscr07, &
- zmscr08, &
- zmscr09, &
- zmscr10, &
+ use stats_variables, only: &
+ stats_zm, & ! Variable(s)
+ irtp2_dp1, &
+ irtp2_dp2, &
+ irtp2_ta, &
+ irtp2_ma, &
+ ithlp2_dp1, &
+ ithlp2_dp2, &
+ ithlp2_ta, &
+ ithlp2_ma, &
+ irtpthlp_dp1, &
+ irtpthlp_dp2, &
+ irtpthlp_ta, &
+ irtpthlp_ma, &
+ iup2_dp1, &
+ iup2_dp2, &
+ iup2_ta, &
+ iup2_ma, &
+ iup2_pr1, &
+ ivp2_dp1
+
+ use stats_variables, only: &
+ ivp2_dp2, &
+ ivp2_ta, &
+ ivp2_ma, &
+ ivp2_pr1, &
+ zmscr01, &
+ zmscr02, &
+ zmscr03, &
+ zmscr04, &
+ zmscr05, &
+ zmscr06, &
+ zmscr07, &
+ zmscr08, &
+ zmscr09, &
+ zmscr10, &
zmscr11
use clubb_precision, only: &
@@ -1316,14 +1344,14 @@ subroutine xp2_xpyp_implicit_stats( solve_type, xapxbp )
! call stat_end_update_pt.
call stat_end_update_pt( ixapxbp_dp1, k, & ! Intent(in)
zmscr01(k) * xapxbp(k), & ! Intent(in)
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! x'y' term dp2 is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( ixapxbp_dp2, k, & ! Intent(in)
zmscr02(k) * xapxbp(km1) & ! Intent(in)
+ zmscr03(k) * xapxbp(k) &
+ zmscr04(k) * xapxbp(kp1), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! x'y' term ta has both implicit and explicit components;
! call stat_end_update_pt.
@@ -1331,20 +1359,20 @@ subroutine xp2_xpyp_implicit_stats( solve_type, xapxbp )
zmscr05(k) * xapxbp(km1) & ! Intent(in)
+ zmscr06(k) * xapxbp(k) &
+ zmscr07(k) * xapxbp(kp1), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! x'y' term ma is completely implicit; call stat_update_var_pt.
call stat_update_var_pt( ixapxbp_ma, k, & ! Intent(in)
zmscr08(k) * xapxbp(km1) & ! Intent(in)
+ zmscr09(k) * xapxbp(k) &
+ zmscr10(k) * xapxbp(kp1), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! x'y' term pr1 has both implicit and explicit components;
! call stat_end_update_pt.
call stat_end_update_pt( ixapxbp_pr1, k, & ! Intent(in)
zmscr11(k) * xapxbp(k), & ! Intent(in)
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
end do ! k=2..gr%nz-1
@@ -1370,16 +1398,19 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
use constants_clubb, only: &
gamma_over_implicit_ts, & ! Constant(s)
- w_tol_sqd
+ w_tol_sqd, &
+ one, &
+ two_thirds, &
+ one_third, &
+ zero
use model_flags, only: &
- l_upwind_xpyp_ta ! Constant(s)
+ l_upwind_xpyp_ta ! Constant(s)
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update_pt, & ! Procedure(s)
stat_update_var_pt, &
stat_modify_pt
@@ -1395,7 +1426,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
iup2_dp1, &
iup2_pr1, &
iup2_pr2, &
- zm, &
+ stats_zm, &
zmscr01, &
zmscr11, &
l_stats_samp
@@ -1405,7 +1436,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! Input Variables
integer, intent(in) :: solve_type
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
logical, intent(in) :: &
@@ -1493,7 +1524,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! Initialize RHS vector to 0.
- rhs = 0.0_core_rknd
+ rhs = zero
do k = 2, gr%nz-1, 1
@@ -1541,7 +1572,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
rhs(k,1) &
= rhs(k,1) &
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) &
+ + ( one - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(1) * xap2(kp1) &
- lhs_fnc_output(2) * xap2(k) &
- lhs_fnc_output(3) * xap2(km1) )
@@ -1549,7 +1580,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! RHS turbulent production (tp) term.
rhs(k,1) &
= rhs(k,1) &
- + (1.0_core_rknd - C5) &
+ + ( one - C5 ) &
* term_tp( xam(kp1), xam(k), xam(kp1), xam(k), &
wpxap(k), wpxap(k), gr%invrs_dzm(k) )
@@ -1566,7 +1597,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
= term_dp1_lhs( C4_C14_1d(k), tau_zm(k) )
rhs(k,1) &
= rhs(k,1) &
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) &
+ + ( one - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(1) * xap2(k) )
! RHS pressure term 2 (pr2).
@@ -1578,7 +1609,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! RHS time tendency.
if ( l_iter ) then
- rhs(k,1) = rhs(k,1) + 1.0_core_rknd/real( dt, kind = core_rknd ) * xap2(k)
+ rhs(k,1) = rhs(k,1) + one/dt * xap2(k)
endif
if ( l_stats_samp ) then
@@ -1594,7 +1625,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
rho_ds_zt(kp1), rho_ds_zt(k), invrs_rho_ds_zm(k), &
a1_zt(kp1), a1(k), a1_zt(k), wpxbp_zt(kp1), wpxbp_zt(k), &
wpxap_zt(kp1), wpxap_zt(k), gr%invrs_dzm(k), beta ), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! Note: An "over-implicit" weighted time step is applied to this term.
! A weighting factor of greater than 1 may be used to make the
@@ -1615,11 +1646,11 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
end if ! ~l_upwind_xpyp_ta
call stat_modify_pt( ixapxbp_ta, k, & ! Intent(in)
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) & ! Intent(in)
+ + ( one - gamma_over_implicit_ts ) & ! Intent(in)
* ( - lhs_fnc_output(1) * xap2(kp1) &
- lhs_fnc_output(2) * xap2(k) &
- lhs_fnc_output(3) * xap2(km1) ), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
if ( ixapxbp_dp1 > 0 ) then
! Note: The function term_pr1 is the explicit component of a
@@ -1635,7 +1666,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! RHS turbulent advection (ta) term).
tmp &
= gamma_over_implicit_ts &
- * term_dp1_lhs( (2.0_core_rknd/3.0_core_rknd)*C4, tau_zm(k) )
+ * term_dp1_lhs( two_thirds*C4, tau_zm(k) )
zmscr01(k) = -tmp
! Statistical contribution of the explicit component of term dp1 for
! up2 or vp2.
@@ -1645,19 +1676,19 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! Note: To find the contribution of x'y' term dp1, substitute 0 for
! the C_14 input to function term_pr1.
call stat_begin_update_pt( ixapxbp_dp1, k, & ! Intent(in)
- -term_pr1( C4, 0.0_core_rknd, xbp2(k), wp2(k), tau_zm(k) ), & ! Intent(in)
- zm ) ! Intent(inout)
+ -term_pr1( C4, zero, xbp2(k), wp2(k), tau_zm(k) ), & ! Intent(in)
+ stats_zm ) ! Intent(inout)
! Note: An "over-implicit" weighted time step is applied to this
! term. A weighting factor of greater than 1 may be used to
! make the term more numerically stable (see note above for
! RHS turbulent advection (ta) term).
lhs_fnc_output(1) &
- = term_dp1_lhs( (2.0_core_rknd/3.0_core_rknd)*C4, tau_zm(k) )
+ = term_dp1_lhs( two_thirds*C4, tau_zm(k) )
call stat_modify_pt( ixapxbp_dp1, k, & ! Intent(in)
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) & ! Intent(in)
+ + ( one - gamma_over_implicit_ts ) & ! Intent(in)
* ( - lhs_fnc_output(1) * xap2(k) ), & ! Intent(in)
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
endif
@@ -1674,7 +1705,7 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! RHS turbulent advection (ta) term).
tmp &
= gamma_over_implicit_ts &
- * term_dp1_lhs( (1.0_core_rknd/3.0_core_rknd)*C14, tau_zm(k) )
+ * term_dp1_lhs( one_third*C14, tau_zm(k) )
zmscr11(k) = -tmp
! Statistical contribution of the explicit component of term pr1 for
! up2 or vp2.
@@ -1684,19 +1715,19 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
! Note: To find the contribution of x'y' term pr1, substitute 0 for
! the C_4 input to function term_pr1.
call stat_begin_update_pt( ixapxbp_pr1, k, & ! Intent(in)
- -term_pr1( 0.0_core_rknd, C14, xbp2(k), wp2(k), tau_zm(k) ), & ! Intent(in)
- zm ) ! Intent(inout)
+ -term_pr1( zero, C14, xbp2(k), wp2(k), tau_zm(k) ), & ! Intent(in)
+ stats_zm ) ! Intent(inout)
! Note: An "over-implicit" weighted time step is applied to this
! term. A weighting factor of greater than 1 may be used to
! make the term more numerically stable (see note above for
! RHS turbulent advection (ta) term).
lhs_fnc_output(1) &
- = term_dp1_lhs( (1.0_core_rknd/3.0_core_rknd)*C14, tau_zm(k) )
+ = term_dp1_lhs( one_third*C14, tau_zm(k) )
call stat_modify_pt( ixapxbp_pr1, k, & ! Intent(in)
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) & ! Intent(in)
+ + ( one - gamma_over_implicit_ts ) & ! Intent(in)
* ( - lhs_fnc_output(1) * xap2(k) ), & ! Intent(in)
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
endif
@@ -1705,14 +1736,14 @@ subroutine xp2_xpyp_uv_rhs( solve_type, dt, l_iter, a1, a1_zt, wp2, &
term_pr2( C5, thv_ds_zm(k), wpthvp(k), wpxap(k), wpxbp(k), & ! Intent(in)
xam, xbm, gr%invrs_dzm(k), kp1, k, &
Lscale(kp1), Lscale(k), wp2_zt(kp1), wp2_zt(k) ), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! x'y' term tp is completely explicit; call stat_update_var_pt.
call stat_update_var_pt( ixapxbp_tp, k, & ! Intent(in)
- (1.0_core_rknd - C5) & ! Intent(in)
+ ( one - C5 ) & ! Intent(in)
* term_tp( xam(kp1), xam(k), xam(kp1), xam(k), &
wpxap(k), wpxap(k), gr%invrs_dzm(k) ), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
endif ! l_stats_samp
@@ -1735,9 +1766,9 @@ end subroutine xp2_xpyp_uv_rhs
!=============================================================================
subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
- wp2_zt, wpxap, wpxap_zt, &
- wp3_on_wp2, wp3_on_wp2_zt, &
- wpxbp, wpxbp_zt, xam, xbm, xapxbp, &
+ wp2_zt, wpxap, wpxap_zt, wp3_on_wp2, &
+ wp3_on_wp2_zt, wpxbp, wpxbp_zt, &
+ xam, xbm, xapxbp, xapxbp_forcing, &
rho_ds_zm, rho_ds_zt, invrs_rho_ds_zm, &
Cn, tau_zm, threshold, beta, &
rhs )
@@ -1751,32 +1782,36 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
gr ! Variable(s)
use constants_clubb, only: &
- gamma_over_implicit_ts ! Variable(s)
+ gamma_over_implicit_ts, & ! Constant(s)
+ one, &
+ zero
use model_flags, only: &
- l_upwind_xpyp_ta ! Constant(s)
+ l_upwind_xpyp_ta ! Constant(s)
use clubb_precision, only: &
- time_precision, & ! Variable(s)
- core_rknd
+ core_rknd ! Variable(s)
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update_pt, & ! Procedure(s)
stat_update_var_pt, &
stat_modify_pt
use stats_variables, only: &
- irtp2_ta, & ! Variable(s)
- irtp2_tp, &
- irtp2_dp1, &
- ithlp2_ta, &
- ithlp2_tp, &
- ithlp2_dp1, &
- irtpthlp_ta, &
- irtpthlp_tp1, &
- irtpthlp_tp2, &
- irtpthlp_dp1, &
- zm, &
+ irtp2_ta, & ! Variable(s)
+ irtp2_tp, &
+ irtp2_dp1, &
+ irtp2_forcing, &
+ ithlp2_ta, &
+ ithlp2_tp, &
+ ithlp2_dp1, &
+ ithlp2_forcing, &
+ irtpthlp_ta, &
+ irtpthlp_tp1, &
+ irtpthlp_tp2, &
+ irtpthlp_dp1, &
+ irtpthlp_forcing, &
+ stats_zm, &
l_stats_samp
use advance_helper_module, only: set_boundary_conditions_rhs
@@ -1786,7 +1821,7 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
! Input Variables
integer, intent(in) :: solve_type
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
logical, intent(in) :: &
@@ -1805,6 +1840,7 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
xam, & ! x_am (thermodynamic levels) [{x_am units}]
xbm, & ! x_bm (thermodynamic levels) [{x_bm units}]
xapxbp, & ! x_a'x_b' (momentum levels) [{x_am units}*{x_bm units}]
+ xapxbp_forcing, & ! x_a'x_b' forcing (momentum levels) [{x_am units}*{x_bm units}/s]
rho_ds_zm, & ! Dry, static density on moment. levels [kg/m^3]
rho_ds_zt, & ! Dry, static density on thermo. levels [kg/m^3]
invrs_rho_ds_zm, & ! Inv. dry, static density on momentum levs. [m^3/kg]
@@ -1839,7 +1875,8 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
ixapxbp_tp, &
ixapxbp_tp1, &
ixapxbp_tp2, &
- ixapxbp_dp1
+ ixapxbp_dp1, &
+ ixapxbp_f
!------------------------------ Begin Code ---------------------------------
@@ -1850,29 +1887,33 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
ixapxbp_tp1 = 0
ixapxbp_tp2 = 0
ixapxbp_dp1 = irtp2_dp1
+ ixapxbp_f = irtp2_forcing
case ( xp2_xpyp_thlp2 )
ixapxbp_ta = ithlp2_ta
ixapxbp_tp = ithlp2_tp
ixapxbp_tp1 = 0
ixapxbp_tp2 = 0
ixapxbp_dp1 = ithlp2_dp1
+ ixapxbp_f = ithlp2_forcing
case ( xp2_xpyp_rtpthlp )
ixapxbp_ta = irtpthlp_ta
ixapxbp_tp = 0
ixapxbp_tp1 = irtpthlp_tp1
ixapxbp_tp2 = irtpthlp_tp2
ixapxbp_dp1 = irtpthlp_dp1
+ ixapxbp_f = irtpthlp_forcing
case default ! No budgets for passive scalars
ixapxbp_ta = 0
ixapxbp_tp = 0
ixapxbp_tp1 = 0
ixapxbp_tp2 = 0
ixapxbp_dp1 = 0
+ ixapxbp_f = 0
end select
! Initialize RHS vector to 0.
- rhs = 0.0_core_rknd
+ rhs = zero
do k = 2, gr%nz-1, 1
@@ -1916,11 +1957,11 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
gr%invrs_dzt(k), gr%invrs_dzt(kp1), &
invrs_rho_ds_zm(k), &
rho_ds_zm(kp1), rho_ds_zm(k), rho_ds_zm(km1), beta )
- end if
+ endif
rhs(k,1) &
= rhs(k,1) &
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) &
+ + ( one - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(1) * xapxbp(kp1) &
- lhs_fnc_output(2) * xapxbp(k) &
- lhs_fnc_output(3) * xapxbp(km1) )
@@ -1943,14 +1984,19 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
= term_dp1_lhs( Cn(k), tau_zm(k) )
rhs(k,1) &
= rhs(k,1) &
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) &
+ + ( one - gamma_over_implicit_ts ) &
* ( - lhs_fnc_output(1) * xapxbp(k) )
! RHS time tendency.
if ( l_iter ) then
- rhs(k,1) = rhs(k,1) + 1.0_core_rknd/real( dt, kind = core_rknd ) * xapxbp(k)
+ rhs(k,1) = rhs(k,1) + one/dt * xapxbp(k)
endif
+ ! RHS forcing.
+ ! Note: forcing includes the effects of microphysics on .
+ rhs(k,1) = rhs(k,1) + xapxbp_forcing(k)
+
+
if ( l_stats_samp ) then
! Statistics: explicit contributions for rtp2, thlp2, or rtpthlp.
@@ -1964,7 +2010,7 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
rho_ds_zt(kp1), rho_ds_zt(k), invrs_rho_ds_zm(k), &
a1_zt(kp1), a1(k), a1_zt(k), wpxbp_zt(kp1), wpxbp_zt(k), &
wpxap_zt(kp1), wpxap_zt(k), gr%invrs_dzm(k), beta ), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! Note: An "over-implicit" weighted time step is applied to this term.
! A weighting factor of greater than 1 may be used to make the
@@ -1984,18 +2030,18 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
rho_ds_zm(kp1), rho_ds_zm(k), rho_ds_zm(km1), beta )
end if
call stat_modify_pt( ixapxbp_ta, k, & ! Intent(in)
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) & ! Intent(in)
+ + ( one - gamma_over_implicit_ts ) & ! Intent(in)
* ( - lhs_fnc_output(1) * xapxbp(kp1) &
- lhs_fnc_output(2) * xapxbp(k) &
- lhs_fnc_output(3) * xapxbp(km1) ), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! x'y' term dp1 has both implicit and explicit components; call
! stat_begin_update_pt. Since stat_begin_update_pt automatically
! subtracts the value sent in, reverse the sign on term_dp1_rhs.
call stat_begin_update_pt( ixapxbp_dp1, k, & ! Intent(in)
-term_dp1_rhs( Cn(k), tau_zm(k), threshold ), & ! Intent(in)
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! Note: An "over-implicit" weighted time step is applied to this term.
! A weighting factor of greater than 1 may be used to make the
@@ -2004,33 +2050,36 @@ subroutine xp2_xpyp_rhs( solve_type, dt, l_iter, a1, a1_zt, &
lhs_fnc_output(1) &
= term_dp1_lhs( Cn(k), tau_zm(k) )
call stat_modify_pt( ixapxbp_dp1, k, & ! Intent(in)
- + ( 1.0_core_rknd - gamma_over_implicit_ts ) & ! Intent(in)
+ + ( one - gamma_over_implicit_ts ) & ! Intent(in)
* ( - lhs_fnc_output(1) * xapxbp(k) ), & ! Intent(in)
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! rtp2/thlp2 case (1 turbulent production term)
! x'y' term tp is completely explicit; call stat_update_var_pt.
call stat_update_var_pt( ixapxbp_tp, k, & ! Intent(in)
term_tp( xam(kp1), xam(k), xbm(kp1), xbm(k), & ! Intent(in)
wpxbp(k), wpxap(k), gr%invrs_dzm(k) ), &
- zm ) ! Intent(inout)
+ stats_zm ) ! Intent(inout)
! rtpthlp case (2 turbulent production terms)
! x'y' term tp1 is completely explicit; call stat_update_var_pt.
! Note: To find the contribution of x'y' term tp1, substitute 0 for all
! the xam inputs and the wpxbp input to function term_tp.
call stat_update_var_pt( ixapxbp_tp1, k, & ! Intent(in)
- term_tp( 0.0_core_rknd, 0.0_core_rknd, xbm(kp1), xbm(k), & ! Intent(in)
- 0.0_core_rknd, wpxap(k), gr%invrs_dzm(k) ), &
- zm ) ! Intent(inout)
+ term_tp( zero, zero, xbm(kp1), xbm(k), & ! Intent(in)
+ zero, wpxap(k), gr%invrs_dzm(k) ), &
+ stats_zm ) ! Intent(inout)
! x'y' term tp2 is completely explicit; call stat_update_var_pt.
! Note: To find the contribution of x'y' term tp2, substitute 0 for all
! the xbm inputs and the wpxap input to function term_tp.
call stat_update_var_pt( ixapxbp_tp2, k, & ! Intent(in)
- term_tp( xam(kp1), xam(k), 0.0_core_rknd, 0.0_core_rknd, & ! Intent(in)
- wpxbp(k), 0.0_core_rknd, gr%invrs_dzm(k) ), &
- zm ) ! Intent(inout)
+ term_tp( xam(kp1), xam(k), zero, zero, & ! Intent(in)
+ wpxbp(k), zero, gr%invrs_dzm(k) ), &
+ stats_zm ) ! Intent(inout)
+
+ ! x'y' forcing term is completely explicit; call stat_update_var_pt.
+ call stat_update_var_pt( ixapxbp_f, k, xapxbp_forcing(k), stats_zm )
endif ! l_stats_samp
@@ -2149,11 +2198,14 @@ pure function term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
use grid_class, only: & ! gr%weights_zm2zt
gr ! Variable(s)
+ use constants_clubb, only: &
+ one_third ! Constant(s)
+
use model_flags, only: &
l_standard_term_ta
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2211,7 +2263,7 @@ pure function term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! Momentum superdiagonal: [ x xapxbp(k+1,) ]
lhs(kp1_mdiag) &
- = + (1.0_core_rknd/3.0_core_rknd) * beta &
+ = + one_third * beta &
* invrs_rho_ds_zm &
* invrs_dzm &
* rho_ds_ztp1 * a1_ztp1 &
@@ -2220,7 +2272,7 @@ pure function term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! Momentum main diagonal: [ x xapxbp(k,) ]
lhs(k_mdiag) &
- = + (1.0_core_rknd/3.0_core_rknd) * beta &
+ = + one_third * beta &
* invrs_rho_ds_zm &
* invrs_dzm &
* ( rho_ds_ztp1 * a1_ztp1 &
@@ -2233,7 +2285,7 @@ pure function term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! Momentum subdiagonal: [ x xapxbp(k-1,) ]
lhs(km1_mdiag) &
- = - (1.0_core_rknd/3.0_core_rknd) * beta &
+ = - one_third * beta &
* invrs_rho_ds_zm &
* invrs_dzm &
* rho_ds_zt * a1_zt &
@@ -2251,7 +2303,7 @@ pure function term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! Momentum superdiagonal: [ x xapxbp(k+1,) ]
lhs(kp1_mdiag) &
- = + (1.0_core_rknd/3.0_core_rknd) * beta &
+ = + one_third * beta &
* invrs_rho_ds_zm * a1 &
* invrs_dzm &
* rho_ds_ztp1 &
@@ -2260,7 +2312,7 @@ pure function term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! Momentum main diagonal: [ x xapxbp(k,) ]
lhs(k_mdiag) &
- = + (1.0_core_rknd/3.0_core_rknd) * beta &
+ = + one_third * beta &
* invrs_rho_ds_zm * a1 &
* invrs_dzm &
* ( rho_ds_ztp1 &
@@ -2273,7 +2325,7 @@ pure function term_ta_lhs( wp3_on_wp2_ztp1, wp3_on_wp2_zt, &
! Momentum subdiagonal: [ x xapxbp(k-1,) ]
lhs(km1_mdiag) &
- = - (1.0_core_rknd/3.0_core_rknd) * beta &
+ = - one_third * beta &
* invrs_rho_ds_zm * a1 &
* invrs_dzm &
* rho_ds_zt &
@@ -2303,8 +2355,12 @@ pure function term_ta_lhs_upwind( a1_zm, a1_zm_p1, a1_zm_m1, &
! None
!-----------------------------------------------------------------------------
+ use constants_clubb, only: &
+ one_third, & ! Constant(s)
+ zero
+
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2334,20 +2390,20 @@ pure function term_ta_lhs_upwind( a1_zm, a1_zm_p1, a1_zm_m1, &
real( kind = core_rknd ), dimension(3) :: lhs
- if ( wp3_on_wp2 > 0._core_rknd ) then
+ if ( wp3_on_wp2 > zero ) then
! Momentum main diagonal: [ x xapxbp(k+1,) ]
- lhs(kp1_mdiag) = 0._core_rknd
+ lhs(kp1_mdiag) = zero
! Momentum main diagonal: [ x xapxbp(k,) ]
lhs(k_mdiag) &
- = + (1.0_core_rknd/3.0_core_rknd) * beta &
+ = + one_third * beta &
* invrs_dzt * invrs_rho_ds_zm &
* rho_ds_zm * a1_zm * wp3_on_wp2
! Momentum subdiagonal: [ x xapxbp(k-1,) ]
lhs(km1_mdiag) &
- = - (1.0_core_rknd/3.0_core_rknd) * beta &
+ = - one_third * beta &
* invrs_dzt * invrs_rho_ds_zm &
* rho_ds_zm_m1 * a1_zm_m1 * wp3_on_wp2_m1
@@ -2355,18 +2411,18 @@ pure function term_ta_lhs_upwind( a1_zm, a1_zm_p1, a1_zm_m1, &
! Momentum main diagonal: [ x xapxbp(k+1,) ]
lhs(kp1_mdiag) &
- = + (1.0_core_rknd/3.0_core_rknd) * beta &
+ = + one_third * beta &
* invrs_dzt_p1 * invrs_rho_ds_zm &
* rho_ds_zm_p1 * a1_zm_p1 * wp3_on_wp2_p1
! Momentum main diagonal: [ x xapxbp(k,) ]
lhs(k_mdiag) &
- = - (1.0_core_rknd/3.0_core_rknd) * beta &
+ = - one_third * beta &
* invrs_dzt_p1 * invrs_rho_ds_zm &
* rho_ds_zm * a1_zm * wp3_on_wp2
! Momentum subdiagonal: [ x xapxbp(k-1,) ]
- lhs(km1_mdiag) = 0._core_rknd
+ lhs(km1_mdiag) = zero
end if
@@ -2457,11 +2513,15 @@ pure function term_ta_rhs( wp2_ztp1, wp2_zt, &
! References:
!-----------------------------------------------------------------------
+ use constants_clubb, only: &
+ one, & ! Constant(s)
+ one_third
+
use model_flags, only: &
l_standard_term_ta
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2498,7 +2558,7 @@ pure function term_ta_rhs( wp2_ztp1, wp2_zt, &
! listed above.
rhs &
- = - ( 1.0_core_rknd - (1.0_core_rknd/3.0_core_rknd) * beta ) &
+ = - ( one - one_third * beta ) &
* invrs_rho_ds_zm &
* invrs_dzm &
* ( rho_ds_ztp1 * a1_ztp1**2 &
@@ -2520,7 +2580,7 @@ pure function term_ta_rhs( wp2_ztp1, wp2_zt, &
! the derivative.
rhs &
- = - ( 1.0_core_rknd - (1.0_core_rknd/3.0_core_rknd) * beta ) &
+ = - ( one - one_third * beta ) &
* invrs_rho_ds_zm * a1**2 &
* invrs_dzm &
* ( rho_ds_ztp1 &
@@ -2816,10 +2876,11 @@ pure function term_pr1( C4, C14, xbp2, wp2, tau_zm ) &
!-----------------------------------------------------------------------
use constants_clubb, only: &
- w_tol_sqd
+ w_tol_sqd, & ! Constant(s)
+ one_third
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2834,14 +2895,14 @@ pure function term_pr1( C4, C14, xbp2, wp2, tau_zm ) &
! Return Variable
real( kind = core_rknd ) :: rhs
- rhs = + 1.0_core_rknd/3.0_core_rknd * ( C4 - C14 ) * ( xbp2 + wp2 ) / tau_zm &
+ rhs = + one_third * ( C4 - C14 ) * ( xbp2 + wp2 ) / tau_zm &
+ ( C14 / tau_zm ) * w_tol_sqd
return
end function term_pr1
!=============================================================================
- pure function term_pr2( C5, thv_ds_zm, wpthvp, upwp, vpwp, &
+ function term_pr2( C5, thv_ds_zm, wpthvp, upwp, vpwp, &
um, vm, invrs_dzm, kp1, k, &
Lscalep1, Lscale, wp2_ztp1, wp2_zt ) &
result( rhs )
@@ -2884,14 +2945,17 @@ pure function term_pr2( C5, thv_ds_zm, wpthvp, upwp, vpwp, &
!-----------------------------------------------------------------------
use constants_clubb, only: & ! Constants
- grav, & ! Gravitational acceleration [m/s^2]
- zero_threshold
+ grav, & ! Gravitational acceleration [m/s^2]
+ one, &
+ two_thirds, &
+ zero, &
+ zero_threshold
use grid_class, only: &
- gr ! Variable(s)
+ gr ! Variable(s)
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -2929,7 +2993,7 @@ pure function term_pr2( C5, thv_ds_zm, wpthvp, upwp, vpwp, &
real( kind = core_rknd ), parameter :: &
! Constants empirically determined for experimental version of term_pr2
! ldgrant March 2010
- constant1 = 1.0_core_rknd, & ! [m/s]
+ constant1 = one, & ! [m/s]
constant2 = 1000.0_core_rknd, & ! [m]
vert_avg_depth = 200.0_core_rknd ! Depth over which to average d(um)/dz and d(vm)/dz [m]
@@ -2953,11 +3017,11 @@ pure function term_pr2( C5, thv_ds_zm, wpthvp, upwp, vpwp, &
! use original version of term_pr2
! As applied to w'2
- rhs = + (2.0_core_rknd/3.0_core_rknd) * C5 &
- * ( ( grav / thv_ds_zm ) * wpthvp &
- - upwp * invrs_dzm * ( um(kp1) - um(k) ) &
- - vpwp * invrs_dzm * ( vm(kp1) - vm(k) ) &
- )
+ rhs = + two_thirds * C5 &
+ * ( ( grav / thv_ds_zm ) * wpthvp &
+ - upwp * invrs_dzm * ( um(kp1) - um(k) ) &
+ - vpwp * invrs_dzm * ( vm(kp1) - vm(k) ) &
+ )
else ! use experimental version of term_pr2 --ldgrant March 2010
@@ -3013,15 +3077,15 @@ pure function term_pr2( C5, thv_ds_zm, wpthvp, upwp, vpwp, &
! For better results, we reduced the value of C5 from 5.2 to 3.0 and
! changed the eddy diffusivity coefficient Kh so that it is
! proportional to 1.5*wp2 rather than to em.
- rhs = + (2.0_core_rknd/3.0_core_rknd) * C5 &
+ rhs = + two_thirds * C5 &
* ( constant1 * abs( wp2_ztp1 - wp2_zt ) * invrs_dzm &
! * abs( Lscalep1 - Lscale ) * invrs_dzm &
+ constant2 * abs( wp2_ztp1 - wp2_zt ) * invrs_dzm &
* abs( vm_high - vm_low ) / ( zt_high - zt_low ) &
- + ( Lscalep1 + Lscale ) * 0._core_rknd &
+ + ( Lscalep1 + Lscale ) * zero &
! This line eliminates an Intel compiler
- ) ! warning that Lscalep1/Lscale are not
- ! used. -meyern
+ ) ! warning that Lscalep1/Lscale are not
+ ! used. -meyern
end if ! .not. l_use_experimental_term_pr2
! Added by dschanen for ticket #36
@@ -3034,7 +3098,7 @@ pure function term_pr2( C5, thv_ds_zm, wpthvp, upwp, vpwp, &
end function term_pr2
!=============================================================================
- pure subroutine find_endpts_for_vert_avg_winds &
+ subroutine find_endpts_for_vert_avg_winds &
( vert_avg_depth, k, um, vm, & ! intent(in)
zt_high, um_high, vm_high, & ! intent(out)
zt_low, um_low, vm_low ) ! intent(out)
@@ -3047,17 +3111,19 @@ pure subroutine find_endpts_for_vert_avg_winds &
! then this subroutine will determine the values of um and vm which
! are 100m above and below the current level.
! ldgrant March 2010
- !---------------------------------------------------------------------------
+ !-----------------------------------------------------------------------
+ use constants_clubb, only: &
+ two ! Constant(s)
use interpolation, only : &
- binary_search, lin_int ! Function(s)
+ binary_search, lin_interpolate_two_points ! Function(s)
use grid_class, only: &
- gr ! Variable(s)
+ gr ! Variable(s)
use clubb_precision, only: &
- core_rknd ! Variable(s)
+ core_rknd ! Variable(s)
implicit none
@@ -3092,7 +3158,7 @@ pure subroutine find_endpts_for_vert_avg_winds &
!------ Begin code ------------
- depth = vert_avg_depth / 2.0_core_rknd
+ depth = vert_avg_depth / two
! Find the grid level that contains the altitude greater than or
! equal to the current altitude + depth
@@ -3116,9 +3182,9 @@ pure subroutine find_endpts_for_vert_avg_winds &
vm_high = vm(k_high)
else ! Do an interpolation to find um & vm at current altitude + depth.
zt_high = gr%zt(k)+depth
- um_high = lin_int( zt_high, gr%zt(k_high), gr%zt(k_high-1), &
+ um_high = lin_interpolate_two_points( zt_high, gr%zt(k_high), gr%zt(k_high-1), &
um(k_high), um(k_high-1) )
- vm_high = lin_int( zt_high, gr%zt(k_high), gr%zt(k_high-1), &
+ vm_high = lin_interpolate_two_points( zt_high, gr%zt(k_high), gr%zt(k_high-1), &
vm(k_high), vm(k_high-1) )
end if ! k_high ...
@@ -3144,9 +3210,9 @@ pure subroutine find_endpts_for_vert_avg_winds &
vm_low = vm(k_low)
else ! Do an interpolation to find um at current altitude - depth.
zt_low = gr%zt(k)-depth
- um_low = lin_int( zt_low, gr%zt(k_low), gr%zt(k_low-1), &
+ um_low = lin_interpolate_two_points( zt_low, gr%zt(k_low), gr%zt(k_low-1), &
um(k_low), um(k_low-1) )
- vm_low = lin_int( zt_low, gr%zt(k_low), gr%zt(k_low-1), &
+ vm_low = lin_interpolate_two_points( zt_low, gr%zt(k_low), gr%zt(k_low-1), &
vm(k_low), vm(k_low-1) )
end if ! k_low ...
@@ -3162,14 +3228,14 @@ subroutine pos_definite_variances( solve_type, dt, tolerance, &
! Use the hole filling code to make a variance term positive definite
!-----------------------------------------------------------------------
- use fill_holes, only: fill_holes_driver
+ use fill_holes, only: fill_holes_vertical
use grid_class, only: gr
- use clubb_precision, only: time_precision, core_rknd
+ use clubb_precision, only: core_rknd
use stats_variables, only: &
- zm, l_stats_samp, &
+ stats_zm, l_stats_samp, &
irtp2_pd, ithlp2_pd, iup2_pd, ivp2_pd ! variables
- use stats_type, only: &
+ use stats_type_utilities, only: &
stat_begin_update, stat_end_update ! subroutines
@@ -3182,7 +3248,7 @@ subroutine pos_definite_variances( solve_type, dt, tolerance, &
integer, intent(in) :: &
solve_type
- real(kind=time_precision), intent(in) :: &
+ real( kind = core_rknd ), intent(in) :: &
dt ! Model timestep [s]
real( kind = core_rknd ), intent(in) :: &
@@ -3215,8 +3281,8 @@ subroutine pos_definite_variances( solve_type, dt, tolerance, &
if ( l_stats_samp ) then
! Store previous value for effect of the positive definite scheme
- call stat_begin_update( ixp2_pd, xp2_np1 / real( dt, kind = core_rknd ), & ! Intent(in)
- zm ) ! Intent(inout)
+ call stat_begin_update( ixp2_pd, xp2_np1 / dt, & ! Intent(in)
+ stats_zm ) ! Intent(inout)
endif
@@ -3225,7 +3291,7 @@ subroutine pos_definite_variances( solve_type, dt, tolerance, &
! Call the hole-filling scheme.
! The first pass-through should draw from only two levels on either side
! of the hole.
- call fill_holes_driver( 2, tolerance, "zm", & ! Intent(in)
+ call fill_holes_vertical( 2, tolerance, "zm", & ! Intent(in)
rho_ds_zt, rho_ds_zm, & ! Intent(in)
xp2_np1 ) ! Intent(inout)
@@ -3233,14 +3299,156 @@ subroutine pos_definite_variances( solve_type, dt, tolerance, &
if ( l_stats_samp ) then
! Store previous value for effect of the positive definite scheme
- call stat_end_update( ixp2_pd, xp2_np1 / real( dt, kind = core_rknd ), & ! Intent(in)
- zm ) ! Intent(inout)
+ call stat_end_update( ixp2_pd, xp2_np1 / dt, & ! Intent(in)
+ stats_zm ) ! Intent(inout)
endif
return
end subroutine pos_definite_variances
+ !============================================================================
+ subroutine update_xp2_mc( nz, dt, cloud_frac, rcm, rvm, thlm, &
+ wm, exner, rrm_evap, pdf_params, &
+ rtp2_mc, thlp2_mc, wprtp_mc, wpthlp_mc, &
+ rtpthlp_mc )
+ !Description:
+ !This subroutine is for use when l_morr_xp2_mc = .true.
+ !The effects of rain evaporation on rtp2 and thlp2 are included by
+ !assuming rain falls through the moist (cold) portion of the pdf.
+ !This is accomplished by defining a precip_fraction and assuming a double
+ !delta shaped pdf, such that the evaporation makes the moist component
+ !moister and the colder component colder. Calculations are done using
+ !variables on the zt grid, and the outputs are on the zm grid --storer
+
+ use pdf_parameter_module, only: pdf_parameter
+
+ use grid_class, only: &
+ zt2zm ! Procedure(s)
+
+ use constants_clubb, only: &
+ cloud_frac_min, & !Variables
+ Cp, &
+ Lv
+
+ use clubb_precision, only: &
+ core_rknd ! Variable(s)
+
+
+ implicit none
+
+ !input parameters
+ integer, intent(in) :: nz ! Points in the Vertical [-]
+
+ real( kind = core_rknd ), intent(in) :: dt ! Model timestep [s]
+
+ real( kind = core_rknd ), dimension(nz), intent(in) :: &
+ cloud_frac, & !Cloud fraction [-]
+ rcm, & !Cloud water mixing ratio [kg/kg]
+ rvm, & !Vapor water mixing ratio [kg/kg]
+ thlm, & !Liquid potential temperature [K]
+ wm, & !Mean vertical velocity [m/s]
+ exner, & !Exner function [-]
+ rrm_evap !Evaporation of rain [kg/kg/s]
+ !It is expected that this variable is negative, as
+ !that is the convention in Morrison microphysics
+
+ type(pdf_parameter), dimension(nz), intent(in) :: &
+ pdf_params ! PDF parameters
+
+ !input/output variables
+ real( kind = core_rknd ), dimension(nz), intent(inout) :: &
+ rtp2_mc, & !Tendency of