diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 54752b6dbc..bbe83a3dc5 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4172,60 +4172,115 @@ sub setup_logic_lai_streams { sub setup_logic_cropcal_streams { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; - # Set first and last stream years - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal', - 'sim_year'=>$nl_flags->{'sim_year'}, - 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal', - 'sim_year'=>$nl_flags->{'sim_year'}, - 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - - # Set align year, if first and last years are different - if ( $nl->get_value('stream_year_first_cropcal') != - $nl->get_value('stream_year_last_cropcal') ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, - 'model_year_align_cropcal', 'sim_year'=>$nl_flags->{'sim_year'}, - 'sim_year_range'=>$nl_flags->{'sim_year_range'}); - } - # Set up other crop calendar parameters + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'cropcals_rx'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'cropcals_rx_adapt'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'generate_crop_gdds'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_mxmat'); - # Option checks - my $generate_crop_gdds = $nl->get_value('generate_crop_gdds') ; - my $use_mxmat = $nl->get_value('use_mxmat') ; + # These can't both be true + my $cropcals_rx = $nl->get_value('cropcals_rx') ; + my $cropcals_rx_adapt = $nl->get_value('cropcals_rx_adapt') ; + if (&value_is_true($cropcals_rx) and &value_is_true($cropcals_rx_adapt)) { + $log->fatal_error("cropcals_rx and cropcals_rx_adapt may not both be true" ); + } + + # Add defaults if using prescribed crop calendars + if ( &value_is_true($cropcals_rx) or &value_is_true($cropcals_rx_adapt) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_start'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_swindow_end'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_cultivar_gdds'); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_cropcal'); + if ( &value_is_true($cropcals_rx_adapt) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldFileName_gdd20_baseline'); + } + } + + # Add defaults if using any crop calendar input files my $swindow_start_file = $nl->get_value('stream_fldFileName_swindow_start') ; my $swindow_end_file = $nl->get_value('stream_fldFileName_swindow_end') ; my $gdd_file = $nl->get_value('stream_fldFileName_cultivar_gdds') ; my $gdd20_baseline_file = $nl->get_value('stream_fldFileName_gdd20_baseline') ; my $mesh_file = $nl->get_value('stream_meshfile_cropcal') ; - if ( ($swindow_start_file eq '' and $swindow_start_file ne '') or ($swindow_start_file ne '' and $swindow_start_file eq '') ) { - $log->fatal_error("When specifying sowing window dates, you must provide both swindow_start_file and swindow_end_file. To specify exact sowing dates, use the same file." ); + if ( !&string_is_undef_or_empty($swindow_start_file) or !&string_is_undef_or_empty($swindow_end_file) or !&string_is_undef_or_empty($gdd_file) or !&string_is_undef_or_empty($gdd20_baseline_file) or !&string_is_undef_or_empty($mesh_file)) { + + # User gave an input file without specifying cropcals_rx or cropcals_rx_adapt = .true. + # Requiring this means nothing to the code, but helps namelist make more sense + if ( !&value_is_true($cropcals_rx) and !&value_is_true($cropcals_rx_adapt) ){ + $log->fatal_error("If providing any crop calendar input file(s), cropcals_rx or cropcals_rx_adapt must be true" ); + } + + # User set cropcals_rx_adapt to true but set stream_fldFileName_gdd20_baseline to empty + if ( &value_is_true($cropcals_rx_adapt) and &string_is_undef_or_empty($gdd20_baseline_file) ) { + $log->fatal_error("If cropcals_rx_adapt is true, stream_fldFileName_gdd20_baseline must be provided" ); + } + + # cropcals_rx_adapt is false but user provided stream_fldFileName_gdd20_baseline + if ( !&value_is_true($cropcals_rx_adapt) and !&string_is_undef_or_empty($gdd20_baseline_file) ) { + $log->fatal_error("If stream_fldFileName_gdd20_baseline provided, cropcals_rx_adapt must be true" ); + } + + # User provided an input file but set mesh file to empty + if ( &string_is_undef_or_empty($mesh_file) ) { + $log->fatal_error("If providing any crop calendar input file(s), you must provide stream_meshfile_cropcal" ); + } + + # Set stream years + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_last_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'model_year_align_cropcal', + 'sim_year'=>$nl_flags->{'sim_year'}, + 'sim_year_range'=>$nl_flags->{'sim_year_range'}); + + # Check/set things if first and last years are different + if ( $nl->get_value('stream_year_first_cropcal') != + $nl->get_value('stream_year_last_cropcal') ) { + + # Do not allow maturity requirements to change over time if stream_fldFileName_gdd20_baseline is provided. That would be nonsensical. + # Note that this restricts sowing windows from changing over time as well, because there are not separate stream_year settings for that. + if ( !&string_is_undef_or_empty($gdd20_baseline_file) ) { + $log->fatal_error("If cropcals_rx_adapt is true (i.e., stream_fldFileName_gdd20_baseline is provided), no crop calendar input is allowed to vary over time (i.e., stream_year_first_cropcal and stream_year_last_cropcal must be the same)." ); + } + } } - if ( $gdd_file eq '' and $gdd20_baseline_file ne '' ) { + + # If running with prescribed crop calendars, certain files must be provided + my $generate_crop_gdds = $nl->get_value('generate_crop_gdds') ; + if ( &value_is_true($cropcals_rx) or &value_is_true($cropcals_rx_adapt) ) { + if ( &string_is_undef_or_empty($swindow_start_file) or &string_is_undef_or_empty($swindow_end_file) ) { + $log->fatal_error("If cropcals_rx or cropcals_rx_adapt is true, sowing window start and end files must be provided. To specify exact sowing dates, use the same file." ); + } + if ( &string_is_undef_or_empty($gdd_file) and (! &value_is_true($generate_crop_gdds)) ){ + $log->fatal_error("If cropcals_rx or cropcals_rx_adapt is true and generate_crop_gdds is false, maturity requirement file stream_fldFileName_cultivar_gdds must be provided" ); + } + } + + # Option checks + if ( &string_is_undef_or_empty($gdd_file) and ! &string_is_undef_or_empty($gdd20_baseline_file) ) { $log->fatal_error("If not providing stream_fldFileName_cultivar_gdds, don't provide stream_fldFileName_gdd20_baseline"); } - if ( $generate_crop_gdds eq '.true.' ) { - if ( $use_mxmat eq '.true.' ) { + if ( &value_is_true($generate_crop_gdds) ) { + my $use_mxmat = $nl->get_value('use_mxmat') ; + if ( &value_is_true($use_mxmat) ) { $log->fatal_error("If generate_crop_gdds is true, you must also set use_mxmat to false" ); } - if ( $swindow_start_file eq '' or $swindow_end_file eq '' ) { + if ( &string_is_undef_or_empty($swindow_start_file) or &string_is_undef_or_empty($swindow_end_file) ) { $log->fatal_error("If generate_crop_gdds is true, you must specify stream_fldFileName_swindow_start and stream_fldFileName_swindow_end") } if ( $swindow_start_file ne $swindow_end_file ) { $log->fatal_error("If generate_crop_gdds is true, you must specify exact sowing dates by setting stream_fldFileName_swindow_start and stream_fldFileName_swindow_end to the same file") } - if ( $gdd_file ne '' ) { + if ( ! &string_is_undef_or_empty($gdd_file) ) { $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_cultivar_gdds") } - if ( $gdd20_baseline_file ne '' ) { + if ( ! &string_is_undef_or_empty($gdd20_baseline_file) ) { $log->fatal_error("If generate_crop_gdds is true, do not specify stream_fldFileName_gdd20_baseline") } } - if ( $mesh_file eq '' and ( $swindow_start_file ne '' or $gdd_file ne '' ) ) { - $log->fatal_error("If prescribing crop sowing dates and/or maturity requirements, you must specify stream_meshfile_cropcal") - } } #------------------------------------------------------------------------------- diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 655e97c47c..85f37a22fd 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1686,10 +1686,23 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c nn nn - -1850 -2100 -1850 + +.false. +.false. +2000 +2000 +2000 + + +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc +share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc +lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc +lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc +lnd/clm2/testdata/gdd20baseline.tmp_dontupload.nc +share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index c88e987756..f37ada6847 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1773,14 +1773,24 @@ Mapping method from LAI input file to the model resolution + +Flag to enable prescribed crop calendars (sowing window dates and maturity requirement) + + + +Flag to enable prescribed crop calendars (sowing window dates and maturity requirement), with maturity requirement adaptive based on recent climate + + -First year to loop over for crop calendar data +First year to loop over for crop calendar data (not including gdd20_baseline file) -Last year to loop over for crop calendar data +Last year to loop over for crop calendar data (not including gdd20_baseline file) + + + + + + + + + + + + + + + + + + diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm index 9cbfea97f0..8a0b4a91be 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCals/user_nl_clm @@ -1,8 +1,2 @@ -! Sowing windows -stream_fldFileName_swindow_start = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_starts_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' -stream_fldFileName_swindow_end = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/swindow_ends_ggcmi_crop_calendar_phase3_v1.01.2000-2000.20231005_145103.nc' -stream_fldFileName_cultivar_gdds = '$DIN_LOC_ROOT/lnd/clm2/cropdata/calendars/processed/gdds_20230829_161011.nc' -stream_year_first_cropcal = 2000 -stream_year_last_cropcal = 2000 -stream_meshfile_cropcal = '$DIN_LOC_ROOT/share/meshes/360x720_120830_ESMFmesh_c20210507_cdf5.nc' +cropcals_rx = .true. diff --git a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm index 1bba9d2a89..709c7221e0 100644 --- a/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm +++ b/cime_config/testdefs/testmods_dirs/clm/RxCropCalsAdapt/user_nl_clm @@ -1,3 +1,3 @@ -! Eventually replace this with half-degree version in the proper place -stream_fldFileName_gdd20_baseline = '/glade/u/home/samrabin/ctsm_scale-mat-reqs/tools/crop_calendars/test.nc' +cropcals_rx = .false. +cropcals_rx_adapt = .true. diff --git a/src/cpl/share_esmf/cropcalStreamMod.F90 b/src/cpl/share_esmf/cropcalStreamMod.F90 index f60ab51000..3333b6cfdc 100644 --- a/src/cpl/share_esmf/cropcalStreamMod.F90 +++ b/src/cpl/share_esmf/cropcalStreamMod.F90 @@ -47,6 +47,8 @@ module cropcalStreamMod character(len=CL) :: stream_fldFileName_swindow_end ! sowing window end stream filename to read character(len=CL) :: stream_fldFileName_cultivar_gdds ! cultivar growing degree-days stream filename to read character(len=CL) :: stream_fldFileName_gdd20_baseline ! GDD20 baseline stream filename to read + logical :: cropcals_rx ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash + logical :: cropcals_rx_adapt ! Used only for setting input files in namelist; does nothing in code, but needs to be here so namelist read doesn't crash character(len=*), parameter :: sourcefile = & __FILE__ @@ -95,7 +97,9 @@ subroutine cropcal_init(bounds) stream_fldFileName_swindow_end, & stream_fldFileName_cultivar_gdds, & stream_fldFileName_gdd20_baseline, & - stream_meshfile_cropcal + stream_meshfile_cropcal, & + cropcals_rx, & + cropcals_rx_adapt ! Default values for namelist stream_year_first_cropcal = 1 ! first year in stream to use