diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm
index 408ff9b573..c3f1866bf4 100755
--- a/bld/CLMBuildNamelist.pm
+++ b/bld/CLMBuildNamelist.pm
@@ -4071,7 +4071,16 @@ sub setup_logic_fire_emis {
if ( &value_is_true( $nl_flags->{'use_fates'} ) ) {
$log->warning("Fire emission option $var can NOT be on when FATES is also on.\n" .
" DON'T use the '--fire_emis' option when '--bgc fates' is activated");
- }
+ } elsif ( ! &value_is_true( $nl_flags->{'use_cn'} ) ) {
+ $log->fatal_error("Fire emission option $var can NOT be on when BGC SP (i.e. Satellite Phenology) is also on.\n" .
+ " DON'T use the '--fire_emis' option when '--bgc sp' is activated");
+ } elsif ( &value_is_true( $nl_flags->{'use_cn'}) ) {
+ my $fire_method = remove_leading_and_trailing_quotes( $nl->get_value('fire_method') );
+ if ( $fire_method eq "nofire" ) {
+ $log->fatal_error("Fire emission option $var can NOT be on with BGC and fire_method=='nofire'.\n" .
+ " DON'T use the '--fire_emis' option when fire_method is nofire");
+ }
+ }
}
}
}
@@ -4235,7 +4244,7 @@ sub setup_logic_lai_streams {
if ( &value_is_true($nl_flags->{'use_crop'}) && &value_is_true($nl->get_value('use_lai_streams')) ) {
$log->fatal_error("turning use_lai_streams on is incompatable with use_crop set to true.");
}
- if ( $nl_flags->{'bgc_mode'} eq "sp" || ($nl_flags->{'bgc_mode'} eq "fates" && &value_is_true($nl->get_value('use_fates_sp')) )) {
+ if ( $nl_flags->{'bgc_mode'} eq "sp" || ($nl_flags->{'bgc_mode'} eq "fates" && &value_is_true($nl_flags->{'use_fates_sp'}) )) {
if ( &value_is_true($nl->get_value('use_lai_streams')) ) {
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_lai_streams');
add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'lai_mapalgo',
@@ -4745,29 +4754,26 @@ sub setup_logic_fates {
# For FATES SP mode make sure no-competetiion, and fixed-biogeography are also set
# And also check for other settings that can't be trigged on as well
#
- my $var = "use_fates_sp";
- if ( defined($nl->get_value($var)) ) {
- if ( &value_is_true($nl->get_value($var)) ) {
- my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog" );
- foreach my $var ( @list ) {
- if ( ! &value_is_true($nl->get_value($var)) ) {
- $log->fatal_error("$var is required when FATES SP is on (use_fates_sp)" );
- }
- }
- # spit-fire can't be on with FATES SP mode is active
- if ( $nl->get_value('fates_spitfire_mode') > 0 ) {
- $log->fatal_error('fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true');
- }
+ if ( &value_is_true($nl_flags->{'use_fates_sp'}) ) {
+ my @list = ( "use_fates_nocomp", "use_fates_fixed_biogeog" );
+ foreach my $var ( @list ) {
+ if ( ! &value_is_true($nl->get_value($var)) ) {
+ $log->fatal_error("$var is required when FATES SP is on (use_fates_sp)" );
+ }
+ }
+ # spit-fire can't be on with FATES SP mode is active
+ if ( $nl->get_value('fates_spitfire_mode') > 0 ) {
+ $log->fatal_error('fates_spitfire_mode can NOT be set to greater than 0 when use_fates_sp is true');
+ }
- # fates landuse can't be on with FATES SP mode is active
- if ( &value_is_true($nl->get_value('use_fates_luh')) ) {
- $log->fatal_error('use_fates_luh can NOT be true when use_fates_sp is true');
- }
+ # fates landuse can't be on with FATES SP mode is active
+ if ( &value_is_true($nl->get_value('use_fates_luh')) ) {
+ $log->fatal_error('use_fates_luh can NOT be true when use_fates_sp is true');
+ }
- # hydro isn't currently supported to work when FATES SP mode is active
- if (&value_is_true( $nl->get_value('use_fates_planthydro') )) {
- $log->fatal_error('fates sp mode is currently not supported to work with fates hydro');
- }
+ # hydro isn't currently supported to work when FATES SP mode is active
+ if (&value_is_true( $nl->get_value('use_fates_planthydro') )) {
+ $log->fatal_error('fates sp mode is currently not supported to work with fates hydro');
}
}
my $var = "use_fates_inventory_init";
@@ -4792,6 +4798,13 @@ sub setup_logic_fates {
}
}
}
+ # Check that both FaTES-SP and FATES ST3 aren't both on
+ my $var = "use_fates_ed_st3";
+ if ( defined($nl->get_value($var)) ) {
+ if ( &value_is_true($nl->get_value($var)) && &value_is_true($nl_flags->{'use_fates_sp'}) ) {
+ $log->fatal_error("$var can NOT also be true with use_fates_sp true" );
+ }
+ }
# check that fates landuse change mode has the necessary luh2 landuse timeseries data
# and add the default if not defined. Do not add default if use_fates_potentialveg is true.
# If fixed biogeography is on, make sure that flandusepftdat is avilable.
diff --git a/bld/unit_testers/build-namelist_test.pl b/bld/unit_testers/build-namelist_test.pl
index 19e7af11c1..6892638a21 100755
--- a/bld/unit_testers/build-namelist_test.pl
+++ b/bld/unit_testers/build-namelist_test.pl
@@ -163,10 +163,10 @@ sub cat_and_create_namelistinfile {
#
# Figure out number of tests that will run
#
-my $ntests = 3276;
+my $ntests = 3285;
if ( defined($opts{'compare'}) ) {
- $ntests += 1987;
+ $ntests += 2161;
}
plan( tests=>$ntests );
@@ -288,7 +288,7 @@ sub cat_and_create_namelistinfile {
&make_config_cache($phys);
my @mfiles = ( "lnd_in", "drv_flds_in", $tempfile );
my $mfiles = NMLTest::CompFiles->new( $cwd, @mfiles );
-foreach my $options ( "-drydep", "-megan", "-drydep -megan", "-fire_emis", "-drydep -megan -fire_emis" ) {
+foreach my $options ( "-drydep --bgc sp", "-megan --bgc sp", "-drydep -megan --bgc bgc", "-fire_emis --bgc bgc", "-drydep -megan -fire_emis --bgc bgc" ) {
&make_env_run();
eval{ system( "$bldnml -envxml_dir . $options > $tempfile 2>&1 " ); };
is( $@, '', "options: $options" );
@@ -576,8 +576,8 @@ sub cat_and_create_namelistinfile {
"--res 1.9x2.5 --bgc bgc --use_case 1850-2100_SSP2-4.5_transient --namelist '&a start_ymd=19101023/'",
"-namelist \"&a dust_emis_method='Zender_2003', zender_soil_erod_source='lnd' /'\"",
"-bgc bgc -use_case 2000_control -namelist \"&a fire_method='nofire'/\" -crop",
- "-res 0.9x1.25 -bgc sp -use_case 1850_noanthro_control -drydep -fire_emis",
- "-res 0.9x1.25 -bgc bgc -use_case 1850_noanthro_control -drydep -fire_emis -light_res 360x720",
+ "-res 0.9x1.25 -bgc sp -use_case 1850_noanthro_control -drydep",
+ "-res 0.9x1.25 -bgc bgc -use_case 1850_noanthro_control -drydep -fire_emis -megan -light_res 360x720",
"--bgc bgc --light_res none --namelist \"&a fire_method='nofire'/\"",
"--bgc fates --light_res 360x720 --no-megan --namelist \"&a fates_spitfire_mode=2/\"",
"--bgc fates --light_res none --no-megan --namelist \"&a fates_spitfire_mode=1/\"",
@@ -1093,6 +1093,10 @@ sub cat_and_create_namelistinfile {
namelst=>"suplnitro='NONE'",
phys=>"clm6_0",
},
+ "FATESwBothSpST3" =>{ options=>"--bgc fates --envxml_dir . --no-megan",
+ namelst=>"use_fates_sp = TRUE, use_fates_ed_st3 = TRUE",
+ phys=>"clm6_0",
+ },
"FireNoneButBGCfireon" =>{ options=>"-bgc bgc -envxml_dir . -light_res none",
namelst=>"fire_method='li2021gswpfrc'",
phys=>"clm6_0",
@@ -1145,6 +1149,14 @@ sub cat_and_create_namelistinfile {
namelst=>"",
phys=>"clm4_5",
},
+ "useFIREEMISwithNOFIRE" =>{ options=>"--bgc bgc --envxml_dir . --fire_emis",
+ namelst=>"fire_method='nofire'",
+ phys=>"clm6_0",
+ },
+ "useFIREEMISwithSP" =>{ options=>"--bgc sp --envxml_dir . --fire_emis",
+ namelst=>"",
+ phys=>"clm6_0",
+ },
"useDRYDEPwithFATES" =>{ options=>"--bgc fates --envxml_dir . --no-megan --drydep",
namelst=>"",
phys=>"clm4_5",
diff --git a/cime_config/config_component.xml b/cime_config/config_component.xml
index 689fbcde0d..f869d0e362 100644
--- a/cime_config/config_component.xml
+++ b/cime_config/config_component.xml
@@ -241,12 +241,24 @@
char
-
- -bgc sp
- -bgc bgc
- -bgc bgc -crop
- -bgc fates -no-megan
- -bgc fates -no-megan
+
+ -bgc sp
+ -bgc bgc
+ -bgc bgc -crop
+
+
+ --bgc fates --no-megan --no-drydep --no-fire_emis
+
+
+ --bgc sp --no-megan --no-drydep --no-fire_emis
+ --bgc bgc --no-megan --no-drydep --no-fire_emis
+ --bgc bgc --crop --no-megan --no-drydep --no-fire_emis
+
-bgc bgc -dynamic_vegetation
diff --git a/cime_config/testdefs/testlist_clm.xml b/cime_config/testdefs/testlist_clm.xml
index 70a9ba32fb..968025e244 100644
--- a/cime_config/testdefs/testlist_clm.xml
+++ b/cime_config/testdefs/testlist_clm.xml
@@ -219,7 +219,7 @@
-
+
@@ -228,7 +228,7 @@
-
+
@@ -406,7 +406,7 @@
-
+
@@ -416,7 +416,7 @@
-
+
@@ -425,7 +425,7 @@
-
+
@@ -434,7 +434,7 @@
-
+
@@ -443,7 +443,7 @@
-
+
@@ -453,7 +453,7 @@
-
+
@@ -462,7 +462,7 @@
-
+
@@ -471,7 +471,7 @@
-
+
@@ -480,7 +480,7 @@
-
+
@@ -546,7 +546,7 @@
-
+
@@ -1261,7 +1261,7 @@
-
+
@@ -1289,7 +1289,7 @@
-
+
@@ -1298,7 +1298,7 @@
-
+
@@ -1758,7 +1758,7 @@
-
+
@@ -1776,7 +1776,7 @@
-
+
@@ -1827,7 +1827,7 @@
-
+
@@ -1847,7 +1847,7 @@
-
+
@@ -1856,7 +1856,7 @@
-
+
@@ -2318,7 +2318,7 @@
-
+
@@ -2865,7 +2865,7 @@
-
+
@@ -3597,7 +3597,7 @@
-
+
@@ -3607,7 +3607,7 @@
-
+
@@ -3618,7 +3618,7 @@
-
+
diff --git a/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/include_user_mods
index 1e4ddf5337..bc8c80f140 100644
--- a/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/ExcessIceStreams/include_user_mods
@@ -1,2 +1,2 @@
-../default
../nofireemis
+../default
\ No newline at end of file
diff --git a/cime_config/testdefs/testmods_dirs/clm/SNICARFRC/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/SNICARFRC/include_user_mods
index 1e4ddf5337..bc8c80f140 100644
--- a/cime_config/testdefs/testmods_dirs/clm/SNICARFRC/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/SNICARFRC/include_user_mods
@@ -1,2 +1,2 @@
-../default
../nofireemis
+../default
\ No newline at end of file
diff --git a/cime_config/testdefs/testmods_dirs/clm/collapse_pfts_78_to_16_decStart_f10/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/collapse_pfts_78_to_16_decStart_f10/include_user_mods
index acdaa462fc..821b73c2e0 100644
--- a/cime_config/testdefs/testmods_dirs/clm/collapse_pfts_78_to_16_decStart_f10/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/collapse_pfts_78_to_16_decStart_f10/include_user_mods
@@ -1 +1,2 @@
+../nofireemis
../decStart
diff --git a/cime_config/testdefs/testmods_dirs/clm/o3lombardozzi2015/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/o3lombardozzi2015/include_user_mods
index 1e4ddf5337..d3df58a6b3 100644
--- a/cime_config/testdefs/testmods_dirs/clm/o3lombardozzi2015/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/o3lombardozzi2015/include_user_mods
@@ -1,2 +1,2 @@
-../default
../nofireemis
+../default
diff --git a/cime_config/testdefs/testmods_dirs/clm/pauseResume/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/pauseResume/include_user_mods
index 1e4ddf5337..d3df58a6b3 100644
--- a/cime_config/testdefs/testmods_dirs/clm/pauseResume/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/pauseResume/include_user_mods
@@ -1,2 +1,2 @@
-../default
../nofireemis
+../default
diff --git a/cime_config/testdefs/testmods_dirs/clm/prescribed/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/prescribed/include_user_mods
index 1e4ddf5337..bc8c80f140 100644
--- a/cime_config/testdefs/testmods_dirs/clm/prescribed/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/prescribed/include_user_mods
@@ -1,2 +1,2 @@
-../default
../nofireemis
+../default
\ No newline at end of file
diff --git a/cime_config/testdefs/testmods_dirs/clm/pts/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/pts/include_user_mods
index 1e4ddf5337..d3df58a6b3 100644
--- a/cime_config/testdefs/testmods_dirs/clm/pts/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/pts/include_user_mods
@@ -1,2 +1,2 @@
-../default
../nofireemis
+../default
diff --git a/cime_config/testdefs/testmods_dirs/clm/waccmx_offline/include_user_mods b/cime_config/testdefs/testmods_dirs/clm/waccmx_offline/include_user_mods
index 1e4ddf5337..d3df58a6b3 100644
--- a/cime_config/testdefs/testmods_dirs/clm/waccmx_offline/include_user_mods
+++ b/cime_config/testdefs/testmods_dirs/clm/waccmx_offline/include_user_mods
@@ -1,2 +1,2 @@
-../default
../nofireemis
+../default
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9707af4f0b..2682775ca5 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -45,6 +45,8 @@ add_subdirectory(${CLM_ROOT}/share/unit_test_stubs/util csm_share_stubs)
list ( APPEND drv_sources_needed
${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/glc_elevclass_mod.F90
${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/shr_dust_emis_mod.F90
+ ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/shr_expr_parser_mod.F90
+ ${CLM_ROOT}/components/cmeps/cesm/nuopc_cap_share/shr_fire_emis_mod.F90
)
# Add CLM source directories
diff --git a/src/biogeochem/CMakeLists.txt b/src/biogeochem/CMakeLists.txt
index 270e85838b..3da0a2eab6 100644
--- a/src/biogeochem/CMakeLists.txt
+++ b/src/biogeochem/CMakeLists.txt
@@ -2,6 +2,7 @@
# source files that are currently used in unit tests
list(APPEND clm_sources
+ ch4varcon.F90
CNSharedParamsMod.F90
CNPhenologyMod.F90
CNSpeciesMod.F90
@@ -12,6 +13,14 @@ list(APPEND clm_sources
DustEmisFactory.F90
CropReprPoolsMod.F90
CropType.F90
+ CNFireBaseMod.F90
+ CNFireNoFireMod.F90
+ CNFireFactoryMod.F90
+ CNFireLi2014Mod.F90
+ CNFireLi2016Mod.F90
+ CNFireLi2021Mod.F90
+ CNFireLi2024Mod.F90
+ CNVegMatrixMod.F90
CNVegStateType.F90
CNVegCarbonStateType.F90
CNVegCarbonFluxType.F90
@@ -20,6 +29,11 @@ list(APPEND clm_sources
CNVegNitrogenFluxType.F90
CNCIsoAtmTimeSeriesReadMod.F90
CNVegComputeSeedMod.F90
+ FATESFireBase.F90
+ FATESFireDataMod.F90
+ FATESFireFactoryMod.F90
+ FATESFireNoDataMod.F90
+ SatellitePhenologyMod.F90
SpeciesBaseType.F90
SpeciesIsotopeType.F90
SpeciesNonIsotopeType.F90
diff --git a/src/biogeochem/CNDriverMod.F90 b/src/biogeochem/CNDriverMod.F90
index b407e07ad5..9a51d9f616 100644
--- a/src/biogeochem/CNDriverMod.F90
+++ b/src/biogeochem/CNDriverMod.F90
@@ -60,7 +60,7 @@ module CNDriverMod
contains
!-----------------------------------------------------------------------
- subroutine CNDriverInit(bounds, NLFilename, cnfire_method)
+ subroutine CNDriverInit(bounds, NLFilename)
!
! !DESCRIPTION:
! Initialzation of the CN Ecosystem dynamics.
@@ -68,18 +68,15 @@ subroutine CNDriverInit(bounds, NLFilename, cnfire_method)
! !USES:
use CNSharedParamsMod , only : use_fun
use CNPhenologyMod , only : CNPhenologyInit
- use FireMethodType , only : fire_method_type
use SoilBiogeochemCompetitionMod, only : SoilBiogeochemCompetitionInit
!
! !ARGUMENTS:
type(bounds_type) , intent(in) :: bounds
character(len=*) , intent(in) :: NLFilename ! Namelist filename
- class(fire_method_type) , intent(inout) :: cnfire_method
!-----------------------------------------------------------------------
call SoilBiogeochemCompetitionInit(bounds)
if(use_cn)then
call CNPhenologyInit(bounds)
- call cnfire_method%FireInit(bounds, NLFilename)
end if
end subroutine CNDriverInit
diff --git a/src/biogeochem/CNFireBaseMod.F90 b/src/biogeochem/CNFireBaseMod.F90
index 2f9e99ea44..42a054b44c 100644
--- a/src/biogeochem/CNFireBaseMod.F90
+++ b/src/biogeochem/CNFireBaseMod.F90
@@ -85,13 +85,17 @@ module CNFireBaseMod
private
! !PRIVATE MEMBER DATA:
! !PUBLIC MEMBER DATA (used by extensions of the base class):
- real(r8), public, pointer :: btran2_patch (:) ! patch root zone soil wetness factor (0 to 1)
+ real(r8), public, pointer :: btran2_patch (:) => NULL() ! patch root zone soil wetness factor (0 to 1)
contains
!
! !PUBLIC MEMBER FUNCTIONS:
+ procedure, public :: CNFireInit ! Initialization of Fire
procedure, public :: FireInit => CNFireInit ! Initialization of Fire
- procedure, public :: FireReadNML ! Read in namelist for CNFire
+ procedure, public :: CNFireCleanBase ! Deallocate fire data
+ procedure, public :: FireClean => CNFireCleanBase ! Deallocate fire data
+ procedure, public :: CNFireReadNML ! Read in namelist for CNFire
+ procedure, public :: FireReadNML => CNFireReadNML ! Read in namelist for CNFire
procedure, public :: CNFireReadParams ! Read in constant parameters from the paramsfile
procedure, public :: CNFireFluxes ! Calculate fire fluxes
procedure, public :: CNFire_calc_fire_root_wetness_Li2014 ! Calculate CN-fire specific root wetness: original version
@@ -129,17 +133,16 @@ end function need_lightning_and_popdens_interface
contains
!-----------------------------------------------------------------------
- subroutine CNFireInit( this, bounds, NLFilename )
+ subroutine CNFireInit( this, bounds )
!
! !DESCRIPTION:
! Initialize CN Fire module
! !ARGUMENTS:
class(cnfire_base_type) :: this
type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename
!-----------------------------------------------------------------------
! Call the base-class Initialization method
- call this%BaseFireInit( bounds, NLFilename )
+ call this%BaseFireInit( bounds )
! Allocate memory
call this%InitAllocate( bounds )
@@ -185,6 +188,24 @@ subroutine InitHistory( this, bounds )
ptr_patch=this%btran2_patch, l2g_scale_type='veg')
end subroutine InitHistory
+ !----------------------------------------------------------------------
+
+ subroutine CNFireCleanBase( this )
+ !
+ ! Deallocate data
+ !
+ ! !ARGUMENTS:
+ class(cnfire_base_type) :: this
+ !-----------------------------------------------------------------------
+ ! Call the base class clean method
+ !call this%BaseFireClean()
+
+ if ( associated(this%btran2_patch) )then
+ deallocate(this%btran2_patch)
+ end if
+ this%btran2_patch => NULL()
+ end subroutine CNFireCleanBase
+
!----------------------------------------------------------------------
subroutine CNFire_calc_fire_root_wetness_Li2014( this, bounds, &
num_exposedvegp, filter_exposedvegp, num_noexposedvegp, filter_noexposedvegp, &
@@ -321,7 +342,7 @@ end subroutine CNFire_calc_fire_root_wetness_Li2021
!----------------------------------------------------------------------
!----------------------------------------------------------------------
- subroutine FireReadNML( this, NLFilename )
+ subroutine CNFireReadNML( this, bounds, NLFilename )
!
! !DESCRIPTION:
! Read the namelist for CNFire
@@ -331,17 +352,17 @@ subroutine FireReadNML( this, NLFilename )
use shr_nl_mod , only : shr_nl_find_group_name
use spmdMod , only : masterproc, mpicom
use shr_mpi_mod , only : shr_mpi_bcast
- use clm_varctl , only : iulog
!
! !ARGUMENTS:
class(cnfire_base_type) :: this
+ type(bounds_type), intent(in):: bounds !bounds
character(len=*), intent(in) :: NLFilename ! Namelist filename
!
! !LOCAL VARIABLES:
integer :: ierr ! error code
integer :: unitn ! unit for namelist file
- character(len=*), parameter :: subname = 'FireReadNML'
+ character(len=*), parameter :: subname = 'CNFireReadNML'
character(len=*), parameter :: nmlname = 'lifire_inparm'
!-----------------------------------------------------------------------
real(r8) :: cli_scale, boreal_peatfire_c, pot_hmn_ign_counts_alpha
@@ -361,6 +382,9 @@ subroutine FireReadNML( this, NLFilename )
borpeat_fire_soilmoist_denom, nonborpeat_fire_precip_denom
if ( this%need_lightning_and_popdens() ) then
+ ! Read the base namelist
+ call this%BaseFireReadNML( bounds, NLFilename )
+
cli_scale = cnfire_const%cli_scale
boreal_peatfire_c = cnfire_const%boreal_peatfire_c
non_boreal_peatfire_c = cnfire_const%non_boreal_peatfire_c
@@ -392,9 +416,11 @@ subroutine FireReadNML( this, NLFilename )
read(unitn, nml=lifire_inparm, iostat=ierr)
if (ierr /= 0) then
call endrun(msg="ERROR reading "//nmlname//"namelist"//errmsg(sourcefile, __LINE__))
+ return
end if
else
call endrun(msg="ERROR could NOT find "//nmlname//"namelist"//errmsg(sourcefile, __LINE__))
+ return
end if
call relavu( unitn )
end if
@@ -447,7 +473,7 @@ subroutine FireReadNML( this, NLFilename )
end if
end if
- end subroutine FireReadNML
+ end subroutine CNFireReadNML
!-----------------------------------------------------------------------
subroutine CNFireFluxes (this, bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, &
diff --git a/src/biogeochem/CNFireFactoryMod.F90 b/src/biogeochem/CNFireFactoryMod.F90
index 44407da927..9d1962d4ff 100644
--- a/src/biogeochem/CNFireFactoryMod.F90
+++ b/src/biogeochem/CNFireFactoryMod.F90
@@ -9,17 +9,20 @@ module CNFireFactoryMod
use abortutils , only : endrun
use shr_log_mod , only : errMsg => shr_log_errMsg
use clm_varctl , only : iulog
+ use shr_kind_mod , only : CS => SHR_KIND_CS
implicit none
save
private
!
! !PUBLIC ROUTINES:
- public :: CNFireReadNML ! read the fire namelist
+ public :: CNFireReadNML ! read the fire factory namelist to get the CN fire_method to use
public :: create_cnfire_method ! create an object of class fire_method_type
+ ! For Unit Testing:
+ public :: CNFireSetFireMethod ! Set the fire_method
! !PRIVATE DATA MEMBERS:
- character(len=80), private :: fire_method = "li2014qianfrc"
+ character(len=CS), private :: fire_method = "UNSET"
character(len=*), parameter, private :: sourcefile = &
__FILE__
@@ -63,9 +66,11 @@ subroutine CNFireReadNML( NLFilename )
read(unitn, nml=cnfire_inparm, iostat=ierr)
if (ierr /= 0) then
call endrun(msg="ERROR reading "//nmlname//"namelist"//errmsg(sourcefile, __LINE__))
+ return
end if
else
call endrun(msg="ERROR finding "//nmlname//"namelist"//errmsg(sourcefile, __LINE__))
+ return
end if
call relavu( unitn )
end if
@@ -82,7 +87,7 @@ end subroutine CNFireReadNML
!-----------------------------------------------------------------------
!-----------------------------------------------------------------------
- subroutine create_cnfire_method( NLFilename, cnfire_method )
+ subroutine create_cnfire_method( cnfire_method )
!
! !DESCRIPTION:
! Create and return an object of fire_method_type. The particular type
@@ -98,11 +103,9 @@ subroutine create_cnfire_method( NLFilename, cnfire_method )
use decompMod , only : bounds_type
!
! !ARGUMENTS:
- character(len=*), intent(in) :: NLFilename ! Namelist filename
class(fire_method_type), allocatable, intent(inout) :: cnfire_method
!
! !LOCAL VARIABLES:
- character(len=*), parameter :: subname = 'create_cnfire_method'
!-----------------------------------------------------------------------
select case (trim(fire_method))
@@ -119,13 +122,29 @@ subroutine create_cnfire_method( NLFilename, cnfire_method )
allocate(cnfire_li2024_type :: cnfire_method)
case default
- write(iulog,*) subname//' ERROR: unknown method: ', fire_method
- call endrun(msg=errMsg(sourcefile, __LINE__))
+ write(iulog,*) 'Unrecognized fire_method ' // errMsg(sourcefile, __LINE__)
+ call endrun( msg='Unknown option for namelist item fire_method: ' // trim(fire_method) )
+ ! For unit-testing, make sure a valid cnfire_method is set and return, otherwise it fails with a seg-fault
+ allocate(cnfire_nofire_type :: cnfire_method)
+ return
end select
- call cnfire_method%FireReadNML( NLFilename )
end subroutine create_cnfire_method
!-----------------------------------------------------------------------
+ subroutine CNFireSetFireMethod( fire_method_in )
+ !
+ ! !DESCRIPTION:
+ ! Set the fire_method (to be used in unit testing)
+ !
+ ! !USES:
+ ! !ARGUMENTS:
+ character(len=*), intent(IN) :: fire_method_in
+
+ fire_method = trim(fire_method_in)
+
+ end subroutine CNFireSetFireMethod
+ !-----------------------------------------------------------------------
+
end module CNFireFactoryMod
diff --git a/src/biogeochem/CNFireNoFireMod.F90 b/src/biogeochem/CNFireNoFireMod.F90
index e0605585e9..da6f28cd0d 100644
--- a/src/biogeochem/CNFireNoFireMod.F90
+++ b/src/biogeochem/CNFireNoFireMod.F90
@@ -8,6 +8,8 @@ module CNFireNoFireMod
!
! !USES:
use shr_kind_mod , only : r8 => shr_kind_r8
+ use abortutils , only : endrun
+ use clm_varctl , only : iulog
use decompMod , only : bounds_type
use atm2lndType , only : atm2lnd_type
use CNVegStateType , only : cnveg_state_type
@@ -36,10 +38,15 @@ module CNFireNoFireMod
contains
!
! !PUBLIC MEMBER FUNCTIONS:
- procedure, public :: need_lightning_and_popdens
- procedure, public :: CNFireArea ! Calculate fire area
+ procedure, public :: need_lightning_and_popdens ! If need lightning and/or population density (always .false. here)
+ procedure, public :: NoFireInit ! Initiialization
+ procedure, public :: FireInit => NoFireInit ! Initiialization
+ procedure, public :: CNFireArea ! Calculate fire area
end type cnfire_nofire_type
+ character(len=*), parameter, private :: sourcefile = &
+ __FILE__
+
contains
!-----------------------------------------------------------------------
@@ -56,6 +63,28 @@ function need_lightning_and_popdens(this)
need_lightning_and_popdens = .false.
end function need_lightning_and_popdens
+ !-----------------------------------------------------------------------
+ subroutine NoFireInit( this, bounds )
+ !
+ ! !DESCRIPTION:
+ ! Initialize No Fire module
+ use shr_fire_emis_mod, only : shr_fire_emis_mechcomps_n
+ use shr_log_mod , only : errMsg => shr_log_errMsg
+ ! !ARGUMENTS:
+ class(cnfire_nofire_type) :: this
+ type(bounds_type), intent(in) :: bounds
+
+ if ( shr_fire_emis_mechcomps_n > 0) then
+ write(iulog,*) "Fire emissions can NOT be active for fire_method=nofire" // &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Having fire emissions on requires fire_method to be something besides nofire" )
+ return
+ end if
+ call this%CNFireInit( bounds )
+
+ end subroutine NoFireInit
+ !-----------------------------------------------------------------------
+
!-----------------------------------------------------------------------
subroutine CNFireArea (this, bounds, num_soilc, filter_soilc, num_soilp, filter_soilp, &
num_exposedvegp, filter_exposedvegp, num_noexposedvegp, filter_noexposedvegp, &
diff --git a/src/biogeochem/CNVegetationFacade.F90 b/src/biogeochem/CNVegetationFacade.F90
index 47099708f4..b47237690d 100644
--- a/src/biogeochem/CNVegetationFacade.F90
+++ b/src/biogeochem/CNVegetationFacade.F90
@@ -204,10 +204,12 @@ subroutine Init(this, bounds, NLFilename, nskip_steps, params_ncid)
!
! !USES:
use CNFireFactoryMod , only : create_cnfire_method
+ use CNFireNoFireMod , only : cnfire_nofire_type
use clm_varcon , only : c13ratio, c14ratio
use ncdio_pio , only : file_desc_t
use filterMod , only : filter
use decompMod , only : get_proc_clumps
+
!
! !ARGUMENTS:
class(cn_vegetation_type), intent(inout) :: this
@@ -302,10 +304,21 @@ subroutine Init(this, bounds, NLFilename, nskip_steps, params_ncid)
! use_cndv is true so that it can be used in associate statements (nag compiler
! complains otherwise)
call this%dgvs_inst%Init(bounds)
- end if
- call create_cnfire_method(NLFilename, this%cnfire_method)
- call this%cnfire_method%CNFireReadParams( params_ncid )
+ call create_cnfire_method( this%cnfire_method )
+ call this%cnfire_method%FireInit( bounds )
+ call this%cnfire_method%FireReadNML( bounds, NLFilename )
+ call this%cnfire_method%CNFireReadParams( params_ncid )
+ end if
+
+ !
+ ! For FATES we HAVE to allocate a cnfire_method even through it won't be used
+ ! cnfire_method is passed down to CN routines that are used for FATES
+ ! so there has to be something allocated that is passed down
+ !
+ if ( use_fates_bgc )then
+ allocate(cnfire_nofire_type :: this%cnfire_method)
+ end if
end subroutine Init
@@ -584,7 +597,7 @@ subroutine Init2(this, bounds, NLFilename)
character(len=*), parameter :: subname = 'Init2'
!-----------------------------------------------------------------------
- call CNDriverInit(bounds, NLFilename, this%cnfire_method)
+ call CNDriverInit(bounds, NLFilename)
if (use_cndv) then
call dynCNDV_init(bounds, this%dgvs_inst)
diff --git a/src/biogeochem/FATESFireFactoryMod.F90 b/src/biogeochem/FATESFireFactoryMod.F90
index 0352994e5f..94e3eee4c3 100644
--- a/src/biogeochem/FATESFireFactoryMod.F90
+++ b/src/biogeochem/FATESFireFactoryMod.F90
@@ -42,7 +42,8 @@ subroutine create_fates_fire_data_method( fates_fire_data_method )
! The particular type is determined based on a namelist parameter.
!
! !USES:
- use clm_varctl, only: fates_spitfire_mode
+ use clm_varctl, only: fates_spitfire_mode, use_fates_sp, use_fates_ed_st3
+ use shr_fire_emis_mod, only : shr_fire_emis_mechcomps_n
use FATESFireBase, only: fates_fire_base_type
use FATESFireNoDataMod, only: fates_fire_no_data_type
use FATESFireDataMod, only: fates_fire_data_type
@@ -51,25 +52,69 @@ subroutine create_fates_fire_data_method( fates_fire_data_method )
class(fates_fire_base_type), allocatable, intent(inout) :: fates_fire_data_method ! function result
!
! !LOCAL VARIABLES:
- integer :: current_case
-
- character(len=*), parameter :: subname = 'create_fates_fire_data_method'
!-----------------------------------------------------------------------
- current_case = fates_spitfire_mode
-
- select case (current_case)
+ !
+ ! For FATES options that bypass fire...
+ !
+ if ( use_fates_sp .or. use_fates_ed_st3 )then
+ !
+ ! Make sure fire-emissions is NOT on
+ !
+ if ( shr_fire_emis_mechcomps_n > 0 )then
+ if ( use_fates_sp )then
+ write(iulog,*) "Fire emissions can NOT be on with FATES-SP mode: ", &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Fire emission with FATES requires FATES to NOT be in Satellite Phenology (SP) mode" )
+ else if ( use_fates_ed_st3 )then
+ write(iulog,*) "Fire emissions can NOT be on with FATES ST3 mode: ", &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Fire emission with FATES requires FATES to NOT be in Static Stand Structure mode" )
+ end if
+ ! For unit-testing return with a FATESFireData type, so there isn't a run-time error
+ ! Also do the FATESFireData type, as using FATESFireNoData type will fail with an error
+ allocate(fates_fire_data_type :: fates_fire_data_method)
+ return
+ end if
+ allocate(fates_fire_no_data_type :: fates_fire_data_method)
+ else
+ !
+ ! For regular FATES options that include fire
+ !
+ select case (fates_spitfire_mode)
- case (no_fire:scalar_lightning)
- allocate(fates_fire_no_data_type :: fates_fire_data_method)
- case (lightning_from_data:anthro_suppression)
- allocate(fates_fire_data_type :: fates_fire_data_method)
+ ! No-fire, scalar-lightning and successful_ignitions ALL do NOT need input data from the base class
+ case (no_fire:scalar_lightning)
+ allocate(fates_fire_no_data_type :: fates_fire_data_method)
+ case (successful_ignitions)
+ allocate(fates_fire_no_data_type :: fates_fire_data_method)
+ ! Lightning from data, and the anthro types (ignition and suppression) need lightning data from the base class
+ case (lightning_from_data)
+ allocate(fates_fire_data_type :: fates_fire_data_method)
+ case (anthro_ignitions:anthro_suppression)
+ allocate(fates_fire_data_type :: fates_fire_data_method)
- case default
- write(iulog,*) subname//' ERROR: unknown method: ', fates_spitfire_mode
- call endrun(msg=errMsg(sourcefile, __LINE__))
+ case default
+ write(iulog,*) 'Unrecognized fates_spitfire_mode option = ', fates_spitfire_mode, ' in: ', &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Unknown option for namelist item fates_spitfire_mode:")
+ ! For unit-testing, make sure a valid fates_fire_data_method is set and return, otherwise it fails with a seg-fault
+ allocate(fates_fire_no_data_type :: fates_fire_data_method)
- end select
+ end select
+ ! -------------------------------------------------------------------------------------------------------
+ ! For now we die with a error whenever fire-emissions are turned on -- because this isn't setup in FATES
+ !
+ if ( fates_spitfire_mode /= no_fire ) then
+ if ( shr_fire_emis_mechcomps_n > 0 )then
+ write(iulog,*) "Fire emissions can NOT be on with FATES currently: ", &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Fire emission with FATES can NOT currently be turned on (see issue #1045)" )
+ return
+ end if
+ end if
+ ! -------------------------------------------------------------------------------------------------------
+ end if
end subroutine create_fates_fire_data_method
diff --git a/src/biogeochem/FATESFireNoDataMod.F90 b/src/biogeochem/FATESFireNoDataMod.F90
index 4034b68e97..65b7bae5af 100644
--- a/src/biogeochem/FATESFireNoDataMod.F90
+++ b/src/biogeochem/FATESFireNoDataMod.F90
@@ -27,6 +27,8 @@ module FATESFireNoDataMod
contains
! !PUBLIC MEMBER FUNCTIONS:
+ procedure, public :: FATESNoFireInit! Initialization
+ procedure, public :: FireInit => FATESNoFireInit
procedure, public :: need_lightning_and_popdens
procedure, public :: GetLight24 ! Return the 24-hour averaged lightning data
procedure, public :: GetGDP ! Return the global gdp data
@@ -40,6 +42,28 @@ module FATESFireNoDataMod
contains
+ !-----------------------------------------------------------------------
+ subroutine FATESNoFireInit( this, bounds )
+ !
+ ! !DESCRIPTION:
+ ! Initialize No Fire data module for FATES
+ use shr_fire_emis_mod, only : shr_fire_emis_mechcomps_n
+ use shr_log_mod , only : errMsg => shr_log_errMsg
+ use clm_varctl , only : fates_spitfire_mode
+ ! !ARGUMENTS:
+ class(fates_fire_no_data_type) :: this
+ type(bounds_type), intent(in) :: bounds
+
+ if ( (shr_fire_emis_mechcomps_n > 0) .and. (fates_spitfire_mode == 0) ) then
+ write(iulog,*) "Fire emissions can NOT be active for fates_spitfire_mode=0 (no_fire)", &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Having fire emissions on requires fates_spitfire_mode to be something besides no_fire (0)" )
+ return
+ end if
+ call this%CNFireInit( bounds )
+
+ end subroutine FATESNoFireInit
+
!------------------------------------------------------------------------
function need_lightning_and_popdens(this)
! !ARGUMENTS:
diff --git a/src/biogeochem/SatellitePhenologyMod.F90 b/src/biogeochem/SatellitePhenologyMod.F90
index ffce605e88..7747aad5fa 100644
--- a/src/biogeochem/SatellitePhenologyMod.F90
+++ b/src/biogeochem/SatellitePhenologyMod.F90
@@ -18,7 +18,8 @@ module SatellitePhenologyMod
use spmdMod , only : masterproc, mpicom, iam
use laiStreamMod , only : lai_init, lai_advance, lai_interp
use clm_varctl , only : use_fates
- use ncdio_pio
+ use ncdio_pio , only : ncd_pio_openfile, ncd_inqfdims, check_dim_size, ncd_io
+ use ncdio_pio , only : ncd_pio_closefile, file_desc_t
!
! !PUBLIC TYPES:
implicit none
@@ -56,6 +57,9 @@ subroutine SatellitePhenologyInit (bounds)
!
! !USES:
use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=)
+ use shr_fire_emis_mod, only : shr_fire_emis_mechcomps_n
+ use shr_log_mod, only : errMsg => shr_log_errMsg
+ use clm_varctl, only : use_cn
!
! !ARGUMENTS:
type(bounds_type), intent(in) :: bounds
@@ -63,6 +67,12 @@ subroutine SatellitePhenologyInit (bounds)
! !LOCAL VARIABLES:
integer :: ier ! error code
!-----------------------------------------------------------------------
+ if ( (shr_fire_emis_mechcomps_n > 0) .and. (.not. use_cn) ) then
+ write(iulog,*) "Fire emissions can NOT be active for Satellite Phenology mode (SP)" // &
+ errMsg(sourcefile, __LINE__)
+ call endrun(msg="Fire emission requires BGC to be on rather than a Satelitte Pheonology (SP) case")
+ return
+ end if
InterpMonths1 = -999 ! saved month index
diff --git a/src/biogeochem/test/CMakeLists.txt b/src/biogeochem/test/CMakeLists.txt
index e22a720523..2ebe27c76f 100644
--- a/src/biogeochem/test/CMakeLists.txt
+++ b/src/biogeochem/test/CMakeLists.txt
@@ -3,3 +3,5 @@ add_subdirectory(CNVegComputeSeed_test)
add_subdirectory(CNPhenology_test)
add_subdirectory(Latbaset_test)
add_subdirectory(DustEmis_test)
+add_subdirectory(CNFireFactory_test)
+add_subdirectory(FATESFireFactory_test)
diff --git a/src/biogeochem/test/CNFireFactory_test/CMakeLists.txt b/src/biogeochem/test/CNFireFactory_test/CMakeLists.txt
new file mode 100644
index 0000000000..032e0fa953
--- /dev/null
+++ b/src/biogeochem/test/CNFireFactory_test/CMakeLists.txt
@@ -0,0 +1,7 @@
+set (pfunit_sources
+ test_CNFireFactory.pf
+)
+
+add_pfunit_ctest(CNFireFActory
+ TEST_SOURCES "${pfunit_sources}"
+ LINK_LIBRARIES clm csm_share esmf)
diff --git a/src/biogeochem/test/CNFireFactory_test/test_CNFireFactory.pf b/src/biogeochem/test/CNFireFactory_test/test_CNFireFactory.pf
new file mode 100644
index 0000000000..5b0f52c8d4
--- /dev/null
+++ b/src/biogeochem/test/CNFireFactory_test/test_CNFireFactory.pf
@@ -0,0 +1,240 @@
+module test_CNFireFactory
+
+ ! Tests of CNFireFactory
+
+ use funit
+ use unittestSubgridMod, only : bounds
+ use FireMethodType , only : fire_method_type
+ use CNFireFactoryMod
+ use ESMF, only : ESMF_SUCCESS
+ use shr_kind_mod , only : r8 => shr_kind_r8
+ use clm_varctl, only : use_cn, iulog
+
+ implicit none
+
+ @TestCase
+ type, extends(TestCase) :: TestCNFireFactory
+ logical :: initialized = .false.
+ class(fire_method_type), allocatable :: cnfire_method
+ contains
+ procedure :: setUp
+ procedure :: tearDown
+ procedure :: FireFactInit
+ procedure :: turn_fire_emis_on
+ end type TestCNFireFactory
+
+ contains
+
+ !-----------------------------------------------------------------------
+
+ subroutine setUp(this)
+ use shr_log_mod, only : shr_log_setLogUnit
+ use ESMF, only : ESMF_Initialize, ESMF_IsInitialized
+ use shr_sys_mod, only : shr_sys_system
+ class(TestCNFireFactory), intent(inout) :: this
+
+ integer :: rc
+ logical :: esmf_initialized
+
+ esmf_initialized = ESMF_IsInitialized( rc=rc )
+ if (rc /= ESMF_SUCCESS) then
+ stop 'Error in ESMF_IsInitialized'
+ end if
+ if ( .not. esmf_initialized )then
+ call ESMF_Initialize( rc=rc )
+ if (rc /= ESMF_SUCCESS) then
+ stop 'Error in ESMF_Initialize'
+ end if
+ end if
+ use_cn = .true.
+ iulog = 6
+ call shr_log_setLogUnit(iulog)
+ this%initialized = .false.
+
+ end subroutine setUp
+ !-----------------------------------------------------------------------
+
+ subroutine tearDown(this)
+ use shr_sys_mod, only : shr_sys_system
+ use shr_log_mod, only : shr_log_setLogUnit
+ class(TestCNFireFactory), intent(inout) :: this
+
+ integer :: rc
+
+ ! A clean method should be added to the fire method class structures
+ if ( this%initialized )then
+ call this%cnfire_method%FireClean()
+ deallocate( this%cnfire_method )
+ end if
+ ! IMPORTANT NOTE: DO NOT CALL ESMF_Finalize HERE!
+ ! Calling ESMF_Finalize here, with full ESMF, means you couldn't call ESMF_Initialize again
+ this%initialized = .false.
+
+ end subroutine tearDown
+
+ !-----------------------------------------------------------------------
+
+ subroutine FireFactInit(this, fire_method)
+ class(TestCNFireFactory), intent(inout) :: this
+ character(len=*), intent(in) :: fire_method
+
+ if ( trim(fire_method) /= "DO_NOT_SET") then
+ call CNFireSetFireMethod( fire_method_in=fire_method )
+ end if
+ call create_cnfire_method(this%cnfire_method)
+ call this%cnfire_method%FireInit(bounds)
+ this%initialized = .true.
+
+ end subroutine FireFactInit
+
+ !-----------------------------------------------------------------------
+
+ subroutine turn_fire_emis_on(this)
+ use shr_fire_emis_mod, only : shr_fire_emis_readnl, shr_fire_emis_mechcomps_n
+ use shr_sys_mod, only : shr_sys_system
+ class(TestCNFireFactory), intent(inout) :: this
+
+ ! NOTE!: This is bad that this can be done directly without having it done through a namelist, or setter!
+ shr_fire_emis_mechcomps_n = 2
+ end subroutine turn_fire_emis_on
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine fire_method_not_set_fails(this)
+ class(TestCNFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ call this%FireFactInit( fire_method = "DO_NOT_SET")
+ expected_msg = "ABORTED: Unknown option for namelist item fire_method: UNSET"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine fire_method_not_set_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine fire_method_bad_fails(this)
+ class(TestCNFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ call this%FireFactInit( fire_method = "ZZTOP") ! Set to an invalid option
+ expected_msg = "ABORTED: Unknown option for namelist item fire_method: ZZTOP"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine fire_method_bad_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine nofire_with_fire_emis_fails(this)
+ class(TestCNFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ call this%turn_fire_emis_on()
+ call this%FireFactInit( fire_method = "nofire")
+ expected_msg = "ABORTED: Having fire emissions on requires fire_method to be something besides nofire"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine nofire_with_fire_emis_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine spcase_with_fire_emis_fails(this)
+ use SatellitePhenologyMod, only : SatellitePhenologyInit
+ class(TestCNFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ use_cn = .false.
+ call this%turn_fire_emis_on()
+ call SatellitePhenologyInit( bounds )
+ expected_msg = "ABORTED: Fire emission requires BGC to be on rather than a Satelitte Pheonology (SP) case"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine spcase_with_fire_emis_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine li2014_works(this)
+ class(TestCNFireFactory), intent(inout) :: this
+
+ call this%FireFactInit( fire_method = "li2014qianfrc")
+
+ end subroutine li2014_works
+
+ !-----------------------------------------------------------------------
+
+ !
+ ! Test that default settings with ALL of the Li Fire options work by default
+ ! (These tests are done one by one which makes them dead simple, but take up more code
+ ! see the looping option below)
+ !
+ @Test
+ subroutine li2016_works(this)
+ class(TestCNFireFactory), intent(inout) :: this
+
+ call this%FireFactInit( fire_method = "li2016crufrc")
+
+ end subroutine li2016_works
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine li2021_works(this)
+ class(TestCNFireFactory), intent(inout) :: this
+
+ call this%FireFactInit( fire_method = "li2021gswpfrc")
+
+ end subroutine li2021_works
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine li2024_works(this)
+ class(TestCNFireFactory), intent(inout) :: this
+
+ call this%FireFactInit( fire_method = "li2024gswpfrc")
+
+ end subroutine li2024_works
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine li2024crujra_works(this)
+ class(TestCNFireFactory), intent(inout) :: this
+
+ call this%FireFactInit( fire_method = "li2024crujra")
+
+ end subroutine li2024crujra_works
+
+ !-----------------------------------------------------------------------
+
+ !
+ ! Test that default settings with ALL of the Li Fire options work when fire emissions
+ ! are turned on. This test is done with a loop rather than one by one as above.
+ ! This cuts down on the total test code, but also means that setUp and tearDown have
+ ! to be explicitly called for example. Setup is always called before a test, and tearDown
+ ! after each test)
+ !
+
+ @Test
+ subroutine all_li_options_with_fire_emis_works(this)
+ class(TestCNFireFactory), intent(inout) :: this
+ integer, parameter :: noptions = 5
+ integer :: i
+ character(len=*), parameter :: fire_method_options(noptions) = (/ 'li2014qianfrc', 'li2016crufrc ', 'li2021gswpfrc', 'li2024gswpfrc', 'li2024crujra '/)
+
+ do i = 1, noptions
+ call this%setUp() ! This is needed because of the loop over all options
+ call this%turn_fire_emis_on()
+ call this%FireFactInit( fire_method = fire_method_options(i) )
+ call this%tearDown() ! This is needed because of the loop over all options
+ end do
+
+ end subroutine all_li_options_with_fire_emis_works
+
+ !-----------------------------------------------------------------------
+
+end module test_CNFireFactory
diff --git a/src/biogeochem/test/FATESFireFactory_test/CMakeLists.txt b/src/biogeochem/test/FATESFireFactory_test/CMakeLists.txt
new file mode 100644
index 0000000000..80ac4114e7
--- /dev/null
+++ b/src/biogeochem/test/FATESFireFactory_test/CMakeLists.txt
@@ -0,0 +1,7 @@
+set (pfunit_sources
+ test_FATESFireFactory.pf
+)
+
+add_pfunit_ctest(FATESFireFActory
+ TEST_SOURCES "${pfunit_sources}"
+ LINK_LIBRARIES clm csm_share esmf)
diff --git a/src/biogeochem/test/FATESFireFactory_test/test_FATESFireFactory.pf b/src/biogeochem/test/FATESFireFactory_test/test_FATESFireFactory.pf
new file mode 100644
index 0000000000..fba39098a8
--- /dev/null
+++ b/src/biogeochem/test/FATESFireFactory_test/test_FATESFireFactory.pf
@@ -0,0 +1,167 @@
+module test_FATESFireFactory
+
+ ! Tests of FATESFireFactory
+
+ use funit
+ use unittestSubgridMod, only : bounds
+ use FATESFireBase, only : fates_fire_base_type
+ use FATESFireFactoryMod
+ use shr_kind_mod , only : r8 => shr_kind_r8, CS => shr_kind_CS
+ use clm_varctl, only : iulog, fates_spitfire_mode, use_fates, use_fates_sp, use_fates_ed_st3
+
+ implicit none
+
+ @TestCase
+ type, extends(TestCase) :: TestFATESFireFactory
+ logical :: initialized = .false.
+ class(fates_fire_base_type), allocatable :: fates_fire_method
+ contains
+ procedure :: setUp
+ procedure :: tearDown
+ procedure :: FireFactInit
+ procedure :: turn_fire_emis_on
+ end type TestFATESFireFactory
+
+ contains
+
+ !-----------------------------------------------------------------------
+
+ subroutine setUp(this)
+ use shr_log_mod, only : shr_log_setLogUnit
+ use ESMF, only : ESMF_Initialize
+ use shr_sys_mod, only : shr_sys_system
+ class(TestFATESFireFactory), intent(inout) :: this
+
+ call ESMF_Initialize()
+ use_fates = .true.
+ use_fates_sp = .false.
+ use_fates_ed_st3 = .false.
+ fates_spitfire_mode = no_fire
+ iulog = 6
+ call shr_log_setLogUnit(iulog)
+ this%initialized = .false.
+
+ end subroutine setUp
+ !-----------------------------------------------------------------------
+
+ subroutine tearDown(this)
+ use shr_sys_mod, only : shr_sys_system
+ use shr_log_mod, only : shr_log_setLogUnit
+ class(TestFATESFireFactory), intent(inout) :: this
+
+ if ( this%initialized )then
+ call this%fates_fire_method%FireClean()
+ deallocate( this%fates_fire_method )
+ end if
+ this%initialized = .false.
+
+ end subroutine tearDown
+
+ !-----------------------------------------------------------------------
+
+ subroutine FireFactInit(this)
+ class(TestFATESFireFactory), intent(inout) :: this
+
+ call create_fates_fire_data_method(this%fates_fire_method)
+ call this%fates_fire_method%FireInit(bounds)
+ this%initialized = .true.
+
+ end subroutine FireFactInit
+
+ !-----------------------------------------------------------------------
+
+ subroutine turn_fire_emis_on(this)
+ use shr_fire_emis_mod, only : shr_fire_emis_readnl, shr_fire_emis_mechcomps_n
+ use shr_sys_mod, only : shr_sys_system
+ class(TestFATESFireFactory), intent(inout) :: this
+
+ ! NOTE!: This is bad that this can be done directly without having it done through a namelist, or setter!
+ shr_fire_emis_mechcomps_n = 2
+ end subroutine turn_fire_emis_on
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine fates_spitfire_mode_bad_fails(this)
+ class(TestFATESFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ fates_spitfire_mode = -1
+ call this%FireFactInit( )
+ expected_msg = "ABORTED: Unknown option for namelist item fates_spitfire_mode:"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine fates_spitfire_mode_bad_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine fates_sp_case_with_fire_emis_fails(this)
+ use clm_varctl, only : use_fates_sp
+ class(TestFATESFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ use_fates_sp = .true.
+ call this%turn_fire_emis_on()
+ call this%FireFactInit( )
+ expected_msg = "ABORTED: Fire emission with FATES requires FATES to NOT be in Satellite Phenology (SP) mode"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine fates_sp_case_with_fire_emis_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine fates_st3_case_with_fire_emis_fails(this)
+ use clm_varctl, only : use_fates_ed_st3
+ class(TestFATESFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ use_fates_ed_st3 = .true.
+ call this%turn_fire_emis_on()
+ call this%FireFactInit( )
+ expected_msg = "ABORTED: Fire emission with FATES requires FATES to NOT be in Static Stand Structure mode"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine fates_st3_case_with_fire_emis_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine fates_no_spitfire_case_with_fire_emis_fails(this)
+ class(TestFATESFireFactory), intent(inout) :: this
+ character(100) :: expected_msg
+
+ call this%turn_fire_emis_on()
+ fates_spitfire_mode = no_fire
+ call this%FireFactInit( )
+ expected_msg = "ABORTED: Having fire emissions on requires fates_spitfire_mode to be something besides no_fire (0)"
+ @assertExceptionRaised(expected_msg)
+
+ end subroutine fates_no_spitfire_case_with_fire_emis_fails
+
+ !-----------------------------------------------------------------------
+
+ @Test
+ subroutine all_fates_spitfire_options_with_fire_emis_fails(this)
+ class(TestFATESFireFactory), intent(inout) :: this
+ integer, parameter :: noptions = anthro_suppression
+ integer :: i
+ character(100) :: expected_msg
+
+ do i = scalar_lightning, noptions
+ call this%setUp()
+ call this%turn_fire_emis_on()
+ fates_spitfire_mode = i
+ use_fates_sp = .false.
+ call this%FireFactInit( )
+ expected_msg = "ABORTED: Fire emission with FATES can NOT currently be turned on (see issue #1045)"
+ @assertExceptionRaised(expected_msg)
+ call this%tearDown()
+ end do
+
+ end subroutine all_fates_spitfire_options_with_fire_emis_fails
+
+ !-----------------------------------------------------------------------
+
+end module test_FATESFireFactory
diff --git a/src/cpl/share_esmf/FireDataBaseType.F90 b/src/cpl/share_esmf/FireDataBaseType.F90
index b84e3bfa33..13323cd924 100644
--- a/src/cpl/share_esmf/FireDataBaseType.F90
+++ b/src/cpl/share_esmf/FireDataBaseType.F90
@@ -26,23 +26,25 @@ module FireDataBaseType
type, abstract, extends(fire_method_type) :: fire_base_type
private
! !PRIVATE MEMBER DATA:
- real(r8), public, pointer :: forc_hdm(:) ! Human population density
- type(shr_strdata_type) :: sdat_hdm ! Human population density input data stream
- real(r8), public, pointer :: forc_lnfm(:) ! Lightning frequency
- type(shr_strdata_type) :: sdat_lnfm ! Lightning frequency input data stream
+ real(r8), public, pointer :: forc_hdm(:) => NULL() ! Human population density
+ type(shr_strdata_type) :: sdat_hdm ! Human population density input data stream
+ real(r8), public, pointer :: forc_lnfm(:) => NULL() ! Lightning frequency
+ type(shr_strdata_type) :: sdat_lnfm ! Lightning frequency input data stream
- real(r8), public, pointer :: gdp_lf_col(:) ! col global real gdp data (k US$/capita)
- real(r8), public, pointer :: peatf_lf_col(:) ! col global peatland fraction data (0-1)
- integer , public, pointer :: abm_lf_col(:) ! col global peak month of crop fire emissions
+ real(r8), public, pointer :: gdp_lf_col(:) => NULL() ! col global real gdp data (k US$/capita)
+ real(r8), public, pointer :: peatf_lf_col(:) => NULL() ! col global peatland fraction data (0-1)
+ integer , public, pointer :: abm_lf_col(:) => NULL() ! col global peak month of crop fire emissions
contains
!
! !PUBLIC MEMBER FUNCTIONS:
- procedure, public :: FireInit => BaseFireInit ! Initialization of Fire
procedure, public :: BaseFireInit ! Initialization of Fire
+ procedure, public :: FireInit => BaseFireInit ! Initialization of Fire
+ procedure, public :: BaseFireClean ! Clean up data and deallocate data
+ procedure, public :: FireClean => BaseFireClean ! Clean up data and deallocate data
procedure, public :: FireInterp ! Interpolate fire data
- procedure(FireReadNML_interface), public, deferred :: &
- FireReadNML ! Read in namelist for Fire
+ procedure, public :: BaseFireReadNML ! Read in the namelist for fire
+ procedure, public :: ReadFireNML => BaseFireReadNML ! Read in the namelist for fire
procedure(need_lightning_and_popdens_interface), public, deferred :: &
need_lightning_and_popdens ! Returns true if need lightning & popdens
!
@@ -78,7 +80,7 @@ end function need_lightning_and_popdens_interface
contains
!==============================================================================
- subroutine FireReadNML_interface( this, NLFilename )
+ subroutine BaseFireReadNML( this, bounds, NLFilename )
!
! !DESCRIPTION:
! Read the namelist for Fire
@@ -87,11 +89,21 @@ subroutine FireReadNML_interface( this, NLFilename )
!
! !ARGUMENTS:
class(fire_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
character(len=*), intent(in) :: NLFilename ! Namelist filename
- end subroutine FireReadNML_interface
+
+ ! Read the namelists for the fire data and do the preparation needed on them
+ if ( this%need_lightning_and_popdens() ) then
+ call this%hdm_init(bounds, NLFilename)
+ call this%hdm_interp(bounds)
+ call this%lnfm_init(bounds, NLFilename)
+ call this%lnfm_interp(bounds)
+ call this%surfdataread(bounds)
+ end if
+ end subroutine BaseFireReadNML
!================================================================
- subroutine BaseFireInit( this, bounds, NLFilename )
+ subroutine BaseFireInit( this, bounds )
!
! !DESCRIPTION:
! Initialize CN Fire module
@@ -101,9 +113,7 @@ subroutine BaseFireInit( this, bounds, NLFilename )
! !ARGUMENTS:
class(fire_base_type) :: this
type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename
!-----------------------------------------------------------------------
-
if ( this%need_lightning_and_popdens() ) then
! Allocate lightning forcing data
allocate( this%forc_lnfm(bounds%begg:bounds%endg) )
@@ -118,16 +128,36 @@ subroutine BaseFireInit( this, bounds, NLFilename )
allocate(this%peatf_lf_col(bounds%begc:bounds%endc))
! Allocates peak month of crop fire emissions
allocate(this%abm_lf_col(bounds%begc:bounds%endc))
-
- call this%hdm_init(bounds, NLFilename)
- call this%hdm_interp(bounds)
- call this%lnfm_init(bounds, NLFilename)
- call this%lnfm_interp(bounds)
- call this%surfdataread(bounds)
end if
end subroutine BaseFireInit
+ !================================================================
+ subroutine BaseFireClean( this )
+ !
+ ! !DESCRIPTION:
+ ! Clean fire data
+ ! !USES:
+ !
+ ! !ARGUMENTS:
+ class(fire_base_type) :: this
+ !-----------------------------------------------------------------------
+
+ if ( this%need_lightning_and_popdens() ) then
+ deallocate( this%forc_lnfm )
+ deallocate( this%forc_hdm )
+ deallocate( this%gdp_lf_col )
+ deallocate( this%peatf_lf_col )
+ deallocate( this%abm_lf_col )
+ this%forc_lnfm => NULL()
+ this%forc_hdm => NULL()
+ this%gdp_lf_col => NULL()
+ this%peatf_lf_col => NULL()
+ this%abm_lf_col => NULL()
+ end if
+
+ end subroutine BaseFireClean
+
!================================================================
subroutine FireInterp(this,bounds)
!
diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt
index 53a6edb8a5..fc324efeb9 100644
--- a/src/main/CMakeLists.txt
+++ b/src/main/CMakeLists.txt
@@ -20,6 +20,7 @@ list(APPEND clm_sources
column_varcon.F90
decompMod.F90
filterColMod.F90
+ FireMethodType.F90
glc2lndMod.F90
glcBehaviorMod.F90
initSubgridMod.F90
diff --git a/src/main/FireMethodType.F90 b/src/main/FireMethodType.F90
index 978450e65f..5f90dea893 100644
--- a/src/main/FireMethodType.F90
+++ b/src/main/FireMethodType.F90
@@ -34,6 +34,9 @@ module FireMethodType
! Figure out the fire fluxes
procedure(CNFireFluxes_interface) , public, deferred :: CNFireFluxes
+ ! Deallocate the fire datasets
+ procedure(FireClean_interface) , public, deferred :: FireClean
+
end type fire_method_type
abstract interface
@@ -52,7 +55,7 @@ module FireMethodType
! consistent between different implementations.
!
!---------------------------------------------------------------------------
- subroutine FireInit_interface(this, bounds, NLFilename )
+ subroutine FireInit_interface(this, bounds )
!
! !DESCRIPTION:
! Initialize Fire datasets
@@ -63,20 +66,21 @@ subroutine FireInit_interface(this, bounds, NLFilename )
! !ARGUMENTS:
class(fire_method_type) :: this
type(bounds_type), intent(in) :: bounds
- character(len=*), intent(in) :: NLFilename
!-----------------------------------------------------------------------
end subroutine FireInit_interface
- subroutine FireReadNML_interface(this, NLFilename )
+ subroutine FireReadNML_interface(this, bounds, NLFilename )
!
! !DESCRIPTION:
! Read general fire namelist
!
! USES
+ use decompMod , only : bounds_type
import :: fire_method_type
! !ARGUMENTS:
class(fire_method_type) :: this
+ type(bounds_type), intent(in) :: bounds
character(len=*), intent(in) :: NLFilename
!-----------------------------------------------------------------------
@@ -97,6 +101,20 @@ subroutine FireInterp_interface(this, bounds)
end subroutine FireInterp_interface
+ !-----------------------------------------------------------------------
+ subroutine FireClean_interface(this)
+ !
+ ! !DESCRIPTION:
+ ! Deallocate Fire datasets
+ !
+ ! USES
+ import :: fire_method_type
+ ! !ARGUMENTS:
+ class(fire_method_type) :: this
+ !-----------------------------------------------------------------------
+
+ end subroutine FireClean_interface
+
!-----------------------------------------------------------------------
subroutine CNFireReadParams_interface( this, ncid )
!
diff --git a/src/soilbiogeochem/CMakeLists.txt b/src/soilbiogeochem/CMakeLists.txt
index e2baa2d1b2..ac467c3e5f 100644
--- a/src/soilbiogeochem/CMakeLists.txt
+++ b/src/soilbiogeochem/CMakeLists.txt
@@ -2,6 +2,7 @@
# source files that are currently used in unit tests
list(APPEND clm_sources
+ SoilBiogeochemCarbonFluxType.F90
SoilBiogeochemStateType.F90
SoilBiogeochemDecompCascadeConType.F90
SoilBiogeochemStateType.F90
diff --git a/src/unit_test_stubs/main/ncdio_pio_fake.F90.in b/src/unit_test_stubs/main/ncdio_pio_fake.F90.in
index e8ef14e457..7f38565e90 100644
--- a/src/unit_test_stubs/main/ncdio_pio_fake.F90.in
+++ b/src/unit_test_stubs/main/ncdio_pio_fake.F90.in
@@ -48,6 +48,7 @@ module ncdio_pio
public :: check_var ! determine if variable is on netcdf file
public :: check_dim ! determine if dimension is on netcdf file
public :: check_var_or_dim ! determine if variable or dimension is on netcdf file
+ public :: check_dim_size ! validity check on dimension
public :: ncd_io ! do fake i/o (currently only set up to read)
public :: ncd_inqvid ! inquire on a variable id
public :: ncd_set_var ! set data on "file" for one variable
@@ -340,6 +341,25 @@ contains
end subroutine check_var_or_dim
+ !-----------------------------------------------------------------------
+ subroutine check_dim_size(ncid, dimname, value, msg)
+ !
+ ! !DESCRIPTION:
+ ! Validity check on dimension
+ !
+ ! !ARGUMENTS:
+ class(file_desc_t),intent(in) :: ncid ! PIO file handle
+ character(len=*) , intent(in) :: dimname ! Dimension name
+ integer, intent(in) :: value ! Expected dimension size
+
+ character(len=*), intent(in), optional :: msg ! Optional additional message printed upon error
+ !
+ ! !LOCAL VARIABLES:
+ !-----------------------------------------------------------------------
+
+ ! Does nothing assumes the dim size is as expected
+
+ end subroutine check_dim_size
!-----------------------------------------------------------------------
subroutine ncd_inqdid(ncid, name, dimid, dimexist)
diff --git a/src/unit_test_stubs/share_esmf/CMakeLists.txt b/src/unit_test_stubs/share_esmf/CMakeLists.txt
index 1d767543ea..368601dcc8 100644
--- a/src/unit_test_stubs/share_esmf/CMakeLists.txt
+++ b/src/unit_test_stubs/share_esmf/CMakeLists.txt
@@ -1,5 +1,7 @@
list(APPEND clm_sources
ExcessIceStreamType.F90
+ FireDataBaseType.F90
+ laiStreamMod.F90
PrigentRoughnessStreamType.F90
ZenderSoilErodStreamType.F90
)
diff --git a/src/unit_test_stubs/share_esmf/FireDataBaseType.F90 b/src/unit_test_stubs/share_esmf/FireDataBaseType.F90
new file mode 100644
index 0000000000..63046188a3
--- /dev/null
+++ b/src/unit_test_stubs/share_esmf/FireDataBaseType.F90
@@ -0,0 +1,123 @@
+module FireDataBaseType
+
+#include "shr_assert.h"
+
+ !-----------------------------------------------------------------------
+ ! !DESCRIPTION:
+ ! module for handling of fire data
+ ! UNIT-TEST STUB for fire data Streams
+ ! This just allows the fire code to be tested without
+ ! reading in the streams data, by faking it and setting it to a
+ ! constant value.
+ !
+ ! !USES:
+ use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL
+ use shr_log_mod , only : errMsg => shr_log_errMsg
+ use clm_varctl , only : iulog
+ use spmdMod , only : masterproc, mpicom, iam
+ use abortutils , only : endrun
+ use decompMod , only : bounds_type
+ use FireMethodType , only : fire_method_type
+ !
+ implicit none
+ private
+ !
+ ! !PUBLIC TYPES:
+ public :: fire_base_type
+ !
+ type, abstract, extends(fire_method_type) :: fire_base_type
+ private
+ ! !PRIVATE MEMBER DATA:
+ real(r8), public, pointer :: forc_hdm(:) ! Human population density
+ real(r8), public, pointer :: forc_lnfm(:) ! Lightning frequency
+ real(r8), public, pointer :: gdp_lf_col(:) ! col global real gdp data (k US$/capita)
+ real(r8), public, pointer :: peatf_lf_col(:) ! col global peatland fraction data (0-1)
+ integer , public, pointer :: abm_lf_col(:) ! col global peak month of crop fire emissions
+
+ contains
+ !
+ ! !PUBLIC MEMBER FUNCTIONS:
+ procedure, public :: BaseFireInit ! Initialization of Fire
+ procedure, public :: FireInit => BaseFireInit ! Initialization of Fire
+ procedure, public :: FireInterp ! Interpolate fire data
+ procedure, public :: BaseFireReadNML ! Read in the namelist
+ procedure, public :: FireReadNML => BaseFireReadNML ! Read in the namelist
+ procedure(need_lightning_and_popdens_interface), public, deferred :: &
+ need_lightning_and_popdens ! Returns true if need lightning & popdens
+
+ end type fire_base_type
+
+ abstract interface
+ !-----------------------------------------------------------------------
+ function need_lightning_and_popdens_interface(this) result(need_lightning_and_popdens)
+ !
+ ! !DESCRIPTION:
+ ! Returns true if need lightning and popdens, false otherwise
+ !
+ ! USES
+ import :: fire_base_type
+ !
+ ! !ARGUMENTS:
+ class(fire_base_type), intent(in) :: this
+ logical :: need_lightning_and_popdens ! function result
+ !-----------------------------------------------------------------------
+ end function need_lightning_and_popdens_interface
+ end interface
+
+ character(len=*), parameter, private :: sourcefile = &
+ __FILE__
+
+!==============================================================================
+contains
+!==============================================================================
+
+ subroutine BaseFireReadNML( this, bounds, NLFilename )
+ !
+ ! !DESCRIPTION:
+ ! Read the namelist for Fire
+ !
+ ! !USES:
+ !
+ ! !ARGUMENTS:
+ class(fire_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ character(len=*), intent(in) :: NLFilename ! Namelist filename
+ end subroutine BaseFireReadNML
+
+ !================================================================
+ subroutine BaseFireInit( this, bounds )
+ !
+ ! !DESCRIPTION:
+ ! Initialize CN Fire module
+ ! !USES:
+ use shr_infnan_mod , only : nan => shr_infnan_nan, assignment(=)
+ !
+ ! !ARGUMENTS:
+ class(fire_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ !-----------------------------------------------------------------------
+
+ if ( this%need_lightning_and_popdens() ) then
+
+ end if
+
+ end subroutine BaseFireInit
+
+ !================================================================
+ subroutine FireInterp(this,bounds)
+ !
+ ! !DESCRIPTION:
+ ! Interpolate CN Fire datasets
+ !
+ ! !ARGUMENTS:
+ class(fire_base_type) :: this
+ type(bounds_type), intent(in) :: bounds
+ !-----------------------------------------------------------------------
+
+ if ( this%need_lightning_and_popdens() ) then
+
+ end if
+
+ end subroutine FireInterp
+
+end module FireDataBaseType
diff --git a/src/unit_test_stubs/share_esmf/laiStreamMod.F90 b/src/unit_test_stubs/share_esmf/laiStreamMod.F90
new file mode 100644
index 0000000000..a39a3eb053
--- /dev/null
+++ b/src/unit_test_stubs/share_esmf/laiStreamMod.F90
@@ -0,0 +1,74 @@
+module laiStreamMod
+
+ !-----------------------------------------------------------------------
+ ! !DESCRIPTION:
+ ! Read LAI from stream
+ !
+ ! !USES:
+ use decompMod , only : bounds_type
+ use abortutils , only : endrun
+ use clm_varctl , only : iulog
+ !
+ ! !PUBLIC TYPES:
+ implicit none
+ private
+
+ ! !PUBLIC MEMBER FUNCTIONS:
+ public :: lai_init ! position datasets for LAI
+ public :: lai_advance ! Advance the LAI streams (outside of a Open-MP threading loop)
+ public :: lai_interp ! interpolates between two years of LAI data (when LAI streams
+
+ character(len=*), parameter :: sourcefile = &
+ __FILE__
+
+!==============================================================================
+contains
+!==============================================================================
+
+ subroutine lai_init(bounds)
+ !
+ ! Initialize data stream information for LAI.
+ !
+ ! !USES:
+ !
+ ! !ARGUMENTS:
+ type(bounds_type), intent(in) :: bounds ! bounds
+ !
+ ! !LOCAL VARIABLES:
+ !-----------------------------------------------------------------------
+
+ end subroutine lai_init
+
+ !================================================================
+ subroutine lai_advance( bounds )
+ !
+ ! Advance LAI streams
+ !
+ ! !USES:
+ !
+ ! !ARGUMENTS:
+ type(bounds_type), intent(in) :: bounds
+ !
+ ! !LOCAL VARIABLES:
+ !-----------------------------------------------------------------------
+
+ end subroutine lai_advance
+
+ !================================================================
+ subroutine lai_interp(bounds, canopystate_inst)
+ !
+ ! Interpolate data stream information for Lai.
+ !
+ ! !USES:
+ use CanopyStateType , only : canopystate_type
+ !
+ ! !ARGUMENTS:
+ type(bounds_type) , intent(in) :: bounds
+ type(canopystate_type) , intent(inout) :: canopystate_inst
+ !
+ ! !LOCAL VARIABLES:
+ !-----------------------------------------------------------------------
+
+ end subroutine lai_interp
+
+end module LaiStreamMod
diff --git a/src/utils/clmfates_interfaceMod.F90 b/src/utils/clmfates_interfaceMod.F90
index 2effb561dd..289244ae89 100644
--- a/src/utils/clmfates_interfaceMod.F90
+++ b/src/utils/clmfates_interfaceMod.F90
@@ -3231,7 +3231,8 @@ subroutine Init2(this, bounds, NLFilename)
call t_startf('fates_init2')
- call this%fates_fire_data_method%FireInit(bounds, NLFilename)
+ call this%fates_fire_data_method%FireInit(bounds)
+ call this%fates_fire_data_method%FireReadNML(bounds, NLFilename)
call t_stopf('fates_init2')