From f00dcc10637c9d6dd5caf369853d8c39fa134234 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Thu, 1 Sep 2022 14:29:48 -0600 Subject: [PATCH 01/39] add new diurnal ozone mod --- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 136 +++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/cpl/share_esmf/diurnalOzoneStreamMod.F90 diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 new file mode 100644 index 0000000000..150e1dfe3a --- /dev/null +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -0,0 +1,136 @@ +module diurnalOzoneStreamMod + +#include "shr_assert.h" + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Read in file to convert input ozone to sub-daily values from stream + ! + ! !USES: + use ESMF + use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL, CS => shr_kind_CS + use dshr_strdata_mod , only : shr_strdata_type + use decompMod , only : bounds_type + use abortutils , only : endrun + use clm_varctl , only : iulog + use perf_mod , only : t_startf, t_stopf + use spmdMod , only : masterproc, mpicom, iam + ! + ! !PUBLIC TYPES: + implicit none + private + + ! !PUBLIC MEMBER FUNCTIONS: + public :: dO3_init ! position dataset for diurnal ozone anomaly + + ! !PRIVATE MEMBER DATA: + integer, allocatable :: g_to_ig(:) ! Array matching gridcell index to data index + type(shr_strdata_type) :: sdat_dO3 ! diurnal ozone anomaly input data stream + character(*), parameter :: dO3String = "dO3_" ! base string for field string + integer , parameter :: numdO3Fields = 16 ! number of fields to build field string + character(len=CS) :: stream_varnames(numdO3Fields) + + character(len=*), parameter :: sourcefile = & + __FILE__ + +!============================================================================== +contains +!============================================================================== + + subroutine dO3_init(bounds) + ! + ! Initialize data stream information for LAI. + ! + ! !USES: + use shr_mpi_mod , only : shr_mpi_bcast + use clm_nlUtilsMod , only : find_nlgroup_name + use lnd_comp_shr , only : mesh, model_clock + use dshr_strdata_mod , only : shr_strdata_init_from_inline + use controlMod , only : NLFilename + ! + ! !ARGUMENTS: + type(bounds_type), intent(in) :: bounds ! bounds + ! + ! !LOCAL VARIABLES: + integer :: i,n ! index + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + character(len=CL) :: stream_fldFileName_dO3 ! diurnal ozone stream filename to read + character(len=CL) :: stream_meshfile_dO3 ! diurnal ozone stream meshfile + character(len=CL) :: dO3_mapalgo = 'bilinear' ! Mapping alogrithm + integer :: rc + character(*), parameter :: subName = "('dO3dyn_init')" + !----------------------------------------------------------------------- + ! + ! deal with namelist variables here in init + ! + namelist /dO3_streams/ & + dO3_mapalgo, & + stream_fldFileName_dO3, & + stream_meshfile_dO3 + + ! Default values for namelist + stream_fldFileName_dO3 = '' + stream_meshfile_dO3 = '' + do n = 1,numdO3Fields + write(stream_varnames(n),'(a,i0)') dO3String,n + end do + + ! Read lai_streams namelist + if (masterproc) then + open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call find_nlgroup_name(nu_nml, 'dO3_streams', status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=dO3_streams,iostat=nml_error) + if (nml_error /= 0) then + call endrun(subname // ':: ERROR reading dO3_streams namelist') + end if + else + call endrun(subname // ':: ERROR finding dO3_streams namelist') + end if + close(nu_nml) + endif + call shr_mpi_bcast(stream_fldFileName_dO3 , mpicom) + call shr_mpi_bcast(stream_meshfile_dO3 , mpicom) + call shr_mpi_bcast(dO3_tintalgo , mpicom) + + if (masterproc) then + write(iulog,*) + write(iulog,'(a)') 'dO3_stream settings:' + write(iulog,'(a,a)' ) ' stream_fldFileName_dO3 = ',trim(stream_fldFileName_dO3) + write(iulog,'(a,a)' ) ' stream_meshfile_dO3 = ',trim(stream_meshfile_dO3) + do n = 1,numdO3Fields + write(iulog,'(a,a)' ) ' stream_varname = ',trim(stream_varnames(n)) + end do + write(iulog,*) + endif + + ! Initialize the cdeps data type sdat_lai + call shr_strdata_init_from_inline(sdat_dO3, & + my_task = iam, & + logunit = iulog, & + compname = 'LND', & + model_clock = model_clock, & + model_mesh = mesh, & + stream_meshfile = trim(stream_meshfile_dO3), & + stream_lev_dimname = 'null', & + stream_mapalgo = trim(dO3_mapalgo), & + stream_filenames = (/trim(stream_fldfilename_dO3)/), & + stream_fldlistFile = stream_varnames, & + stream_fldListModel = stream_varnames, & + stream_yearFirst = 'null', & + stream_yearLast = 'null', & + stream_yearAlign = 'null', & + stream_offset = 'null', & + stream_taxmode = 'null', & + stream_dtlimit = 'null', & + stream_tintalgo = 'null', & + stream_name = 'dO3 data', & + rc = rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + end subroutine dO3_init + +end module diurnalOzoneStreamMod From fb2ba210c2ba148b3b7b8d0c37aaa821cdc8fa9c Mon Sep 17 00:00:00 2001 From: adrifoster Date: Fri, 2 Sep 2022 11:07:25 -0600 Subject: [PATCH 02/39] add do3 streams namelist info --- bld/CLMBuildNamelist.pm | 31 ++- bld/namelist_files/namelist_defaults_ctsm.xml | 14 +- .../namelist_definition_ctsm.xml | 190 ++++++++++-------- src/cpl/nuopc/lnd_import_export.F90 | 7 +- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 2 +- 5 files changed, 156 insertions(+), 88 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index cbd5e3ce44..05fe82b86f 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1662,6 +1662,11 @@ sub process_namelist_inline_logic { ################################## setup_logic_lai_streams($opts, $nl_flags, $definition, $defaults, $nl); + ################################## + # namelist group: dO3_streams # + ################################## + setup_logic_dO3_streams($opts, $nl_flags, $definition, $defaults, $nl); + ########################################## # namelist group: soil_moisture_streams # ########################################## @@ -2726,8 +2731,8 @@ sub setup_logic_do_transient_urban { # for them to be unset if that will be their final state): # - flanduse_timeseries # - # NOTE(kwo, 2021-08-11) I based this function on setup_logic_do_transient_lakes. - # As in NOTE(wjs, 2020-08-23) I'm not sure if all of the checks here are truly important + # NOTE(kwo, 2021-08-11) I based this function on setup_logic_do_transient_lakes. + # As in NOTE(wjs, 2020-08-23) I'm not sure if all of the checks here are truly important # for transient urban (in particular, my guess is that collapse_urban could probably be done with transient # urban - as well as transient pfts and transient crops for that matter), but some of # the checks probably are needed, and it seems best to keep transient urban consistent @@ -3826,6 +3831,28 @@ sub setup_logic_lai_streams { #------------------------------------------------------------------------------- +sub setup_logic_dO3_streams { + # input file for creating diurnal ozone from >daily data + my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; + + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_dO3_streams'); + if ( &value_is_true( $nl->get_value('use_dO3_streams') ) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_dO3', + 'hgrid'=>"360x720cru" ); + if ($opts->{'driver'} eq "nuopc" ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_dO3', + 'hgrid'=>"360x720cru" ); + } + } else { + if ( defined($nl->get_value('stream_fldfilename_dO3'))) { + $log->fatal_error("One of the dO3 streams namelist items (stream_fldfilename_dO3, " . + " is defined, but use_dO3_streams option NOT set to true"); + } + } +} + +#------------------------------------------------------------------------------- + sub setup_logic_soilwater_movement { my ($opts, $nl_flags, $definition, $defaults, $nl) = @_; diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 2686d62b9a..d52b86c545 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1194,15 +1194,15 @@ lnd/clm2/surfdata_map/release-clm5.0.30/surfdata_ne0np4.CONUS.ne30x8_hist_78pfts lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc -lnd/clm2/surfdata_map/landuse.timeseries_0.9x1.25_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc -lnd/clm2/surfdata_map/landuse.timeseries_1.9x2.5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc -lnd/clm2/surfdata_map/landuse.timeseries_10x15_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc lnd/clm2/surfdata_map/landuse.timeseries_4x5_hist_16pfts_Irrig_CMIP6_simyr1850-2015_c170824.nc @@ -1556,6 +1556,14 @@ lnd/clm2/surfdata_map/release-clm5.0.30/surfdata_ne0np4.CONUS.ne30x8_hist_78pfts nn nn + +.false. + +/glade/work/afoster/ozone_damage_files/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc +$DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + +bilinear + none diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index a08795dd1f..bb4e68094b 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -8,11 +8,11 @@ - Full pathname of initial conditions file. If blank CLM will startup from arbitrary initial conditions. @@ -29,30 +29,30 @@ creating the output file specified by finidat_interp_dest. This requires that finidat be non-blank. - Full pathname of master restart file for a branch run. (only used if RUN_TYPE=branch) (Set with RUN_REFCASE and RUN_REFDATE) - Component name to use in history and restart files - Full pathname of land fraction data file. @@ -78,8 +78,8 @@ Type of CO2 feedback. -Supplemental Nitrogen mode and for what type of vegetation it's turned on for. -In this mode Nitrogen is unlimited rather than prognosed and in general vegetation is +Supplemental Nitrogen mode and for what type of vegetation it's turned on for. +In this mode Nitrogen is unlimited rather than prognosed and in general vegetation is over-productive. NONE = No vegetation types get supplemental Nitrogen ALL = Supplemental Nitrogen is active for all vegetation types @@ -123,7 +123,7 @@ Otherwise use the fraction straight up (the default for CLM5.0) 10SL_3.5m = standard CLM4 and CLM4.5 version -23SL_3.5m = more vertical layers for permafrost simulations +23SL_3.5m = more vertical layers for permafrost simulations 49SL_10m = 49 layer soil column, 10m of soil, 5 bedrock layers 20SL_8.5m = 20 layer soil column, 8m of soil, 5 bedrock layers 4SL_2m = 4 layer soil column, 2m of soil, 0 bedrock layers @@ -357,7 +357,7 @@ Index of solution method of Richards equation. Change method for richards equation solution and boundary conditions. -CLM 4.5 - soilwater_movement_method = 0 (Zeng and Decker, 2009, method). +CLM 4.5 - soilwater_movement_method = 0 (Zeng and Decker, 2009, method). CLM 5.0 - soilwater_movement_method = 1 (adaptive time stepping moisture form from Martyn Clark). 1 (adaptive time stepping moisture form @@ -377,7 +377,7 @@ lower_boundary_condition = 2 : zero-flux lower boundary condition lower_boundary_condition = 3 : water table head-based lower boundary condition w/ aquifer layer. (use with soilwater_movement_method=adaptive time stepping) lower_boundary_condition = 4 : 11-layer solution w/ aquifer layer (only used with soilwater_movement_method=Zeng&Decker 2009) -TODO(bja, 2015-09) these should be strings so they have meaningful names instead of ints. +TODO(bja, 2015-09) these should be strings so they have meaningful names instead of ints. If TRUE, irrigation will be active. - + If TRUE, fsat will be set to zero for crop columns. - + @@ -639,7 +639,7 @@ Switch deciding which nutrient model to use in FATES. + group="clm_inparm" valid_values="" value=".false."> Toggle to turn on the tree damage module in FATES (Only relevant if FATES is on) @@ -650,7 +650,7 @@ Turn on spitfire module to simulate fire by setting fates_spitfire_mode > 0. Allowed values are: 0 : Simulations of fire are off 1 : use a global constant lightning rate found in fates_params. - 2 : use an external lightning dataset. + 2 : use an external lightning dataset. 3 : use an external confirmed ignitions dataset (not available through standard CSEM dataset collection). 4 : use external lightning and population datasets to simulate both natural and anthropogenic 5 : use gross domestic production and population datasets to simulate anthropogenic fire supression @@ -659,20 +659,20 @@ ignitions. + group="clm_inparm" valid_values="" value=".false."> Toggle to turn on fixed biogeography mode (Only relevant if FATES is on) -Toggle to turn on no competition mode (only relevant if FATES is being used). + group="clm_inparm" valid_values="" value=".false."> +Toggle to turn on no competition mode (only relevant if FATES is being used). -Toggle to turn on FATES satellite phenology mode (only relevant if FATES is being used). + group="clm_inparm" valid_values="" value=".false."> +Toggle to turn on FATES satellite phenology mode (only relevant if FATES is being used). - SNICAR (SNow, ICe, and Aerosol Radiative model) optical data file name - SNICAR (SNow, ICe, and Aerosol Radiative model) snow aging data file name @@ -907,7 +907,7 @@ Per tape series maximum number of time samples. -Per tape series history file density (i.e. output precision) +Per tape series history file density (i.e. output precision) 1=double precision 2=single precision Default: 2,2,2,2,2,2,2,2,2,2 @@ -915,7 +915,7 @@ Per tape series history file density (i.e. output precision) -Per tape series history write frequency. +Per tape series history write frequency. positive means in time steps 0=monthly negative means hours @@ -962,7 +962,7 @@ If TRUE, urban traffic flux will be activated (Currently NOT implemented). group="clm_humanindex_inparm" valid_values="ALL,FAST,NONE" > Human heat stress indices: ALL = All indices will be calculated - FAST = A subset of indices will be calculated (will not include the computationally + FAST = A subset of indices will be calculated (will not include the computationally expensive wet bulb calculation and associated indices) NONE = No indices will be calculated @@ -1023,7 +1023,7 @@ Turn on methane model. Standard part of CLM45BGC model. -CLM Biogeochemistry mode : Carbon Nitrogen model (CN) +CLM Biogeochemistry mode : Carbon Nitrogen model (CN) (or CLM45BGC if phys=clm4_5, vsoilc_centbgc='on', and clm4me='on') @@ -1041,7 +1041,7 @@ Requires the CN model to work (either CN or CNDV). -Nitrification/denitrification splits the prognostic mineral N pool into two +Nitrification/denitrification splits the prognostic mineral N pool into two mineral N pools: NO3 and NH4, and includes the transformations between them. Turned on for BGC FATES currently allows it to be true or false, but will be hardwired to true later @@ -1081,19 +1081,19 @@ Toggle to turn on the prognostic crop model -Toggle to turn on the prognostic fertilizer for crop model +Toggle to turn on the prognostic fertilizer for crop model -Toggle to turn on the 1-year grain product pool in the crop model +Toggle to turn on the 1-year grain product pool in the crop model Type of mapping to use for base temperature for prognostic crop model constant = Just use baset from the PFT parameter file -varytropicsbylat = Vary the tropics by latitude +varytropicsbylat = Vary the tropics by latitude - Parameter to set the type of ozone vegetation stress method - unset = (default) ozone stress vegetation method is off + Parameter to set the type of ozone vegetation stress method + unset = (default) ozone stress vegetation method is off stress_lombardozzi2015 = ozone stress vegetation functions from Danica Lombardozzi 2015 stress_falk = ozone stress vegetation functions from Stefanie Falk (issue #1224) Default: "unset" - - + + Phenology onset depends on the vegetation type @@ -1240,7 +1240,7 @@ SCRIP format grid data file group="clmexp" valid_values="none,64bit_offset,netcdf4" > Flag to pass to the ESMF mapping utility, telling it what kind of large file support is needed for an output file generated with this grid as -either the source or destination ('none', '64bit_offset' or 'netcdf4'). +either the source or destination ('none', '64bit_offset' or 'netcdf4'). Filename for mksurfdata_map to remap raw data into the output surface dataset @@ -1535,7 +1535,7 @@ by getco2_historical.ncl - Aerosol deposition file name (only used for aerdepregrid.ncl) @@ -1699,13 +1699,13 @@ Mapping method from Nitrogen deposition input file to the model resolution -Filename of input stream data for finundated inversion of observed (from Prigent dataset) +Filename of input stream data for finundated inversion of observed (from Prigent dataset) to hydrologic variables (either TWS or ZWT) -mesh filename of input stream data for finundated inversion of observed (from Prigent dataset) +mesh filename of input stream data for finundated inversion of observed (from Prigent dataset) to hydrologic variables (either TWS or ZWT) @@ -1805,6 +1805,38 @@ Mapping method from LAI input file to the model resolution copy = copy using the same indices + + + + + + +Toggle to turn on reading in of diurnal ozone anomaly file. Used to convert >daily ozone to sub-daily + + + +Filename of input stream data for diurnal ozone anomaly + + + +Filename of mesh file for diurnal ozone anomaly file + + + +Mapping method from diurnal ozone input file to the model resolution + bilinear = bilinear interpolation + nn = nearest neighbor + nnoni = nearest neighbor on the "i" (longitude) axis + nnonj = nearest neighbor on the "j" (latitude) axis + spval = set to special value + copy = copy using the same indices + + + @@ -1968,16 +2000,16 @@ Mapping file to go from one resolution/land-mask to another resolution/land-mask Land mask description for mksurfdata input files - + Horizontal grid resolutions for mksurfdata input files - + @@ -1990,7 +2022,7 @@ Resolution of finundated inversion streams dataset (stream_fldfilename_ch4finund to use for methane model (only applies when CN and methane model are turned on) - + Resolution of Lightning dataset to use for CN fire model @@ -2009,51 +2041,51 @@ Add a note to the output namelist about the options given to build-namelist -CLM run type. +CLM run type. 'default' use the default type of clm_start type for this configuration 'cold' is a run from arbitrary initial conditions 'arb_ic' is a run using initial conditions if provided, OR arbitrary initial conditions if no files can be found - 'startup' is an initial run with initial conditions provided. + 'startup' is an initial run with initial conditions provided. 'continue' is a restart run. 'branch' is a restart run in which properties of the output history files may be changed. Horizontal resolutions Note: 0.25x0.25, 0.5x0.5, 5x5min, 10x10min, 3x3min, 1km-merge-10min and 0.33x0.33 are only used for CLM toolsI - + -Shared Socioeconomic Pathway (SSP) and Representative Concentration Pathway (RCP) combination for future scenarios +Shared Socioeconomic Pathway (SSP) and Representative Concentration Pathway (RCP) combination for future scenarios The form is SSPn-m.m Where n is the SSP number and m.m is RCP radiative forcing at peak or 2100 in W/m^2 n is just the whole number of the specific SSP scenario. The lower numbers have higher mitigation - the higher numbers less mitigation, more than one SSP can result in the same RCP forcing hist means do NOT use a future scenario, just use historical data. - + Land mask description - + General configuration of model version and atmospheric forcing to tune the model to run under. -This sets the model to run with constants and initial conditions that were set to run well under +This sets the model to run with constants and initial conditions that were set to run well under the configuration of model version and atmospheric forcing. To run well constants would need to be changed to run with a different type of atmospheric forcing. - + If 1, turn on the MEGAN model for BVOC's (Biogenic Volitile Organic Compounds) - + + + @@ -2115,8 +2147,8 @@ NOTE: THIS CORRESPONDS DIRECTLY TO THE env_run.xml VARIABLE OF THE SAME NAME. Command line arguement for biogeochemistry mode for CLM4.5 sp = Satellitte Phenology cn = Carbon Nitrogen model - bgc = CLM4.5 BGC model with: - CENTURY model pools + bgc = CLM4.5 BGC model with: + CENTURY model pools Nitrification/De-nitrification Methane model Vertically resolved Carbon @@ -2134,8 +2166,8 @@ Flag for overriding the crash that should occur if user tries to start the model -Flag for setting the state of the Accelerated decomposition spinup state for the BGC model. - 0 = normal model behavior; +Flag for setting the state of the Accelerated decomposition spinup state for the BGC model. + 0 = normal model behavior; 1 = AD spinup (standard) 2 = AD spinup (accelerated spinup from Ricciuto, doesn't work for CNDV and not implemented for CN soil decomposition) Entering and exiting spinup mode occurs automatically by comparing the namelist and restart file values for this variable. @@ -2195,7 +2227,7 @@ Soil decomposition method CENTURYKoven2013 -- CENTURY model in CTSM from Koven et. al. 2013 MIMICSWieder2015 -- MIMICS model in CTSM from Wieder et. al. 2015 -An active soil decomposition method requires the BGC or FATES model to work +An active soil decomposition method requires the BGC or FATES model to work And both BGC and FATES models require an active soil decomposition model @@ -2343,7 +2375,7 @@ Minimum lake depth to increase non-molecular thermal diffusivities by the factor group="clm_inparm" valid_values="" > Factor to increase non-molecular thermal diffusivities for lakes deeper than deepmixing_depthcrit to account for unresolved 3D processes. -Set to 1 to +Set to 1 to -Allows user to tune the value of aereoxid. If set to FALSE, then use the value of aereoxid from +Allows user to tune the value of aereoxid. If set to FALSE, then use the value of aereoxid from the parameter file (set to 0.0, but may be tuned with values in the range {0.0,1.0}. If set to TRUE, then don't fix aere (see ch4Mod.F90). Default: .true. @@ -2408,7 +2440,7 @@ so the coupled system will NOT conserve carbon in this mode if the methane model -Inundated fraction method type to use for the CH4 submodel (possibly affecting soil +Inundated fraction method type to use for the CH4 submodel (possibly affecting soil heterotrophic respiration and denitrification depending on the configuration), h2osfc ----------- Use prognostic saturated fraction h2osfc value calculated in Soil Hydrology @@ -2578,7 +2610,7 @@ Values less than 5 are mainly useful for testing, and should not be used for sci -Maximum snow depth in mm H2O equivalent. Additional mass gains will be capped when this depth +Maximum snow depth in mm H2O equivalent. Additional mass gains will be capped when this depth is exceeded. Changes in this value should possibly be accompanied by changes in: - nlevsno: larger values of h2osno_max should be accompanied by increases in nlevsno @@ -2707,8 +2739,8 @@ differently in areas below and above reset_snow_glc_ela. Only relevant if reset_snow_glc is .true. When resetting snow pack over glacier columns, one can choose to do this over all glacier -columns, or only those below a certain elevation. A typical use case is to reset only those -columns that have a seasonal snow pack in the real world, i.e. SMB less than 0, also known as +columns, or only those below a certain elevation. A typical use case is to reset only those +columns that have a seasonal snow pack in the real world, i.e. SMB less than 0, also known as the equilibrium line altitude (ELA). This parameter sets a single global ELA value. By setting this parameter to a large value (i.e. 10000 m), all glacier columns will be reset. @@ -2740,7 +2772,7 @@ the related bulk quantities. If .true., run with water isotopes - + diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index b505d822e5..09c4c0f69e 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -22,6 +22,7 @@ module lnd_import_export use shr_megan_mod , only : shr_megan_readnl, shr_megan_mechcomps_n use nuopc_shr_methods , only : chkerr use lnd_import_export_utils , only : check_for_errors, check_for_nans + use diurnalOzoneStreamMod , only : dO3_init implicit none private ! except @@ -311,7 +312,7 @@ subroutine advertise_fields(gcomp, flds_scalar_name, glc_present, cism_evolve, r end if if (send_lnd2glc) then ! lnd->glc states from land all lnd->glc elevation classes (1:glc_nec) plus bare land (index 0). - ! The following puts all of the elevation class fields as an! undistributed dimension in + ! The following puts all of the elevation class fields as an! undistributed dimension in ! the export state field call fldlist_add(fldsFrLnd_num, fldsFrLnd, Sl_tsrf_elev , ungridded_lbound=1, ungridded_ubound=glc_nec+1) call fldlist_add(fldsFrLnd_num, fldsFrLnd, Sl_topo_elev , ungridded_lbound=1, ungridded_ubound=glc_nec+1) @@ -713,7 +714,7 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & ! input/output variables type(ESMF_GridComp) :: gcomp - type(bounds_type) , intent(in) :: bounds + type(bounds_type) , intent(in) :: bounds logical , intent(in) :: glc_present logical , intent(in) :: rof_prognostic type(waterlnd2atmbulk_type) , intent(inout) :: waterlnd2atmbulk_inst @@ -759,7 +760,7 @@ subroutine export_fields( gcomp, bounds, glc_present, rof_prognostic, & if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_setexport_1d(exportState, Sl_snowh , waterlnd2atmbulk_inst%h2osno_grc(begg:), & init_spval=.false., rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (ChkErr(rc,__LINE__,u_FILE_u)) return call state_setexport_1d(exportState, Sl_avsdr , lnd2atm_inst%albd_grc(begg:,1), & init_spval=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 150e1dfe3a..7d836344ee 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -76,7 +76,7 @@ subroutine dO3_init(bounds) write(stream_varnames(n),'(a,i0)') dO3String,n end do - ! Read lai_streams namelist + ! Read dO3_streams namelist if (masterproc) then open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) call find_nlgroup_name(nu_nml, 'dO3_streams', status=nml_error) From 37fed717b76a4c33e7fec0e5257b0bc93a43e8c5 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Fri, 2 Sep 2022 15:09:12 -0600 Subject: [PATCH 03/39] move to all lower case --- bld/namelist_files/namelist_definition_ctsm.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index bb4e68094b..d59f09ff78 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1810,7 +1810,7 @@ Mapping method from LAI input file to the model resolution - Toggle to turn on reading in of diurnal ozone anomaly file. Used to convert >daily ozone to sub-daily From 907940430bd87b4c34ad904324b672a077d26e8c Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Thu, 8 Sep 2022 13:36:03 -0600 Subject: [PATCH 04/39] fix namelist variables --- bld/CLMBuildNamelist.pm | 14 +++++++------- bld/namelist_files/namelist_defaults_ctsm.xml | 10 +++++----- bld/namelist_files/namelist_definition_ctsm.xml | 12 ++++++------ src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 14 +++++++------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 2368268f8b..a4b812fd1d 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1665,7 +1665,7 @@ sub process_namelist_inline_logic { ################################## # namelist group: dO3_streams # ################################## - setup_logic_dO3_streams($opts, $nl_flags, $definition, $defaults, $nl); + setup_logic_do3_streams($opts, $nl_flags, $definition, $defaults, $nl); ########################################## # namelist group: soil_moisture_streams # @@ -3830,12 +3830,12 @@ sub setup_logic_lai_streams { #------------------------------------------------------------------------------- -sub setup_logic_dO3_streams { +sub setup_logic_do3_streams { # input file for creating diurnal ozone from >daily data my ($opts, $nl_flags, $definition, $defaults, $nl, $physv) = @_; - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_dO3_streams'); - if ( &value_is_true( $nl->get_value('use_dO3_streams') ) ) { + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_do3_streams'); + if ( &value_is_true( $nl->get_value('use_do3_streams') ) ) { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_dO3', 'hgrid'=>"360x720cru" ); if ($opts->{'driver'} eq "nuopc" ) { @@ -3843,9 +3843,9 @@ sub setup_logic_dO3_streams { 'hgrid'=>"360x720cru" ); } } else { - if ( defined($nl->get_value('stream_fldfilename_dO3'))) { - $log->fatal_error("One of the dO3 streams namelist items (stream_fldfilename_dO3, " . - " is defined, but use_dO3_streams option NOT set to true"); + if ( defined($nl->get_value('stream_fldfilename_do3'))) { + $log->fatal_error("One of the do3 streams namelist items (stream_fldfilename_do3, " . + " is defined, but use_do3_streams option NOT set to true"); } } } diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index d52b86c545..2fd0b9d8d4 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1556,13 +1556,13 @@ lnd/clm2/surfdata_map/release-clm5.0.30/surfdata_ne0np4.CONUS.ne30x8_hist_78pfts nn nn - -.false. + +.false. -/glade/work/afoster/ozone_damage_files/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc -$DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc +/glade/work/afoster/ozone_damage_files/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc +$DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc -bilinear +bilinear diff --git a/bld/namelist_files/namelist_definition_ctsm.xml b/bld/namelist_files/namelist_definition_ctsm.xml index d59f09ff78..2260ea243e 100644 --- a/bld/namelist_files/namelist_definition_ctsm.xml +++ b/bld/namelist_files/namelist_definition_ctsm.xml @@ -1815,18 +1815,18 @@ Mapping method from LAI input file to the model resolution Toggle to turn on reading in of diurnal ozone anomaly file. Used to convert >daily ozone to sub-daily - + Filename of input stream data for diurnal ozone anomaly - + Filename of mesh file for diurnal ozone anomaly file - + Mapping method from diurnal ozone input file to the model resolution bilinear = bilinear interpolation nn = nearest neighbor diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 7d836344ee..c639789d46 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -92,7 +92,7 @@ subroutine dO3_init(bounds) endif call shr_mpi_bcast(stream_fldFileName_dO3 , mpicom) call shr_mpi_bcast(stream_meshfile_dO3 , mpicom) - call shr_mpi_bcast(dO3_tintalgo , mpicom) + call shr_mpi_bcast(dO3_mapalgo , mpicom) if (masterproc) then write(iulog,*) @@ -118,14 +118,14 @@ subroutine dO3_init(bounds) stream_filenames = (/trim(stream_fldfilename_dO3)/), & stream_fldlistFile = stream_varnames, & stream_fldListModel = stream_varnames, & - stream_yearFirst = 'null', & - stream_yearLast = 'null', & - stream_yearAlign = 'null', & - stream_offset = 'null', & + stream_yearFirst = 1, & + stream_yearLast = 1, & + stream_yearAlign = 1, & + stream_offset = 0, & stream_taxmode = 'null', & - stream_dtlimit = 'null', & + stream_dtlimit = 0.0_r8, & stream_tintalgo = 'null', & - stream_name = 'dO3 data', & + stream_name = 'do3 data', & rc = rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then call ESMF_Finalize(endflag=ESMF_END_ABORT) From 743bfa0510077f5cb80352657b64ee0cdf5e177d Mon Sep 17 00:00:00 2001 From: adrifoster Date: Thu, 8 Sep 2022 13:42:51 -0600 Subject: [PATCH 05/39] update fieldlist names --- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index c639789d46..876f4dac56 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -26,7 +26,7 @@ module diurnalOzoneStreamMod ! !PRIVATE MEMBER DATA: integer, allocatable :: g_to_ig(:) ! Array matching gridcell index to data index type(shr_strdata_type) :: sdat_dO3 ! diurnal ozone anomaly input data stream - character(*), parameter :: dO3String = "dO3_" ! base string for field string + character(*), parameter :: dO3String = "do3_" ! base string for field string integer , parameter :: numdO3Fields = 16 ! number of fields to build field string character(len=CS) :: stream_varnames(numdO3Fields) @@ -79,14 +79,14 @@ subroutine dO3_init(bounds) ! Read dO3_streams namelist if (masterproc) then open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) - call find_nlgroup_name(nu_nml, 'dO3_streams', status=nml_error) + call find_nlgroup_name(nu_nml, 'do3_streams', status=nml_error) if (nml_error == 0) then read(nu_nml, nml=dO3_streams,iostat=nml_error) if (nml_error /= 0) then - call endrun(subname // ':: ERROR reading dO3_streams namelist') + call endrun(subname // ':: ERROR reading do3_streams namelist') end if else - call endrun(subname // ':: ERROR finding dO3_streams namelist') + call endrun(subname // ':: ERROR finding do3_streams namelist') end if close(nu_nml) endif @@ -96,9 +96,9 @@ subroutine dO3_init(bounds) if (masterproc) then write(iulog,*) - write(iulog,'(a)') 'dO3_stream settings:' - write(iulog,'(a,a)' ) ' stream_fldFileName_dO3 = ',trim(stream_fldFileName_dO3) - write(iulog,'(a,a)' ) ' stream_meshfile_dO3 = ',trim(stream_meshfile_dO3) + write(iulog,'(a)') 'do3_stream settings:' + write(iulog,'(a,a)' ) ' stream_fldFileName_do3 = ',trim(stream_fldFileName_dO3) + write(iulog,'(a,a)' ) ' stream_meshfile_do3 = ',trim(stream_meshfile_dO3) do n = 1,numdO3Fields write(iulog,'(a,a)' ) ' stream_varname = ',trim(stream_varnames(n)) end do From 40110babbd40a8096924da0399b88e7201142f39 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Thu, 8 Sep 2022 14:01:23 -0600 Subject: [PATCH 06/39] update bld --- bld/CLMBuildNamelist.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index a4b812fd1d..ac1555afd7 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3836,10 +3836,10 @@ sub setup_logic_do3_streams { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_do3_streams'); if ( &value_is_true( $nl->get_value('use_do3_streams') ) ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_dO3', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_do3', 'hgrid'=>"360x720cru" ); if ($opts->{'driver'} eq "nuopc" ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_dO3', + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_do3', 'hgrid'=>"360x720cru" ); } } else { From 01c3efa4f9942c9f18b694a9be02cb72b7197dc1 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Thu, 8 Sep 2022 14:32:31 -0600 Subject: [PATCH 07/39] fix do3 streams --- bld/CLMBuildNamelist.pm | 13 ++++++++----- bld/namelist_files/namelist_defaults_ctsm.xml | 5 ++--- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 2 +- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index ac1555afd7..24411ba2c5 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -3836,12 +3836,15 @@ sub setup_logic_do3_streams { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'use_do3_streams'); if ( &value_is_true( $nl->get_value('use_do3_streams') ) ) { + if ($opts->{'driver'} ne "nuopc") { + $log->fatal_error("Cannot use do3_streams=.true. with MCT."); + } add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_fldfilename_do3', 'hgrid'=>"360x720cru" ); - if ($opts->{'driver'} eq "nuopc" ) { - add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_do3', - 'hgrid'=>"360x720cru" ); - } + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_meshfile_do3', + 'hgrid'=>"360x720cru" ); + add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'do3_mapalgo', + 'hgrid'=>$nl_flags->{'res'} ); } else { if ( defined($nl->get_value('stream_fldfilename_do3'))) { $log->fatal_error("One of the do3 streams namelist items (stream_fldfilename_do3, " . @@ -4231,7 +4234,7 @@ sub write_output_files { soil_resis_inparm bgc_shared canopyfluxes_inparm aerosol clmu_inparm clm_soilstate_inparm clm_nitrogen clm_snowhydrology_inparm cnprecision_inparm clm_glacier_behavior crop irrigation_inparm - surfacealbedo_inparm water_tracers_inparm); + surfacealbedo_inparm water_tracers_inparm do3_streams); #@groups = qw(clm_inparm clm_canopyhydrology_inparm clm_soilhydrology_inparm # finidat_consistency_checks dynpft_consistency_checks); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 2fd0b9d8d4..024fbb472d 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1559,9 +1559,8 @@ lnd/clm2/surfdata_map/release-clm5.0.30/surfdata_ne0np4.CONUS.ne30x8_hist_78pfts .false. -/glade/work/afoster/ozone_damage_files/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc -$DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc - +/glade/work/afoster/ozone_damage_files/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc +$DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc bilinear diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 876f4dac56..15881d2c88 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -105,7 +105,7 @@ subroutine dO3_init(bounds) write(iulog,*) endif - ! Initialize the cdeps data type sdat_lai + ! Initialize the cdeps data type sdat_dO3 call shr_strdata_init_from_inline(sdat_dO3, & my_task = iam, & logunit = iulog, & From ea819761d06711eaf2fc2aa68b460e6ed41a7833 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 11:07:28 -0600 Subject: [PATCH 08/39] create diurnalozonetype --- bld/namelist_files/namelist_defaults_ctsm.xml | 2 +- src/biogeophys/DiurnalOzoneType.F90 | 80 +++++ src/biogeophys/OzoneMod.F90 | 10 +- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 283 +++++++++++------- 4 files changed, 259 insertions(+), 116 deletions(-) create mode 100644 src/biogeophys/DiurnalOzoneType.F90 diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 024fbb472d..dbb1e60f37 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1559,7 +1559,7 @@ lnd/clm2/surfdata_map/release-clm5.0.30/surfdata_ne0np4.CONUS.ne30x8_hist_78pfts .false. -/glade/work/afoster/ozone_damage_files/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc +/glade/work/afoster/ozone_damage_files/converted/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc bilinear diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 new file mode 100644 index 0000000000..be6373fad3 --- /dev/null +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -0,0 +1,80 @@ +module DiurnalOzoneType + + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Sets up type for converting multi-day ozone input to sub-daily values using an input + ! ozone anomaly file + ! + ! !USES: + #include "shr_assert.h" + use shr_kind_mod , only : r8 => shr_kind_r8 + use decompMod , only : bounds_type + use clm_varcon , only : spval + use clm_varctl , only : iulog + use abortutils , only : endrun + use shr_ozone_coupling_mod , only : atm_ozone_frequency_unset, atm_ozone_frequency_subdaily, & + atm_ozone_frequency_multiday_average + implicit none + save + private + + ! !PUBLIC TYPES: + type, public :: diurnal_ozone_anom_type + private + ! Private data members + integer :: ozone_input_frequency ! Which ozone input frequency are we receiving? + integer :: ntimes + real(r8), allocatable :: sec(:) ! seconds of day (size ntimes) + real(r8), allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] + + contains + ! Public routines + procedure, public :: Init + procedure, public :: Interp + + end type diurnal_ozone_anom_type + + ! !PRIVATE TYPES: + integer, parameter :: ozone_frequency_unset = 0 + integer, parameter :: ozone_frequency_subdaily = 1 + integer, parameter :: ozone_frequency_multiday_average = 2 + + character(len=*), parameter, private :: sourcefile = & + __FILE__ + + + contains + + ! ======================================================================== + ! Infrastructure routines (initialization, restart, etc.) + ! ======================================================================== + + !----------------------------------------------------------------------- + subroutine Init(this) + ! + ! !DESCRIPTION: + ! Initialize ozone data structure + ! + ! + ! !ARGUMENTS: + class(diurnal_ozone_anom_type), intent(inout) :: this + !----------------------------------------------------------------------- + + if (atm_ozone_frequency_val == atm_ozone_frequency_unset) then + this%ozone_input_frequency = ozone_frequency_unset + else if (atm_ozone_frequency_val == atm_ozone_frequency_subdaily) then + this%ozone_input_frequency = ozone_frequency_subdaily + else if (atm_ozone_frequency_val == atm_ozone_frequency_multiday_average) then + this%ozone_input_frequency = ozone_frequency_multiday_average + else + call endrun('unknown ozone frequency') + end if + + end subroutine Init + + + !----------------------------------------------------------------------- + + + end module DiurnalOzoneType + \ No newline at end of file diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 61efdfcde0..ba9eef27b4 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -398,6 +398,12 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & tlai_old => this%tlai_old_patch & ! Output: [real(r8) (:)] tlai from last time step ) + if (this%flag == 'multiday_average') then + call o3DiurnalAnomolyInst%interp(forc_o3, forc_o3_down) + else + forc_o3_down => forc_o3 + end if + do fp = 1, num_exposedvegp p = filter_exposedvegp(fp) c = patch%column(p) @@ -405,14 +411,14 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & ! Ozone uptake for shaded leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssha(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesha(p)) ! Ozone uptake for sunlit leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssun(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesun(p)) diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 15881d2c88..b7648320ae 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -2,135 +2,192 @@ module diurnalOzoneStreamMod #include "shr_assert.h" - !----------------------------------------------------------------------- - ! !DESCRIPTION: - ! Read in file to convert input ozone to sub-daily values from stream - ! - ! !USES: - use ESMF - use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL, CS => shr_kind_CS - use dshr_strdata_mod , only : shr_strdata_type - use decompMod , only : bounds_type - use abortutils , only : endrun - use clm_varctl , only : iulog - use perf_mod , only : t_startf, t_stopf - use spmdMod , only : masterproc, mpicom, iam - ! - ! !PUBLIC TYPES: - implicit none - private - - ! !PUBLIC MEMBER FUNCTIONS: - public :: dO3_init ! position dataset for diurnal ozone anomaly - - ! !PRIVATE MEMBER DATA: - integer, allocatable :: g_to_ig(:) ! Array matching gridcell index to data index - type(shr_strdata_type) :: sdat_dO3 ! diurnal ozone anomaly input data stream - character(*), parameter :: dO3String = "do3_" ! base string for field string - integer , parameter :: numdO3Fields = 16 ! number of fields to build field string - character(len=CS) :: stream_varnames(numdO3Fields) - - character(len=*), parameter :: sourcefile = & - __FILE__ + !----------------------------------------------------------------------- + ! !DESCRIPTION: + ! Read in file to convert input ozone to sub-daily values from stream + ! + ! !USES: + use ESMF + use dshr_strdata_mod , only : shr_strdata_type + use shr_kind_mod , only : r8 => shr_kind_r8, CL => shr_kind_CL, CS => shr_kind_CS + use shr_log_mod , only : errMsg => shr_log_errMsg + use spmdMod , only : masterproc, mpicom + use clm_varctl , only : iulog + use abortutils , only : endrun + use decompMod , only : bounds_type + use diurnalOzoneType , only : diurnal_ozone_anom_type -!============================================================================== -contains -!============================================================================== + ! + ! PUBLIC TYPES: + implicit none + private + + ! PUBLIC MEMBER FUNCTIONS: + public :: dO3_init ! position dataset for diurnal ozone anomaly + + character(len=*), parameter :: sourcefile = & + __FILE__ + + !============================================================================== + contains - subroutine dO3_init(bounds) - ! - ! Initialize data stream information for LAI. - ! - ! !USES: - use shr_mpi_mod , only : shr_mpi_bcast - use clm_nlUtilsMod , only : find_nlgroup_name - use lnd_comp_shr , only : mesh, model_clock - use dshr_strdata_mod , only : shr_strdata_init_from_inline - use controlMod , only : NLFilename - ! - ! !ARGUMENTS: - type(bounds_type), intent(in) :: bounds ! bounds - ! - ! !LOCAL VARIABLES: - integer :: i,n ! index - integer :: nu_nml ! unit for namelist file - integer :: nml_error ! namelist i/o error flag - character(len=CL) :: stream_fldFileName_dO3 ! diurnal ozone stream filename to read - character(len=CL) :: stream_meshfile_dO3 ! diurnal ozone stream meshfile - character(len=CL) :: dO3_mapalgo = 'bilinear' ! Mapping alogrithm - integer :: rc - character(*), parameter :: subName = "('dO3dyn_init')" - !----------------------------------------------------------------------- - ! - ! deal with namelist variables here in init - ! - namelist /dO3_streams/ & - dO3_mapalgo, & - stream_fldFileName_dO3, & + !============================================================================== + + subroutine dO3_init(diurnalOzoneAnomInst, bounds) + ! + ! Initialize data stream information for LAI. + ! + ! USES: + use spmdMod , only : iam + use clm_nlUtilsMod , only : find_nlgroup_name + use shr_log_mod , only : errMsg => shr_log_errMsg + use shr_mpi_mod , only : shr_mpi_bcast + use controlMod , only : NLFilename + use lnd_comp_shr , only : mesh, model_clock + use dshr_strdata_mod , only : shr_strdata_init_from_inline, shr_strdata_print + use dshr_strdata_mod , only : shr_strdata_advance + use dshr_methods_mod , only : dshr_field_getfldptr + + ! + ! ARGUMENTS: + type(diurnal_ozone_anom_type), intent(in) :: diurnalOzoneAnomInst ! instance of diurnal ozone anomaly type + type(bounds_type), intent(in) :: bounds ! bounds + ! + ! !LOCAL VARIABLES: + type(shr_strdata_type) :: sdat_dO3 ! input data stream + real(r8), pointer :: dataptr2d(:,:) ! first dimension is level, second is data on that level + integer :: ig, g, j ! indices + integer :: nu_nml ! unit for namelist file + integer :: nml_error ! namelist i/o error flag + integer :: year ! year (0, ...) for nstep+1 + integer :: mon ! month (1, ..., 12) for nstep+1 + integer :: day ! day of month (1, ..., 31) for nstep+1 + integer :: sec ! seconds into current date for nstep+1 + integer :: mcdate ! current model date (yyyymmdd) + integer :: rc ! error code + integer, parameter :: nlevsec = 24 ! number of hours in day + integer, allocatable :: g_to_ig(:) ! array matching gridcell index to data index + character(len=CL) :: stream_fldFileName_dO3 = ' ' ! diurnal ozone stream filename to read + character(len=CL) :: stream_meshfile_dO3 = ' ' ! diurnal ozone stream meshfile + character(len=CL) :: dO3_mapalgo = 'bilinear' ! mapping alogrithm + character(len=CL) :: stream_lev_dimname = 'sec' ! name of vertical layer dimension + character(*), parameter :: stream_var_name = "O3_diurnal_factor" ! base string for field string + character(len=*), parameter :: subName = "('dO3_init')" + + !----------------------------------------------------------------------- + ! + ! namelist variables + ! + namelist /dO3_streams/ & + dO3_mapalgo, & + stream_fldFileName_dO3, & stream_meshfile_dO3 - ! Default values for namelist - stream_fldFileName_dO3 = '' - stream_meshfile_dO3 = '' - do n = 1,numdO3Fields - write(stream_varnames(n),'(a,i0)') dO3String,n - end do - - ! Read dO3_streams namelist - if (masterproc) then - open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) - call find_nlgroup_name(nu_nml, 'do3_streams', status=nml_error) - if (nml_error == 0) then - read(nu_nml, nml=dO3_streams,iostat=nml_error) - if (nml_error /= 0) then - call endrun(subname // ':: ERROR reading do3_streams namelist') - end if - else - call endrun(subname // ':: ERROR finding do3_streams namelist') - end if - close(nu_nml) - endif - call shr_mpi_bcast(stream_fldFileName_dO3 , mpicom) - call shr_mpi_bcast(stream_meshfile_dO3 , mpicom) - call shr_mpi_bcast(dO3_mapalgo , mpicom) - - if (masterproc) then - write(iulog,*) - write(iulog,'(a)') 'do3_stream settings:' - write(iulog,'(a,a)' ) ' stream_fldFileName_do3 = ',trim(stream_fldFileName_dO3) - write(iulog,'(a,a)' ) ' stream_meshfile_do3 = ',trim(stream_meshfile_dO3) - do n = 1,numdO3Fields - write(iulog,'(a,a)' ) ' stream_varname = ',trim(stream_varnames(n)) - end do - write(iulog,*) - endif - - ! Initialize the cdeps data type sdat_dO3 - call shr_strdata_init_from_inline(sdat_dO3, & + ! Read dO3_streams namelist + if (masterproc) then + open( newunit=nu_nml, file=trim(NLFilename), status='old', iostat=nml_error ) + call find_nlgroup_name(nu_nml, 'do3_streams', status=nml_error) + if (nml_error == 0) then + read(nu_nml, nml=dO3_streams,iostat=nml_error) + if (nml_error /= 0) then + call endrun(subname // ':: ERROR reading do3_streams namelist') + end if + else + call endrun(subname // ':: ERROR finding do3_streams namelist') + end if + close(nu_nml) + endif + + call shr_mpi_bcast(stream_fldFileName_dO3 , mpicom) + call shr_mpi_bcast(stream_meshfile_dO3 , mpicom) + call shr_mpi_bcast(dO3_mapalgo , mpicom) + + if (masterproc) then + write(iulog,*) + write(iulog,'(a)') 'do3_stream settings:' + write(iulog,'(a,a)' ) ' stream_fldFileName_do3 = ',trim(stream_fldFileName_dO3) + write(iulog,'(a,a)' ) ' stream_meshfile_do3 = ',trim(stream_meshfile_dO3) + do n = 1,numdO3Fields + write(iulog,'(a,a)' ) ' stream_varname = ',trim(stream_varnames(n)) + end do + write(iulog,*) + endif + + ! Initialize the cdeps data type sdat_dO3 + call shr_strdata_init_from_inline(sdat_dO3, & my_task = iam, & logunit = iulog, & compname = 'LND', & model_clock = model_clock, & model_mesh = mesh, & stream_meshfile = trim(stream_meshfile_dO3), & - stream_lev_dimname = 'null', & + stream_lev_dimname = trim(stream_lev_dimname), & stream_mapalgo = trim(dO3_mapalgo), & stream_filenames = (/trim(stream_fldfilename_dO3)/), & - stream_fldlistFile = stream_varnames, & - stream_fldListModel = stream_varnames, & - stream_yearFirst = 1, & - stream_yearLast = 1, & + stream_fldlistFile = (/trim(stream_var_name)/), & + stream_fldListModel = (/trim(stream_var_name)/), & + stream_yearFirst = 2000, & + stream_yearLast = 2000, & stream_yearAlign = 1, & stream_offset = 0, & - stream_taxmode = 'null', & - stream_dtlimit = 0.0_r8, & - stream_tintalgo = 'null', & + stream_taxmode = 'extend', & + stream_dtlimit = 1.0e30_r8, & + stream_tintalgo = 'linear', & stream_name = 'do3 data', & rc = rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then - call ESMF_Finalize(endflag=ESMF_END_ABORT) - end if + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Explicitly set current date to a hardcoded constant value + ! as in ch4FInundatedStreamType + year = 2000 + mon = 12 + day = 31 + sec = 0 + mcdate = year*10000 + mon*100 + day + + call shr_strdata_advance(sdat_dO3, ymd=mcdate, tod=sec, logunit=iulog, istr='do3', rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Map gridcell to 1->local_size + if ( .not. allocated(g_to_ig) )then + allocate (g_to_ig(bounds%begg:bounds%endg) ) + ig = 0 + do g = bounds%begg,bounds%endg + ig = ig+1 + g_to_ig(g) = ig + end do + end if - end subroutine dO3_init + ! Get pointer for stream data that is time and spatially interpolated to model time and grid + call dshr_fldbun_getFldPtr(sdat_do3%pstrm(1)%fldbun_model, trim(stream_var_name), fldptr2=dataptr2d, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + + ! Check that inner most dimension of dataptr2d is equal to nlevsoi + if (size(dataptr2d,dim=1) /= nlevsec) then + if (masterproc) then + write(iulog,*) 'ERROR: dataptr2d(dim=1) = ',size(dataptr2d,dim=1),& + ' and nlevsec = ',nlevsec,' must match ' + end if + call endrun(trim(subname) // & + ' ERROR:: The input diurnal ozone anomaly stream does not have levels equal to nlevsec') + end if + + ! Set the diurnal ozone anomaly + do g = bounds%begg, bounds%endg + ig = g_to_ig(g) + do j = 1, nlevsec + diurnalOzoneAnomInst%o3_anomaly_grc(g,j) = dataptr2d(j,ig) + end do + end do + + end subroutine dO3_init + +!============================================================================== end module diurnalOzoneStreamMod From c04e1fd94ed2cd21472fb423f9cf3b079c62f12b Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 11:40:52 -0600 Subject: [PATCH 09/39] remove notes --- src/biogeophys/DiurnalOzoneType.F90 | 53 +++++++++++++++++++++++------ src/biogeophys/OzoneMod.F90 | 14 ++++---- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index be6373fad3..2f4ba5630a 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -29,8 +29,9 @@ module DiurnalOzoneType contains ! Public routines - procedure, public :: Init - procedure, public :: Interp + procedure, public :: Init + procedure, private :: InitAllocate + procedure, public :: Interp end type diurnal_ozone_anom_type @@ -46,35 +47,67 @@ module DiurnalOzoneType contains ! ======================================================================== - ! Infrastructure routines (initialization, restart, etc.) + ! Infrastructure routines (initialization, etc.) ! ======================================================================== !----------------------------------------------------------------------- - subroutine Init(this) + subroutine Init(this, bounds, nsec) ! - ! !DESCRIPTION: + ! DESCRIPTION: ! Initialize ozone data structure ! ! ! !ARGUMENTS: class(diurnal_ozone_anom_type), intent(inout) :: this + type(bounds_type), intent(in) :: bounds + integer, intent(in) :: nsec !----------------------------------------------------------------------- - + if (atm_ozone_frequency_val == atm_ozone_frequency_unset) then - this%ozone_input_frequency = ozone_frequency_unset + this%ozone_input_frequency = ozone_frequency_unset else if (atm_ozone_frequency_val == atm_ozone_frequency_subdaily) then - this%ozone_input_frequency = ozone_frequency_subdaily + this%ozone_input_frequency = ozone_frequency_subdaily else if (atm_ozone_frequency_val == atm_ozone_frequency_multiday_average) then this%ozone_input_frequency = ozone_frequency_multiday_average else - call endrun('unknown ozone frequency') + call endrun('unknown ozone frequency') end if + + call this%InitAllocate(bounds, nsec) end subroutine Init !----------------------------------------------------------------------- + subroutine InitAllocate(this, bounds, nsec) + ! + ! !DESCRIPTION: + ! Allocate module variables and data structures + ! + ! !USES: + use shr_infnan_mod, only: nan => shr_infnan_nan, assignment(=) + ! + ! !ARGUMENTS: + class(diurnal_ozone_anom_type), intent(inout) :: this + type(bounds_type), intent(in) :: bounds + integer, intent(in) :: nsec + ! + ! LOCAL VARIABLES: + integer :: begp, endp + integer :: begc, endc + integer :: begg, endg + !--------------------------------------------------------------------- + + begp = bounds%begp; endp = bounds%endp + begc = bounds%begc; endc = bounds%endc + begg = bounds%begg; endg = bounds%endg + + allocate(this%o3_anomaly_grc(begc:endc,1:nsec)) + this%o3_anomaly_grc(:,:) = nan + + end subroutine InitAllocate + + !----------------------------------------------------------------------- - end module DiurnalOzoneType \ No newline at end of file diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index ba9eef27b4..260166afbb 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -398,11 +398,11 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & tlai_old => this%tlai_old_patch & ! Output: [real(r8) (:)] tlai from last time step ) - if (this%flag == 'multiday_average') then - call o3DiurnalAnomolyInst%interp(forc_o3, forc_o3_down) - else - forc_o3_down => forc_o3 - end if + !if (this%flag == 'multiday_average') then + ! call o3DiurnalAnomolyInst%interp(forc_o3, forc_o3_down) + !else + ! forc_o3_down => forc_o3 + !end if do fp = 1, num_exposedvegp p = filter_exposedvegp(fp) @@ -411,14 +411,14 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & ! Ozone uptake for shaded leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssha(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesha(p)) ! Ozone uptake for sunlit leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssun(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesun(p)) From 1abfed3aa60a88d5e75393380fc234b7cbb8a713 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:04:24 -0600 Subject: [PATCH 10/39] add call to shr_ozone_readnl --- src/biogeophys/DiurnalOzoneType.F90 | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 2f4ba5630a..4a00799e09 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -13,7 +13,8 @@ module DiurnalOzoneType use clm_varctl , only : iulog use abortutils , only : endrun use shr_ozone_coupling_mod , only : atm_ozone_frequency_unset, atm_ozone_frequency_subdaily, & - atm_ozone_frequency_multiday_average + atm_ozone_frequency_multiday_average, & + shr_ozone_coupling_readnl implicit none save private @@ -31,7 +32,7 @@ module DiurnalOzoneType ! Public routines procedure, public :: Init procedure, private :: InitAllocate - procedure, public :: Interp + !procedure, public :: Interp - will add this eventually end type diurnal_ozone_anom_type @@ -57,12 +58,17 @@ subroutine Init(this, bounds, nsec) ! Initialize ozone data structure ! ! - ! !ARGUMENTS: + ! ARGUMENTS: class(diurnal_ozone_anom_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds integer, intent(in) :: nsec + + ! Local variables + integer :: atom_ozone_frequency_val !----------------------------------------------------------------------- + call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) + if (atm_ozone_frequency_val == atm_ozone_frequency_unset) then this%ozone_input_frequency = ozone_frequency_unset else if (atm_ozone_frequency_val == atm_ozone_frequency_subdaily) then From eb989a4bd844873c4f6d1daca73ca7a129edd2d0 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:26:21 -0600 Subject: [PATCH 11/39] move frequency flag to OzoneModType --- src/biogeophys/DiurnalOzoneType.F90 | 25 +----------------------- src/biogeophys/OzoneMod.F90 | 30 ++++++++++++++++++++--------- 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 4a00799e09..8c6e0b05f4 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -12,9 +12,7 @@ module DiurnalOzoneType use clm_varcon , only : spval use clm_varctl , only : iulog use abortutils , only : endrun - use shr_ozone_coupling_mod , only : atm_ozone_frequency_unset, atm_ozone_frequency_subdaily, & - atm_ozone_frequency_multiday_average, & - shr_ozone_coupling_readnl + implicit none save private @@ -23,7 +21,6 @@ module DiurnalOzoneType type, public :: diurnal_ozone_anom_type private ! Private data members - integer :: ozone_input_frequency ! Which ozone input frequency are we receiving? integer :: ntimes real(r8), allocatable :: sec(:) ! seconds of day (size ntimes) real(r8), allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] @@ -36,11 +33,6 @@ module DiurnalOzoneType end type diurnal_ozone_anom_type - ! !PRIVATE TYPES: - integer, parameter :: ozone_frequency_unset = 0 - integer, parameter :: ozone_frequency_subdaily = 1 - integer, parameter :: ozone_frequency_multiday_average = 2 - character(len=*), parameter, private :: sourcefile = & __FILE__ @@ -62,23 +54,8 @@ subroutine Init(this, bounds, nsec) class(diurnal_ozone_anom_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds integer, intent(in) :: nsec - - ! Local variables - integer :: atom_ozone_frequency_val !----------------------------------------------------------------------- - call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) - - if (atm_ozone_frequency_val == atm_ozone_frequency_unset) then - this%ozone_input_frequency = ozone_frequency_unset - else if (atm_ozone_frequency_val == atm_ozone_frequency_subdaily) then - this%ozone_input_frequency = ozone_frequency_subdaily - else if (atm_ozone_frequency_val == atm_ozone_frequency_multiday_average) then - this%ozone_input_frequency = ozone_frequency_multiday_average - else - call endrun('unknown ozone frequency') - end if - call this%InitAllocate(bounds, nsec) end subroutine Init diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 260166afbb..c7f165623c 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -15,14 +15,18 @@ module OzoneMod ! ! !USES: #include "shr_assert.h" - use shr_kind_mod, only : r8 => shr_kind_r8 - use decompMod , only : bounds_type - use clm_varcon , only : spval - use clm_varctl , only : iulog - use OzoneBaseMod, only : ozone_base_type - use abortutils , only : endrun - use PatchType , only : patch - use pftconMod , only : pftcon + use shr_kind_mod , only : r8 => shr_kind_r8 + use decompMod , only : bounds_type + use clm_varcon , only : spval + use clm_varctl , only : iulog + use OzoneBaseMod , only : ozone_base_type + use abortutils , only : endrun + use PatchType , only : patch + use pftconMod , only : pftcon + use shr_ozone_coupling_mod , only : atm_ozone_frequency_unset, & + atm_ozone_frequency_subdaily, & + atm_ozone_frequency_multiday_average, & + shr_ozone_coupling_readnl implicit none save @@ -33,6 +37,7 @@ module OzoneMod private ! Private data members integer :: stress_method ! Which ozone stress parameterization we're using in this run + integer :: atm_ozone_freq ! Which ozone input frequency are we receiving? real(r8), pointer :: o3uptakesha_patch(:) ! ozone dose, shaded leaves (mmol O3/m^2) real(r8), pointer :: o3uptakesun_patch(:) ! ozone dose, sunlit leaves (mmol O3/m^2) @@ -145,8 +150,15 @@ subroutine Init(this, bounds, o3_veg_stress_method) class(ozone_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds character(len=*), intent(in) :: o3_veg_stress_method - !----------------------------------------------------------------------- + ! Local variables + integer :: atm_ozone_frequency_val + !----------------------------------------------------------------------- + + ! read what atm ozone frequency we have + call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) + this%atm_ozone_freq = atm_ozone_frequency_val + if (o3_veg_stress_method=='stress_lombardozzi2015') then this%stress_method = stress_method_lombardozzi2015 else if (o3_veg_stress_method=='stress_falk') then From 53b600891b89ae98aaec9b974078eaf986f0c5c0 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:31:00 -0600 Subject: [PATCH 12/39] typo --- src/biogeophys/DiurnalOzoneType.F90 | 6 +----- src/biogeophys/OzoneMod.F90 | 6 +++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 8c6e0b05f4..5b1cbc062f 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -76,16 +76,12 @@ subroutine InitAllocate(this, bounds, nsec) integer, intent(in) :: nsec ! ! LOCAL VARIABLES: - integer :: begp, endp - integer :: begc, endc integer :: begg, endg !--------------------------------------------------------------------- - begp = bounds%begp; endp = bounds%endp - begc = bounds%begc; endc = bounds%endc begg = bounds%begg; endg = bounds%endg - allocate(this%o3_anomaly_grc(begc:endc,1:nsec)) + allocate(this%o3_anomaly_grc(begg:endg,1:nsec)) this%o3_anomaly_grc(:,:) = nan end subroutine InitAllocate diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index c7f165623c..bb8e2c72d4 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -158,7 +158,7 @@ subroutine Init(this, bounds, o3_veg_stress_method) ! read what atm ozone frequency we have call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) this%atm_ozone_freq = atm_ozone_frequency_val - + if (o3_veg_stress_method=='stress_lombardozzi2015') then this%stress_method = stress_method_lombardozzi2015 else if (o3_veg_stress_method=='stress_falk') then @@ -423,14 +423,14 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & ! Ozone uptake for shaded leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssha(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesha(p)) ! Ozone uptake for sunlit leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3, forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssun(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesun(p)) From 46cd241e35c3e6dd95780ba973f260dce3d894c0 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:34:06 -0600 Subject: [PATCH 13/39] fix iulog error --- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index b7648320ae..fb2c67d758 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -107,9 +107,7 @@ subroutine dO3_init(diurnalOzoneAnomInst, bounds) write(iulog,'(a)') 'do3_stream settings:' write(iulog,'(a,a)' ) ' stream_fldFileName_do3 = ',trim(stream_fldFileName_dO3) write(iulog,'(a,a)' ) ' stream_meshfile_do3 = ',trim(stream_meshfile_dO3) - do n = 1,numdO3Fields - write(iulog,'(a,a)' ) ' stream_varname = ',trim(stream_varnames(n)) - end do + write(iulog,'(a,a)' ) ' stream varname = ',trim(stream_var_name) write(iulog,*) endif From 57ab73a53ed307e21bca045a43d2dd1983f9fabf Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:39:52 -0600 Subject: [PATCH 14/39] fix private issue --- src/biogeophys/DiurnalOzoneType.F90 | 6 +++--- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 5b1cbc062f..03d2cefb7f 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -21,9 +21,9 @@ module DiurnalOzoneType type, public :: diurnal_ozone_anom_type private ! Private data members - integer :: ntimes - real(r8), allocatable :: sec(:) ! seconds of day (size ntimes) - real(r8), allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] + integer :: ntimes + real(r8), allocatable :: sec(:) ! seconds of day (size ntimes) + real(r8), public, allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] contains ! Public routines diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index fb2c67d758..74cebbb325 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -50,8 +50,8 @@ subroutine dO3_init(diurnalOzoneAnomInst, bounds) ! ! ARGUMENTS: - type(diurnal_ozone_anom_type), intent(in) :: diurnalOzoneAnomInst ! instance of diurnal ozone anomaly type - type(bounds_type), intent(in) :: bounds ! bounds + type(diurnal_ozone_anom_type), intent(inout) :: diurnalOzoneAnomInst ! instance of diurnal ozone anomaly type + type(bounds_type), intent(in) :: bounds ! bounds ! ! !LOCAL VARIABLES: type(shr_strdata_type) :: sdat_dO3 ! input data stream @@ -161,7 +161,7 @@ subroutine dO3_init(diurnalOzoneAnomInst, bounds) end if ! Get pointer for stream data that is time and spatially interpolated to model time and grid - call dshr_fldbun_getFldPtr(sdat_do3%pstrm(1)%fldbun_model, trim(stream_var_name), fldptr2=dataptr2d, rc=rc) + call dshr_fldbun_getFldPtr(sdat_dO3%pstrm(1)%fldbun_model, trim(stream_var_name), fldptr2=dataptr2d, rc=rc) if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) then call ESMF_Finalize(endflag=ESMF_END_ABORT) end if From 56792c2973ed2512acb22f2f88dbdd5f4e057d43 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:42:25 -0600 Subject: [PATCH 15/39] fix use statement --- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 74cebbb325..1c766bffb2 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -46,7 +46,7 @@ subroutine dO3_init(diurnalOzoneAnomInst, bounds) use lnd_comp_shr , only : mesh, model_clock use dshr_strdata_mod , only : shr_strdata_init_from_inline, shr_strdata_print use dshr_strdata_mod , only : shr_strdata_advance - use dshr_methods_mod , only : dshr_field_getfldptr + use dshr_methods_mod , only : dshr_fldbun_getfldptr ! ! ARGUMENTS: From 67d01db7f2d437ff86b83eb22e902aafa05428e3 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:55:02 -0600 Subject: [PATCH 16/39] add init call --- src/biogeophys/DiurnalOzoneType.F90 | 35 ++++++++++++++++---- src/biogeophys/OzoneMod.F90 | 8 ++++- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 6 ++-- 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 03d2cefb7f..850bad21ee 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -12,6 +12,7 @@ module DiurnalOzoneType use clm_varcon , only : spval use clm_varctl , only : iulog use abortutils , only : endrun + use diurnalOzoneStreamMod , only : read_O3_stream implicit none save @@ -21,7 +22,7 @@ module DiurnalOzoneType type, public :: diurnal_ozone_anom_type private ! Private data members - integer :: ntimes + integer :: ntimes = 24 real(r8), allocatable :: sec(:) ! seconds of day (size ntimes) real(r8), public, allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] @@ -29,6 +30,7 @@ module DiurnalOzoneType ! Public routines procedure, public :: Init procedure, private :: InitAllocate + procedure, private :: ReadInStream !procedure, public :: Interp - will add this eventually end type diurnal_ozone_anom_type @@ -44,7 +46,7 @@ module DiurnalOzoneType ! ======================================================================== !----------------------------------------------------------------------- - subroutine Init(this, bounds, nsec) + subroutine Init(this, bounds, ntimes) ! ! DESCRIPTION: ! Initialize ozone data structure @@ -53,16 +55,17 @@ subroutine Init(this, bounds, nsec) ! ARGUMENTS: class(diurnal_ozone_anom_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds - integer, intent(in) :: nsec + integer, intent(in) :: ntimes !----------------------------------------------------------------------- call this%InitAllocate(bounds, nsec) + call this%ReadInStream(bounds) end subroutine Init !----------------------------------------------------------------------- - subroutine InitAllocate(this, bounds, nsec) + subroutine InitAllocate(this, bounds, ntimes) ! ! !DESCRIPTION: ! Allocate module variables and data structures @@ -73,7 +76,7 @@ subroutine InitAllocate(this, bounds, nsec) ! !ARGUMENTS: class(diurnal_ozone_anom_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds - integer, intent(in) :: nsec + integer, intent(in) :: ntimes ! ! LOCAL VARIABLES: integer :: begg, endg @@ -81,12 +84,30 @@ subroutine InitAllocate(this, bounds, nsec) begg = bounds%begg; endg = bounds%endg - allocate(this%o3_anomaly_grc(begg:endg,1:nsec)) - this%o3_anomaly_grc(:,:) = nan + allocate(this%o3_anomaly_grc(begg:endg,1:ntimes)); this%o3_anomaly_grc(:,:) = nan end subroutine InitAllocate !----------------------------------------------------------------------- + subroutine ReadInStream(this, bounds) + ! + ! DESCRIPTION: + ! Read in stream data from + ! + ! !USES: + use shr_infnan_mod, only: nan => shr_infnan_nan, assignment(=) + ! + ! !ARGUMENTS: + class(diurnal_ozone_anom_type), intent(inout) :: this + type(bounds_type), intent(in) :: bounds + !--------------------------------------------------------------------- + + read_O3_stream(this, bounds) + + end subroutine ReadInStream + + !----------------------------------------------------------------------- + end module DiurnalOzoneType \ No newline at end of file diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index bb8e2c72d4..bb6b88ca6f 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -27,6 +27,7 @@ module OzoneMod atm_ozone_frequency_subdaily, & atm_ozone_frequency_multiday_average, & shr_ozone_coupling_readnl + use DiurnalOzoneType , only : diurnal_ozone_anom_type implicit none save @@ -58,7 +59,8 @@ module OzoneMod ! Then the setter method would also set tlai_old. This feels like the most robust ! solution, but we don't have any precedent for using getters and setters for data ! arrays. - real(r8), pointer :: tlai_old_patch(:) ! tlai from last time step + real(r8), pointer :: tlai_old_patch(:) ! tlai from last time step + type(diurnal_ozone_anom_type) :: diurnalOzoneAnomInst contains ! Public routines @@ -159,6 +161,10 @@ subroutine Init(this, bounds, o3_veg_stress_method) call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) this%atm_ozone_freq = atm_ozone_frequency_val + if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then + this%diurnalOzoneAnomInst%Init + end if + if (o3_veg_stress_method=='stress_lombardozzi2015') then this%stress_method = stress_method_lombardozzi2015 else if (o3_veg_stress_method=='stress_falk') then diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 1c766bffb2..3349235fb3 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -23,7 +23,7 @@ module diurnalOzoneStreamMod private ! PUBLIC MEMBER FUNCTIONS: - public :: dO3_init ! position dataset for diurnal ozone anomaly + public :: read_O3_stream ! position dataset for diurnal ozone anomaly character(len=*), parameter :: sourcefile = & __FILE__ @@ -33,7 +33,7 @@ module diurnalOzoneStreamMod !============================================================================== - subroutine dO3_init(diurnalOzoneAnomInst, bounds) + subroutine read_O3_stream(diurnalOzoneAnomInst, bounds) ! ! Initialize data stream information for LAI. ! @@ -184,7 +184,7 @@ subroutine dO3_init(diurnalOzoneAnomInst, bounds) end do end do - end subroutine dO3_init + end subroutine read_O3_stream !============================================================================== From 1e1a5401772d03381ccdda46f63ef9b9b29d1c11 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 13:57:33 -0600 Subject: [PATCH 17/39] remove ntimes --- src/biogeophys/DiurnalOzoneType.F90 | 10 ++++------ src/biogeophys/OzoneMod.F90 | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 850bad21ee..4b9361d6a1 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -46,7 +46,7 @@ module DiurnalOzoneType ! ======================================================================== !----------------------------------------------------------------------- - subroutine Init(this, bounds, ntimes) + subroutine Init(this, bounds) ! ! DESCRIPTION: ! Initialize ozone data structure @@ -55,17 +55,16 @@ subroutine Init(this, bounds, ntimes) ! ARGUMENTS: class(diurnal_ozone_anom_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds - integer, intent(in) :: ntimes !----------------------------------------------------------------------- - call this%InitAllocate(bounds, nsec) + call this%InitAllocate(bounds) call this%ReadInStream(bounds) end subroutine Init !----------------------------------------------------------------------- - subroutine InitAllocate(this, bounds, ntimes) + subroutine InitAllocate(this, bounds) ! ! !DESCRIPTION: ! Allocate module variables and data structures @@ -76,7 +75,6 @@ subroutine InitAllocate(this, bounds, ntimes) ! !ARGUMENTS: class(diurnal_ozone_anom_type), intent(inout) :: this type(bounds_type), intent(in) :: bounds - integer, intent(in) :: ntimes ! ! LOCAL VARIABLES: integer :: begg, endg @@ -84,7 +82,7 @@ subroutine InitAllocate(this, bounds, ntimes) begg = bounds%begg; endg = bounds%endg - allocate(this%o3_anomaly_grc(begg:endg,1:ntimes)); this%o3_anomaly_grc(:,:) = nan + allocate(this%o3_anomaly_grc(begg:endg,1:this%ntimes)); this%o3_anomaly_grc(:,:) = nan end subroutine InitAllocate diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index bb6b88ca6f..2fdd38a5cf 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -162,7 +162,7 @@ subroutine Init(this, bounds, o3_veg_stress_method) this%atm_ozone_freq = atm_ozone_frequency_val if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then - this%diurnalOzoneAnomInst%Init + this%diurnalOzoneAnomInst%Init(bounds) end if if (o3_veg_stress_method=='stress_lombardozzi2015') then From ce71f954606466b6a08646d3c83121976eac9d04 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 14:10:52 -0600 Subject: [PATCH 18/39] checking includes --- src/biogeophys/DiurnalOzoneType.F90 | 1 - src/biogeophys/OzoneMod.F90 | 13 +++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 4b9361d6a1..bd209c9867 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -23,7 +23,6 @@ module DiurnalOzoneType private ! Private data members integer :: ntimes = 24 - real(r8), allocatable :: sec(:) ! seconds of day (size ntimes) real(r8), public, allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] contains diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 2fdd38a5cf..f43ebfb30e 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -23,10 +23,7 @@ module OzoneMod use abortutils , only : endrun use PatchType , only : patch use pftconMod , only : pftcon - use shr_ozone_coupling_mod , only : atm_ozone_frequency_unset, & - atm_ozone_frequency_subdaily, & - atm_ozone_frequency_multiday_average, & - shr_ozone_coupling_readnl + use shr_ozone_coupling_mod , only : atm_ozone_frequency_multiday_average, shr_ozone_coupling_readnl use DiurnalOzoneType , only : diurnal_ozone_anom_type implicit none @@ -60,7 +57,7 @@ module OzoneMod ! solution, but we don't have any precedent for using getters and setters for data ! arrays. real(r8), pointer :: tlai_old_patch(:) ! tlai from last time step - type(diurnal_ozone_anom_type) :: diurnalOzoneAnomInst + !type(diurnal_ozone_anom_type) :: diurnalOzoneAnomInst contains ! Public routines @@ -161,9 +158,9 @@ subroutine Init(this, bounds, o3_veg_stress_method) call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) this%atm_ozone_freq = atm_ozone_frequency_val - if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then - this%diurnalOzoneAnomInst%Init(bounds) - end if + !if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then + ! this%diurnalOzoneAnomInst%Init(bounds) + !end if if (o3_veg_stress_method=='stress_lombardozzi2015') then this%stress_method = stress_method_lombardozzi2015 From ab88f6a4c56d5836b788f6edf5fb07e42dab0fd1 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 14:23:59 -0600 Subject: [PATCH 19/39] typo fix? --- src/biogeophys/OzoneMod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index f43ebfb30e..1fc0427dfa 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -24,7 +24,7 @@ module OzoneMod use PatchType , only : patch use pftconMod , only : pftcon use shr_ozone_coupling_mod , only : atm_ozone_frequency_multiday_average, shr_ozone_coupling_readnl - use DiurnalOzoneType , only : diurnal_ozone_anom_type + use diurnalOzoneType , only : diurnal_ozone_anom_type implicit none save From 734ea152f02db214204527a6bc361fba3c0ce9d9 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 13 Sep 2022 14:30:29 -0600 Subject: [PATCH 20/39] update ozone type name --- src/biogeophys/OzoneMod.F90 | 2 +- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 1fc0427dfa..f43ebfb30e 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -24,7 +24,7 @@ module OzoneMod use PatchType , only : patch use pftconMod , only : pftcon use shr_ozone_coupling_mod , only : atm_ozone_frequency_multiday_average, shr_ozone_coupling_readnl - use diurnalOzoneType , only : diurnal_ozone_anom_type + use DiurnalOzoneType , only : diurnal_ozone_anom_type implicit none save diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 3349235fb3..66acc3c3cd 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -15,7 +15,7 @@ module diurnalOzoneStreamMod use clm_varctl , only : iulog use abortutils , only : endrun use decompMod , only : bounds_type - use diurnalOzoneType , only : diurnal_ozone_anom_type + use DiurnalOzoneType , only : diurnal_ozone_anom_type ! ! PUBLIC TYPES: From 56171953b8b1ed545d1a232459119434aff79b5b Mon Sep 17 00:00:00 2001 From: adrifoster Date: Fri, 16 Sep 2022 10:07:24 -0600 Subject: [PATCH 21/39] fix circular dependency --- src/biogeophys/DiurnalOzoneType.F90 | 24 +----------------------- src/biogeophys/OzoneMod.F90 | 14 +++++++++----- 2 files changed, 10 insertions(+), 28 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index bd209c9867..46bf3e619c 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -12,7 +12,6 @@ module DiurnalOzoneType use clm_varcon , only : spval use clm_varctl , only : iulog use abortutils , only : endrun - use diurnalOzoneStreamMod , only : read_O3_stream implicit none save @@ -29,7 +28,6 @@ module DiurnalOzoneType ! Public routines procedure, public :: Init procedure, private :: InitAllocate - procedure, private :: ReadInStream !procedure, public :: Interp - will add this eventually end type diurnal_ozone_anom_type @@ -57,8 +55,7 @@ subroutine Init(this, bounds) !----------------------------------------------------------------------- call this%InitAllocate(bounds) - call this%ReadInStream(bounds) - + end subroutine Init @@ -87,24 +84,5 @@ end subroutine InitAllocate !----------------------------------------------------------------------- - subroutine ReadInStream(this, bounds) - ! - ! DESCRIPTION: - ! Read in stream data from - ! - ! !USES: - use shr_infnan_mod, only: nan => shr_infnan_nan, assignment(=) - ! - ! !ARGUMENTS: - class(diurnal_ozone_anom_type), intent(inout) :: this - type(bounds_type), intent(in) :: bounds - !--------------------------------------------------------------------- - - read_O3_stream(this, bounds) - - end subroutine ReadInStream - - !----------------------------------------------------------------------- - end module DiurnalOzoneType \ No newline at end of file diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index f43ebfb30e..ab2b6db62b 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -25,6 +25,7 @@ module OzoneMod use pftconMod , only : pftcon use shr_ozone_coupling_mod , only : atm_ozone_frequency_multiday_average, shr_ozone_coupling_readnl use DiurnalOzoneType , only : diurnal_ozone_anom_type + use diurnalOzoneStreamMod , only : read_O3_stream implicit none save @@ -57,7 +58,7 @@ module OzoneMod ! solution, but we don't have any precedent for using getters and setters for data ! arrays. real(r8), pointer :: tlai_old_patch(:) ! tlai from last time step - !type(diurnal_ozone_anom_type) :: diurnalOzoneAnomInst + type(diurnal_ozone_anom_type) :: diurnalOzoneAnomInst contains ! Public routines @@ -157,10 +158,13 @@ subroutine Init(this, bounds, o3_veg_stress_method) ! read what atm ozone frequency we have call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) this%atm_ozone_freq = atm_ozone_frequency_val - - !if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then - ! this%diurnalOzoneAnomInst%Init(bounds) - !end if + + ! if we have multi-day average input ozone, we need to convert to sub-daily using + ! an input anomaly file + if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then + call this%diurnalOzoneAnomInst%Init(bounds) + call read_O3_stream(this%diurnalOzoneAnomInst, bounds) + end if if (o3_veg_stress_method=='stress_lombardozzi2015') then this%stress_method = stress_method_lombardozzi2015 From 09d3c2f599365784210af5ef572b0cc6a30bace3 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Tue, 27 Sep 2022 08:45:51 -0600 Subject: [PATCH 22/39] adding introplation --- src/biogeophys/DiurnalOzoneType.F90 | 39 ++++++++++++++++++++ src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 4 +- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 46bf3e619c..7d61b2df92 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -84,5 +84,44 @@ end subroutine InitAllocate !----------------------------------------------------------------------- + !----------------------------------------------------------------------- + subroutine Interp(this, bounds, forc_o3, forc_o3_down) + ! + ! !DESCRIPTION: + ! Allocate module variables and data structures + ! + ! !USES: + use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) + use clm_time_manager , only : get_curr_time + ! + ! !ARGUMENTS: + class(diurnal_ozone_anom_type), intent(in) :: this + type(bounds_type), intent(in) :: bounds + real(r8), intent(in) :: forc_o3( bounds%begg: ) ! ozone partial pressure (mol/mol) + real(r8), intent(out) :: forc_o3_down( bounds%begg: ) ! ozone partial pressure, downscaled (mol/mol) + ! + ! LOCAL VARIABLES: + integer :: j ! time stamp to grab + integer :: yr ! year + integer :: mon ! month + integer :: day ! day of month + integer :: tod ! time of day (seconds past 0Z) + integer :: begg, endg + !----------------------------------------------------------------------- + + begg = bounds%begg; endg = bounds%endg + + ! Get current date/time - we really only need seconds + call get_curr_date(yr, mon, day, tod) + + !! interpolate here! + + ! apply anomaly + forc_o3_down(begg:endg) = forc_o3(begg:eng)*this%o3_anomaly_grc(begg:endg, j) + + end subroutine Interp + + !----------------------------------------------------------------------- + end module DiurnalOzoneType \ No newline at end of file diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 66acc3c3cd..10f2b41958 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -23,7 +23,7 @@ module diurnalOzoneStreamMod private ! PUBLIC MEMBER FUNCTIONS: - public :: read_O3_stream ! position dataset for diurnal ozone anomaly + public :: read_O3_stream ! read dataset for diurnal ozone anomaly character(len=*), parameter :: sourcefile = & __FILE__ @@ -166,7 +166,7 @@ subroutine read_O3_stream(diurnalOzoneAnomInst, bounds) call ESMF_Finalize(endflag=ESMF_END_ABORT) end if - ! Check that inner most dimension of dataptr2d is equal to nlevsoi + ! Check that inner most dimension of dataptr2d is equal to nlevsec if (size(dataptr2d,dim=1) /= nlevsec) then if (masterproc) then write(iulog,*) 'ERROR: dataptr2d(dim=1) = ',size(dataptr2d,dim=1),& From f214f1293c14b8353e918a7dc2cc1bbb83a3e9af Mon Sep 17 00:00:00 2001 From: adrifoster Date: Wed, 28 Sep 2022 14:06:22 -0600 Subject: [PATCH 23/39] lots of updates, design doc --- src/main/test/CESM_Macros.cmake | 67 +++++++++++++++++++++++++++++++++ src/main/test/Makefile.utest | 41 ++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 src/main/test/CESM_Macros.cmake create mode 100644 src/main/test/Makefile.utest diff --git a/src/main/test/CESM_Macros.cmake b/src/main/test/CESM_Macros.cmake new file mode 100644 index 0000000000..ba207ff55a --- /dev/null +++ b/src/main/test/CESM_Macros.cmake @@ -0,0 +1,67 @@ +# CESM build flags for: +# Compiler = gnu: +# Machine = roo2: +# OS = Mac OS X: + +# ================================================== +# Compilers +# ================================================== + +set(CMAKE_Fortran_COMPILER mpif90) +set(CMAKE_C_COMPILER mpicc) + +# ================================================== +# pFUnit location. +# ================================================== + +list(APPEND CMAKE_PREFIX_PATH /usr/local/pfunit/pfunit-mpi) +include(Compilers) + +# ================================================== +# Flags needed for linking netcdf (needed for some drv unit tests) +# ================================================== + +set(NETCDF_DIR "/usr/local") + +# The following is a hack to get cmake to link in hdf5, because there does not +# appear to be a find package script for hdf5: +set(CMAKE_EXE_LINKER_FLAGS "-lhdf5_hl") +include_directories("/usr/local/include") +link_directories("/usr/local/lib") + +# The following is needed so that the above include_directories are listed after +# any include_directories specified by the top-level CMakeLists.txt +set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON) + + +# ================================================== +# CPP definitions. +# ================================================== + +add_config_definitions(CESM -DFORTRANUNDERSCORE -DNO_R16) +add_config_definitions(CESM -DHAVE_NANOTIME ) +add_config_definitions(CESM_DEBUG -DFORTRANUNDERSCORE -DNO_R16) +add_config_definitions(CESM_DEBUG -DHAVE_NANOTIME ) +add_definitions(-DSYSDARWIN) +# For gnu, define USE_CONTIGUOUS as empty (at least some versions of gnu don't +# have support for 'contiguous') +add_definitions(-DUSE_CONTIGUOUS= ) + +# ================================================== +# Fortran flags. +# ================================================== +add_flags(CMAKE_Fortran_FLAGS_CESM -fopenmp -fconvert=big-endian -ffree-line-length-none -ffixed-line-length-none) +add_flags(CMAKE_Fortran_FLAGS_CESM -O2 ) +add_flags(CMAKE_Fortran_FLAGS_CESM_DEBUG -fopenmp -fconvert=big-endian -ffree-line-length-none -ffixed-line-length-none -fno-range-check -fall-intrinsics -ffpe-trap=zero,overflow -fcheck=bounds) +add_flags(CMAKE_Fortran_FLAGS_CESM_DEBUG -O0 -g) + +# ================================================== +# C flags. +# ================================================== + +add_flags(CMAKE_C_FLAGS_CESM -fopenmp -O2) +add_flags(CMAKE_C_FLAGS_CESM_DEBUG -fopenmp -O0) + +# ================================================== +# Linker flags. +# ================================================== diff --git a/src/main/test/Makefile.utest b/src/main/test/Makefile.utest new file mode 100644 index 0000000000..c678e613e8 --- /dev/null +++ b/src/main/test/Makefile.utest @@ -0,0 +1,41 @@ +# -*- mode: makefile -*- + +ifndef CIMEROOT + $(error Must set variable CIMEROOT) +endif + +CIMEROOT_ABSPATH := $(realpath $(CIMEROOT)) + +TEST_ROOT=$(shell pwd) + +CESM_CMAKE_UTILS=$(CIMEROOT_ABSPATH)/externals/CMake +GENF90=$(CIMEROOT_ABSPATH)/externals/genf90 + +DEBUG_CMAKE= +#DEBUG_CMAKE=--debug-output --trace + +config : clean + mkdir -p build + cp CESM_Macros.cmake build/ + cd build && cmake \ + $(DEBUG_CMAKE) \ + -Wdev \ + -DENABLE_GENF90=ON \ + -DCMAKE_PROGRAM_PATH=$(GENF90) \ + -DCMAKE_BUILD_TYPE=CESM_DEBUG \ + -DCESM_CMAKE_MODULE_DIRECTORY=$(CESM_CMAKE_UTILS) \ + $(TEST_ROOT) + +test : all + @if [ -d ./build ]; then \ + $(MAKE) --directory=build $@; \ + fi + +all : + @if [ -d ./build ]; then \ + $(MAKE) --directory=build $@; \ + fi + + +clean : + rm -rf *~ build From 06a62712a5f3784921f0981181e3b5037cfbdb8e Mon Sep 17 00:00:00 2001 From: adrifoster Date: Wed, 28 Sep 2022 14:12:46 -0600 Subject: [PATCH 24/39] add design doc --- doc/design/design_doc_diurnal_ozone.md | 106 +++++++++++++++++++ src/biogeophys/DiurnalOzoneType.F90 | 60 +++++++---- src/biogeophys/OzoneMod.F90 | 21 ++-- src/cpl/share_esmf/diurnalOzoneStreamMod.F90 | 35 ++++-- src/main/circle.F90 | 22 ++++ 5 files changed, 204 insertions(+), 40 deletions(-) create mode 100644 doc/design/design_doc_diurnal_ozone.md create mode 100644 src/main/circle.F90 diff --git a/doc/design/design_doc_diurnal_ozone.md b/doc/design/design_doc_diurnal_ozone.md new file mode 100644 index 0000000000..43c552d535 --- /dev/null +++ b/doc/design/design_doc_diurnal_ozone.md @@ -0,0 +1,106 @@ +# Software Design Documentation + +Project Name + + +**Date:**: 09/27/22 + +**Written By**: Adrianna Foster (@adrifoster) + +## Introduction +--------------------------------------- + +As laid out in CTSM Issue [#270](https://github.com/ESCOMP/CTSM/issues/270) we want to downscale input ozone partial pressure (mol/mol) temporally if we receive a multi-day average input ozone (usually in DATM mode). + +We have the infrastructure laid out for CAM and DATM to inform CTSM which type of input we are receiving (i.e., 'multiday_average' or 'subdaily'). We should only apply this downscaling when receiving multiday average ozone. + +We have a gridded file provided by Louisa Emmons for a diurnal ozone variation factor. The data is additionally dimensioned by 'secs' (seconds of day), and depending on the model time of day, can be used as a multiplicative factor for converting multi-day average ozone to sub-daily ozone partial pressure. + +## Solutions +--------------------------------------- + +Read in the diurnal anomaly file as a streams file, being careful to not assume too much so that other files may be provided in the future. Create a diurnal ozone type that has an `Interp` method to downscale and interpolate multi-day average ozone data to sub-daily based on a factor attribute. Inside the existing `CalcOzoneUptake` routine, if we are using multi-day average ozone, interpolate/downscale the `forc_o3` array using the `Interp` subroutine. + +**Some alternate ideas**: +1. have the existing `ozone_type` type have this diurnal ozone anomaly type as an attribute that gets initiated only if we are reading in multi-day average ozone. +2. have the diurnal ozone type be fed into relevant `ozone_type` methods as arguments. We would only want to do this if other modules are going to use the diurnal ozone type. This has a possibility, but no clear plans are on the horizon for it. + +**Consider going with the first solution for now** + +## Design Considerations +--------------------------------------- + +### Assumptions and Dependencies: + +Right now we are assuming that the units of the input diurnal file are going to be in seconds, and that the file covers the whole day. + +There is no need to assume that the dimension will be 1-24 (i.e. on the hour) or that the dimensions be equal intervals. + + +## Design and Architecture +--------------------------------------- + +### System diagram or flowchart + +#### Diurnal Factor Streams File + +We need to read in the diurnal ozone factor file provided by Louisa Emmons as a streams file. Some modifications are required on the file so that it can be accurately read and parsed by ESMF and to facilitate our chosen implementation strategy: + +1. Add a new 'time' variable (even though the data is not dimensioned by time, except for seconds of day) so that ESMF can parse it. The date is arbitrarily set to 2000-01-01, and the dimensions are set to 'UNLIMITED'. + +2. Shift the 'secs' array up 1800 seconds so that it provides the midpoint of the averaged time interval, rather than the beginning. This conversion is done to facilitate interpolation between the time-of-day dimensions. + +These file modifications can be seen in the Jupyter notebook /glade/u/home/afoster/Diurnal_ozone.ipynb. + +The file is read in using a new `src/share_esmf/diurnalOzoneStreamMod` module, with associated updates to `bld/CLMBuildNamelist.pm`, `bld/namelist_files/namelist_defaults_ctsm.xml` and `bld/namelist_files/namelist_definition_csvm.xml` + +Right now the new variable `use_do3_streams` is set in the `user_nl_clm` file. And the other namelist variables (`stream_fldfilename_do3`, `stream_meshfile_do3`, and `do3_mapalgo`) are inside the `lnd_in` file under a `do3_streams` namelist. + +**I'm not sure setting up the `use_do3_streams` namelist variable is the best way to go about this, since we essentially want this feature on whenever the ozone frequency is 'multiday_average'** + +Right now we are hard-coding the `stream_var_name`, and `stream_lev_dimname`. I think this is okay. Otherwise, we would want them to be namelist variables that get read in. + +Because the diurnal anomaly file is not dimensioned by time other than seconds of day, we just need to read it in and advance one time. This is all currently done in the `diurnalOzoneStreamMod`'s `read_O3_stream` subroutine. We set the date to an arbitrary date (the same as on the file, I'm not sure if this is necessary?). + +We also need to grab the `secs` array to do interpolation/downscaling with. + +Both are read from the file and then an instance of `diurnal_ozone_anom_type` is initialized and relevant arrays are set to the ozone factor and seconds data. + +### Diurnal Ozone Anomaly Type + +The module `DiurnalOzoneType` sets up a `diurnal_ozone_anom_type` which has only a few attributes and methods: + +**Attributes**: +1. `ntimes` - size of time/seconds-of-day dimension (private) +2. `o3_anomaly_grc` - o3 anomaly data, 2d, gridcells x ntimes +3. `time_arr` - time/seconds of day array, 1d, ntimes + +**Methods**: +1. `Init` - Initializes the anomaly data structures, calls `InitAllocate` +2. `InitAllocate` - allocates arrays and sets them to nan +3. `Interp` - Interpolates/downscales an input multi-day average ozone (`forc_o3`) using the o3 anomaly data and outputs a downscaled `forc_o3_down` array. See below for `Interp` algorithm/pseudo code + +### Implementation within OzoneMod + +We add an instance of the `diurnal_ozone_anom_type` as an attribute of the `ozone_base_type`. + +Within the `Init` method of the `ozone_base_type`, we read the `drv_flds_in` file to get the `atom_ozone_frequency_val`. If this value is `atm_ozone_frequency_multiday_average` then we initialize and read in the o3 anomaly data by calling the `read_O3_stream` described above. *Do we need an else decision here?* + +We also add an integer `atm_ozone_freq` as a new attribute, and set it in `Init`. + +Within the `CalcOzoneUptake` method, we check for the `atm_ozone_freq` flag and if it is `atm_ozone_frequency_multiday_average` we call the `Interp` method. + +### Algorithm and Pseudo code for Interp + + + +## Rollout Plan +--------------------------------------- +Define the roll-out phases and tests you plan to do + + +## Review Sign-off +--------------------------------------- +* Reviewer(s): + +*Sign-off Completed on YYYY-MM-DD* diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 7d61b2df92..d09ba32854 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -21,14 +21,15 @@ module DiurnalOzoneType type, public :: diurnal_ozone_anom_type private ! Private data members - integer :: ntimes = 24 - real(r8), public, allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] + integer :: ntimes ! size of time dimension + real(r8), public, allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] + real(r8), public, allocatable :: time_arr(:) ! time dimension (units = seconds of day) contains ! Public routines procedure, public :: Init procedure, private :: InitAllocate - !procedure, public :: Interp - will add this eventually + procedure, public :: Interp end type diurnal_ozone_anom_type @@ -43,17 +44,22 @@ module DiurnalOzoneType ! ======================================================================== !----------------------------------------------------------------------- - subroutine Init(this, bounds) + subroutine Init(this, bounds, n) ! ! DESCRIPTION: - ! Initialize ozone data structure + ! Initialize ozone anomaly data structures ! ! ! ARGUMENTS: class(diurnal_ozone_anom_type), intent(inout) :: this - type(bounds_type), intent(in) :: bounds + type(bounds_type), intent(in) :: bounds + integer, intent(in) :: n !----------------------------------------------------------------------- + ! set ntimes from input + this%ntimes = n + + ! allocate arrays call this%InitAllocate(bounds) end subroutine Init @@ -79,45 +85,61 @@ subroutine InitAllocate(this, bounds) begg = bounds%begg; endg = bounds%endg allocate(this%o3_anomaly_grc(begg:endg,1:this%ntimes)); this%o3_anomaly_grc(:,:) = nan + allocate(this%time_arr(1:this%ntimes)); this%time_arr(:) = nan end subroutine InitAllocate !----------------------------------------------------------------------- !----------------------------------------------------------------------- - subroutine Interp(this, bounds, forc_o3, forc_o3_down) + subroutine Interp(this, forc_o3, forc_o3_down) ! ! !DESCRIPTION: - ! Allocate module variables and data structures + ! Downscale/interpolate multi-day ozone data to subdaily ! ! !USES: - use shr_infnan_mod, only : nan => shr_infnan_nan, assignment(=) use clm_time_manager , only : get_curr_time ! ! !ARGUMENTS: - class(diurnal_ozone_anom_type), intent(in) :: this - type(bounds_type), intent(in) :: bounds + class(diurnal_ozone_anom_type), intent(in) :: this real(r8), intent(in) :: forc_o3( bounds%begg: ) ! ozone partial pressure (mol/mol) real(r8), intent(out) :: forc_o3_down( bounds%begg: ) ! ozone partial pressure, downscaled (mol/mol) ! ! LOCAL VARIABLES: - integer :: j ! time stamp to grab + integer :: i ! looping index integer :: yr ! year integer :: mon ! month integer :: day ! day of month integer :: tod ! time of day (seconds past 0Z) - integer :: begg, endg !----------------------------------------------------------------------- - begg = bounds%begg; endg = bounds%endg - ! Get current date/time - we really only need seconds call get_curr_date(yr, mon, day, tod) - !! interpolate here! - - ! apply anomaly - forc_o3_down(begg:endg) = forc_o3(begg:eng)*this%o3_anomaly_grc(begg:endg, j) + ! find the time interval we are in + do i = 1, this%ntimes + if (real(tod) <= this%time_arr(i)) then + exit + end if + end do + + ! interpolate, checking for edge cases + if (i == 1) then + ! wrap around to front + forc_o3_down(:) = forc_o3(:)*((this%o3_anomaly_grc(:,this%ntimes)* & + (this%time_arr(i) - real(tod)) + & + this%o3_anomaly_grc(:,i)*((86400.0 - this%time_arr(this%ntimes)) + real(tod)))/ & + (this%time_arr(i) + (86400.0 - this%time_arr(this%ntimes)))) + else + ! interpolate normally + forc_o3_down(:) = forc_o3(:)*((this%o3_anomaly_grc(:,i-1)* & + (this%time_arr(i) - real(tod)) + & + this%o3_anomaly_grc(:,i)*(real(tod) - this%time_arr(i-1)))/ & + (this%time_arr(i) - this%time_arr(i-1))) + end if + + + end subroutine Interp diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index ab2b6db62b..5713bcbdd3 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -162,7 +162,7 @@ subroutine Init(this, bounds, o3_veg_stress_method) ! if we have multi-day average input ozone, we need to convert to sub-daily using ! an input anomaly file if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then - call this%diurnalOzoneAnomInst%Init(bounds) + ! initialize and read in data for diurnal O3 anomaly stream call read_O3_stream(this%diurnalOzoneAnomInst, bounds) end if @@ -393,10 +393,11 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & real(r8) , intent(in) :: forc_o3( bounds%begg: ) ! ozone partial pressure (mol/mol) ! ! !LOCAL VARIABLES: - integer :: fp ! filter index - integer :: p ! patch index - integer :: c ! column index - integer :: g ! gridcell index + real(r8), pointer :: forc_o3_down( bounds%begg: ) ! downscaled ozone partial pressure (mol/mol) + integer :: fp ! filter index + integer :: p ! patch index + integer :: c ! column index + integer :: g ! gridcell index character(len=*), parameter :: subname = 'CalcOzoneUptake' !----------------------------------------------------------------------- @@ -417,11 +418,11 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & tlai_old => this%tlai_old_patch & ! Output: [real(r8) (:)] tlai from last time step ) - !if (this%flag == 'multiday_average') then - ! call o3DiurnalAnomolyInst%interp(forc_o3, forc_o3_down) - !else - ! forc_o3_down => forc_o3 - !end if + if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then + call this%diurnalOzoneAnomInst%Interp(forc_o3, forc_o3_down) + else + forc_o3_down = forc_o3 + end if do fp = 1, num_exposedvegp p = filter_exposedvegp(fp) diff --git a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 index 10f2b41958..abbb8bac02 100644 --- a/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 +++ b/src/cpl/share_esmf/diurnalOzoneStreamMod.F90 @@ -47,6 +47,7 @@ subroutine read_O3_stream(diurnalOzoneAnomInst, bounds) use dshr_strdata_mod , only : shr_strdata_init_from_inline, shr_strdata_print use dshr_strdata_mod , only : shr_strdata_advance use dshr_methods_mod , only : dshr_fldbun_getfldptr + use ncdio_pio , only : file_desc_t, ncd_pio_openfile, ncd_io ! ! ARGUMENTS: @@ -55,7 +56,9 @@ subroutine read_O3_stream(diurnalOzoneAnomInst, bounds) ! ! !LOCAL VARIABLES: type(shr_strdata_type) :: sdat_dO3 ! input data stream + type(file_desc_t) :: ncid ! netcdf file id real(r8), pointer :: dataptr2d(:,:) ! first dimension is level, second is data on that level + real(r8), pointer :: secs(:) ! time-of-day (units = seconds) dimension on file integer :: ig, g, j ! indices integer :: nu_nml ! unit for namelist file integer :: nml_error ! namelist i/o error flag @@ -65,11 +68,12 @@ subroutine read_O3_stream(diurnalOzoneAnomInst, bounds) integer :: sec ! seconds into current date for nstep+1 integer :: mcdate ! current model date (yyyymmdd) integer :: rc ! error code - integer, parameter :: nlevsec = 24 ! number of hours in day + integer :: nlevsec ! dimension of 'secs' variable integer, allocatable :: g_to_ig(:) ! array matching gridcell index to data index + logical :: readvar character(len=CL) :: stream_fldFileName_dO3 = ' ' ! diurnal ozone stream filename to read character(len=CL) :: stream_meshfile_dO3 = ' ' ! diurnal ozone stream meshfile - character(len=CL) :: dO3_mapalgo = 'bilinear' ! mapping alogrithm + character(len=CL) :: dO3_mapalgo = ' ' ! mapping alogrithm character(len=CL) :: stream_lev_dimname = 'sec' ! name of vertical layer dimension character(*), parameter :: stream_var_name = "O3_diurnal_factor" ! base string for field string character(len=*), parameter :: subName = "('dO3_init')" @@ -166,17 +170,21 @@ subroutine read_O3_stream(diurnalOzoneAnomInst, bounds) call ESMF_Finalize(endflag=ESMF_END_ABORT) end if - ! Check that inner most dimension of dataptr2d is equal to nlevsec - if (size(dataptr2d,dim=1) /= nlevsec) then - if (masterproc) then - write(iulog,*) 'ERROR: dataptr2d(dim=1) = ',size(dataptr2d,dim=1),& - ' and nlevsec = ',nlevsec,' must match ' - end if - call endrun(trim(subname) // & - ' ERROR:: The input diurnal ozone anomaly stream does not have levels equal to nlevsec') + ! set the nlevsec size + nlevsec = size(dataptr2d, dim=1) + + ! read in the seconds array as well + allocate(secs(nlevsec)) + call ncd_pio_openfile(ncid, trim(stream_fldFileName_dO3), 0) + call ncd_io(ncid=ncid, varname=trim(stream_lev_dimname), flag='read', data=secs, readvar=readvar) + if (.not. readvar) then + call endrun(msg=' ERROR: secs NOT on diurnal ozone file'//errMsg(sourcefile, __LINE__)) end if + + ! initialize arrays + call diurnalOzoneAnomInst%Init(bounds, nlevsec) - ! Set the diurnal ozone anomaly + ! set the diurnal ozone anomaly do g = bounds%begg, bounds%endg ig = g_to_ig(g) do j = 1, nlevsec @@ -184,6 +192,11 @@ subroutine read_O3_stream(diurnalOzoneAnomInst, bounds) end do end do + ! set the seconds array + do j = 1, nlevsec + diurnalOzoneAnomInst%time_arr(j) = secs(j) + end do + end subroutine read_O3_stream !============================================================================== diff --git a/src/main/circle.F90 b/src/main/circle.F90 new file mode 100644 index 0000000000..58f7d20a5d --- /dev/null +++ b/src/main/circle.F90 @@ -0,0 +1,22 @@ +module circle + + use shr_kind_mod, only : r8 => shr_kind_r8 + + implicit none + private + + real(r8), parameter, public :: pi = 3.14159265358979323846_r8 + + public :: circle_area + +contains + + function circle_area(r) + real(r8), intent(in) :: r + real(r8) :: circle_area + + circle_area = pi*r*r + + end function circle_area + +end module circle From 0c3ad39394e2adfc60d27990f39885f11900d950 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Mon, 9 Jan 2023 11:09:24 -0700 Subject: [PATCH 25/39] previous updates --- src/biogeophys/DiurnalOzoneType.F90 | 4 +++- src/biogeophys/OzoneMod.F90 | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index d09ba32854..22d2d09439 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -124,8 +124,10 @@ subroutine Interp(this, forc_o3, forc_o3_down) end do ! interpolate, checking for edge cases + !TODO: Add bounds here + !TODO: make seconds in day a parameter if (i == 1) then - ! wrap around to front + ! wrap around to back forc_o3_down(:) = forc_o3(:)*((this%o3_anomaly_grc(:,this%ntimes)* & (this%time_arr(i) - real(tod)) + & this%o3_anomaly_grc(:,i)*((86400.0 - this%time_arr(this%ntimes)) + real(tod)))/ & diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 5713bcbdd3..3b9001cf4a 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -393,8 +393,8 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & real(r8) , intent(in) :: forc_o3( bounds%begg: ) ! ozone partial pressure (mol/mol) ! ! !LOCAL VARIABLES: - real(r8), pointer :: forc_o3_down( bounds%begg: ) ! downscaled ozone partial pressure (mol/mol) - integer :: fp ! filter index + real(r8) :: forc_o3_down(bounds%begg:bounds%endg) ! downscaled ozone partial pressure (mol/mol) + integer :: fp ! filter index integer :: p ! patch index integer :: c ! column index integer :: g ! gridcell index @@ -421,7 +421,7 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then call this%diurnalOzoneAnomInst%Interp(forc_o3, forc_o3_down) else - forc_o3_down = forc_o3 + forc_o3_down(bounds%begg:bounds%endg) = forc_o3(bounds%begg:bounds%endg) end if do fp = 1, num_exposedvegp From f85d84f09130c8ccc5e6669ec70d01d93fbcae89 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Wed, 24 Apr 2024 13:02:20 -0600 Subject: [PATCH 26/39] remove weird files? --- src/main/test/CESM_Macros.cmake | 67 --------------------------------- src/main/test/Makefile.utest | 41 -------------------- 2 files changed, 108 deletions(-) delete mode 100644 src/main/test/CESM_Macros.cmake delete mode 100644 src/main/test/Makefile.utest diff --git a/src/main/test/CESM_Macros.cmake b/src/main/test/CESM_Macros.cmake deleted file mode 100644 index ba207ff55a..0000000000 --- a/src/main/test/CESM_Macros.cmake +++ /dev/null @@ -1,67 +0,0 @@ -# CESM build flags for: -# Compiler = gnu: -# Machine = roo2: -# OS = Mac OS X: - -# ================================================== -# Compilers -# ================================================== - -set(CMAKE_Fortran_COMPILER mpif90) -set(CMAKE_C_COMPILER mpicc) - -# ================================================== -# pFUnit location. -# ================================================== - -list(APPEND CMAKE_PREFIX_PATH /usr/local/pfunit/pfunit-mpi) -include(Compilers) - -# ================================================== -# Flags needed for linking netcdf (needed for some drv unit tests) -# ================================================== - -set(NETCDF_DIR "/usr/local") - -# The following is a hack to get cmake to link in hdf5, because there does not -# appear to be a find package script for hdf5: -set(CMAKE_EXE_LINKER_FLAGS "-lhdf5_hl") -include_directories("/usr/local/include") -link_directories("/usr/local/lib") - -# The following is needed so that the above include_directories are listed after -# any include_directories specified by the top-level CMakeLists.txt -set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON) - - -# ================================================== -# CPP definitions. -# ================================================== - -add_config_definitions(CESM -DFORTRANUNDERSCORE -DNO_R16) -add_config_definitions(CESM -DHAVE_NANOTIME ) -add_config_definitions(CESM_DEBUG -DFORTRANUNDERSCORE -DNO_R16) -add_config_definitions(CESM_DEBUG -DHAVE_NANOTIME ) -add_definitions(-DSYSDARWIN) -# For gnu, define USE_CONTIGUOUS as empty (at least some versions of gnu don't -# have support for 'contiguous') -add_definitions(-DUSE_CONTIGUOUS= ) - -# ================================================== -# Fortran flags. -# ================================================== -add_flags(CMAKE_Fortran_FLAGS_CESM -fopenmp -fconvert=big-endian -ffree-line-length-none -ffixed-line-length-none) -add_flags(CMAKE_Fortran_FLAGS_CESM -O2 ) -add_flags(CMAKE_Fortran_FLAGS_CESM_DEBUG -fopenmp -fconvert=big-endian -ffree-line-length-none -ffixed-line-length-none -fno-range-check -fall-intrinsics -ffpe-trap=zero,overflow -fcheck=bounds) -add_flags(CMAKE_Fortran_FLAGS_CESM_DEBUG -O0 -g) - -# ================================================== -# C flags. -# ================================================== - -add_flags(CMAKE_C_FLAGS_CESM -fopenmp -O2) -add_flags(CMAKE_C_FLAGS_CESM_DEBUG -fopenmp -O0) - -# ================================================== -# Linker flags. -# ================================================== diff --git a/src/main/test/Makefile.utest b/src/main/test/Makefile.utest deleted file mode 100644 index c678e613e8..0000000000 --- a/src/main/test/Makefile.utest +++ /dev/null @@ -1,41 +0,0 @@ -# -*- mode: makefile -*- - -ifndef CIMEROOT - $(error Must set variable CIMEROOT) -endif - -CIMEROOT_ABSPATH := $(realpath $(CIMEROOT)) - -TEST_ROOT=$(shell pwd) - -CESM_CMAKE_UTILS=$(CIMEROOT_ABSPATH)/externals/CMake -GENF90=$(CIMEROOT_ABSPATH)/externals/genf90 - -DEBUG_CMAKE= -#DEBUG_CMAKE=--debug-output --trace - -config : clean - mkdir -p build - cp CESM_Macros.cmake build/ - cd build && cmake \ - $(DEBUG_CMAKE) \ - -Wdev \ - -DENABLE_GENF90=ON \ - -DCMAKE_PROGRAM_PATH=$(GENF90) \ - -DCMAKE_BUILD_TYPE=CESM_DEBUG \ - -DCESM_CMAKE_MODULE_DIRECTORY=$(CESM_CMAKE_UTILS) \ - $(TEST_ROOT) - -test : all - @if [ -d ./build ]; then \ - $(MAKE) --directory=build $@; \ - fi - -all : - @if [ -d ./build ]; then \ - $(MAKE) --directory=build $@; \ - fi - - -clean : - rm -rf *~ build From 673b90a92a8a0f8bf99e37d4e26fda67077c9d6c Mon Sep 17 00:00:00 2001 From: adrifoster Date: Wed, 24 Apr 2024 13:03:25 -0600 Subject: [PATCH 27/39] remove more weird files --- doc/design/design_doc_diurnal_ozone.md | 28 +++++++++++++++++--------- src/main/circle.F90 | 22 -------------------- 2 files changed, 19 insertions(+), 31 deletions(-) delete mode 100644 src/main/circle.F90 diff --git a/doc/design/design_doc_diurnal_ozone.md b/doc/design/design_doc_diurnal_ozone.md index 43c552d535..e340c4f062 100644 --- a/doc/design/design_doc_diurnal_ozone.md +++ b/doc/design/design_doc_diurnal_ozone.md @@ -8,6 +8,7 @@ **Written By**: Adrianna Foster (@adrifoster) ## Introduction + --------------------------------------- As laid out in CTSM Issue [#270](https://github.com/ESCOMP/CTSM/issues/270) we want to downscale input ozone partial pressure (mol/mol) temporally if we receive a multi-day average input ozone (usually in DATM mode). @@ -17,27 +18,31 @@ We have the infrastructure laid out for CAM and DATM to inform CTSM which type o We have a gridded file provided by Louisa Emmons for a diurnal ozone variation factor. The data is additionally dimensioned by 'secs' (seconds of day), and depending on the model time of day, can be used as a multiplicative factor for converting multi-day average ozone to sub-daily ozone partial pressure. ## Solutions + --------------------------------------- Read in the diurnal anomaly file as a streams file, being careful to not assume too much so that other files may be provided in the future. Create a diurnal ozone type that has an `Interp` method to downscale and interpolate multi-day average ozone data to sub-daily based on a factor attribute. Inside the existing `CalcOzoneUptake` routine, if we are using multi-day average ozone, interpolate/downscale the `forc_o3` array using the `Interp` subroutine. -**Some alternate ideas**: -1. have the existing `ozone_type` type have this diurnal ozone anomaly type as an attribute that gets initiated only if we are reading in multi-day average ozone. +**Some alternate ideas**: + +1. have the existing `ozone_type` type have this diurnal ozone anomaly type as an attribute that gets initiated only if we are reading in multi-day average ozone. 2. have the diurnal ozone type be fed into relevant `ozone_type` methods as arguments. We would only want to do this if other modules are going to use the diurnal ozone type. This has a possibility, but no clear plans are on the horizon for it. -**Consider going with the first solution for now** +Consider going with the first solution for now. ## Design Considerations + --------------------------------------- -### Assumptions and Dependencies: +### Assumptions and Dependencies -Right now we are assuming that the units of the input diurnal file are going to be in seconds, and that the file covers the whole day. +Right now we are assuming that the units of the input diurnal file are going to be in seconds, and that the file covers the whole day. There is no need to assume that the dimension will be 1-24 (i.e. on the hour) or that the dimensions be equal intervals. ## Design and Architecture + --------------------------------------- ### System diagram or flowchart @@ -54,7 +59,7 @@ These file modifications can be seen in the Jupyter notebook /glade/u/home/afost The file is read in using a new `src/share_esmf/diurnalOzoneStreamMod` module, with associated updates to `bld/CLMBuildNamelist.pm`, `bld/namelist_files/namelist_defaults_ctsm.xml` and `bld/namelist_files/namelist_definition_csvm.xml` -Right now the new variable `use_do3_streams` is set in the `user_nl_clm` file. And the other namelist variables (`stream_fldfilename_do3`, `stream_meshfile_do3`, and `do3_mapalgo`) are inside the `lnd_in` file under a `do3_streams` namelist. +Right now the new variable `use_do3_streams` is set in the `user_nl_clm` file. And the other namelist variables (`stream_fldfilename_do3`, `stream_meshfile_do3`, and `do3_mapalgo`) are inside the `lnd_in` file under a `do3_streams` namelist. **I'm not sure setting up the `use_do3_streams` namelist variable is the best way to go about this, since we essentially want this feature on whenever the ozone frequency is 'multiday_average'** @@ -62,7 +67,7 @@ Right now we are hard-coding the `stream_var_name`, and `stream_lev_dimname`. I Because the diurnal anomaly file is not dimensioned by time other than seconds of day, we just need to read it in and advance one time. This is all currently done in the `diurnalOzoneStreamMod`'s `read_O3_stream` subroutine. We set the date to an arbitrary date (the same as on the file, I'm not sure if this is necessary?). -We also need to grab the `secs` array to do interpolation/downscaling with. +We also need to grab the `secs` array to do interpolation/downscaling with. Both are read from the file and then an instance of `diurnal_ozone_anom_type` is initialized and relevant arrays are set to the ozone factor and seconds data. @@ -71,18 +76,20 @@ Both are read from the file and then an instance of `diurnal_ozone_anom_type` is The module `DiurnalOzoneType` sets up a `diurnal_ozone_anom_type` which has only a few attributes and methods: **Attributes**: + 1. `ntimes` - size of time/seconds-of-day dimension (private) 2. `o3_anomaly_grc` - o3 anomaly data, 2d, gridcells x ntimes 3. `time_arr` - time/seconds of day array, 1d, ntimes **Methods**: + 1. `Init` - Initializes the anomaly data structures, calls `InitAllocate` 2. `InitAllocate` - allocates arrays and sets them to nan 3. `Interp` - Interpolates/downscales an input multi-day average ozone (`forc_o3`) using the o3 anomaly data and outputs a downscaled `forc_o3_down` array. See below for `Interp` algorithm/pseudo code ### Implementation within OzoneMod -We add an instance of the `diurnal_ozone_anom_type` as an attribute of the `ozone_base_type`. +We add an instance of the `diurnal_ozone_anom_type` as an attribute of the `ozone_base_type`. Within the `Init` method of the `ozone_base_type`, we read the `drv_flds_in` file to get the `atom_ozone_frequency_val`. If this value is `atm_ozone_frequency_multiday_average` then we initialize and read in the o3 anomaly data by calling the `read_O3_stream` described above. *Do we need an else decision here?* @@ -95,12 +102,15 @@ Within the `CalcOzoneUptake` method, we check for the `atm_ozone_freq` flag and ## Rollout Plan + --------------------------------------- Define the roll-out phases and tests you plan to do ## Review Sign-off + --------------------------------------- + * Reviewer(s): -*Sign-off Completed on YYYY-MM-DD* +* Sign-off Completed on YYYY-MM-DD* diff --git a/src/main/circle.F90 b/src/main/circle.F90 deleted file mode 100644 index 58f7d20a5d..0000000000 --- a/src/main/circle.F90 +++ /dev/null @@ -1,22 +0,0 @@ -module circle - - use shr_kind_mod, only : r8 => shr_kind_r8 - - implicit none - private - - real(r8), parameter, public :: pi = 3.14159265358979323846_r8 - - public :: circle_area - -contains - - function circle_area(r) - real(r8), intent(in) :: r - real(r8) :: circle_area - - circle_area = pi*r*r - - end function circle_area - -end module circle From f2d58ca9c2deb7900f43594d444ba414436e5ce5 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Wed, 24 Apr 2024 15:34:37 -0600 Subject: [PATCH 28/39] updating Interp function --- src/biogeophys/DiurnalOzoneType.F90 | 83 ++++++++++++++++------------- src/biogeophys/OzoneMod.F90 | 12 ++--- 2 files changed, 52 insertions(+), 43 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 22d2d09439..8565455368 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -16,15 +16,15 @@ module DiurnalOzoneType implicit none save private - + ! !PUBLIC TYPES: type, public :: diurnal_ozone_anom_type private ! Private data members integer :: ntimes ! size of time dimension real(r8), public, allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] - real(r8), public, allocatable :: time_arr(:) ! time dimension (units = seconds of day) - + real(r8), public, allocatable :: time_arr(:) ! time dimension (units = seconds of day) + contains ! Public routines procedure, public :: Init @@ -32,17 +32,17 @@ module DiurnalOzoneType procedure, public :: Interp end type diurnal_ozone_anom_type - + character(len=*), parameter, private :: sourcefile = & __FILE__ contains - + ! ======================================================================== ! Infrastructure routines (initialization, etc.) ! ======================================================================== - + !----------------------------------------------------------------------- subroutine Init(this, bounds, n) ! @@ -63,8 +63,8 @@ subroutine Init(this, bounds, n) call this%InitAllocate(bounds) end subroutine Init - - + + !----------------------------------------------------------------------- subroutine InitAllocate(this, bounds) ! @@ -99,53 +99,62 @@ subroutine Interp(this, forc_o3, forc_o3_down) ! ! !USES: use clm_time_manager , only : get_curr_time + use clm_varcon , only : secspday ! ! !ARGUMENTS: - class(diurnal_ozone_anom_type), intent(in) :: this - real(r8), intent(in) :: forc_o3( bounds%begg: ) ! ozone partial pressure (mol/mol) - real(r8), intent(out) :: forc_o3_down( bounds%begg: ) ! ozone partial pressure, downscaled (mol/mol) + class(diurnal_ozone_anom_type), intent(in) :: this + real(r8), intent(in) :: forc_o3(bounds%begg:bounds%endg) ! ozone partial pressure (mol/mol) + real(r8), intent(out) :: forc_o3_down(bounds%begg:bounds%endg) ! ozone partial pressure, downscaled (mol/mol) ! ! LOCAL VARIABLES: - integer :: i ! looping index - integer :: yr ! year - integer :: mon ! month - integer :: day ! day of month - integer :: tod ! time of day (seconds past 0Z) + integer :: t ! looping index + integer :: yr ! year + integer :: mon ! month + integer :: day ! day of month + integer :: tod ! time of day (seconds past 0Z) + integer :: begg, endg ! bounds + integer :: t_prev ! previous time index + real(r8) :: + real(r8) :: anomaly_val_start + real(r8) :: anomaly_val_end + real(r8) :: anomaly_scalar + real(r8) :: tdiff_end, tdiff_start !----------------------------------------------------------------------- + begg = bounds%begg; endg = bounds%endg + ! Get current date/time - we really only need seconds call get_curr_date(yr, mon, day, tod) ! find the time interval we are in - do i = 1, this%ntimes - if (real(tod) <= this%time_arr(i)) then + do t = 1, this%ntimes + if (real(tod) <= this%time_arr(t)) then exit end if end do ! interpolate, checking for edge cases - !TODO: Add bounds here - !TODO: make seconds in day a parameter - if (i == 1) then - ! wrap around to back - forc_o3_down(:) = forc_o3(:)*((this%o3_anomaly_grc(:,this%ntimes)* & - (this%time_arr(i) - real(tod)) + & - this%o3_anomaly_grc(:,i)*((86400.0 - this%time_arr(this%ntimes)) + real(tod)))/ & - (this%time_arr(i) + (86400.0 - this%time_arr(this%ntimes)))) - else - ! interpolate normally - forc_o3_down(:) = forc_o3(:)*((this%o3_anomaly_grc(:,i-1)* & - (this%time_arr(i) - real(tod)) + & - this%o3_anomaly_grc(:,i)*(real(tod) - this%time_arr(i-1)))/ & - (this%time_arr(i) - this%time_arr(i-1))) - end if - - - + if (t == 1) then + t_prev = this%ntimes + tdiff_end = secspday - this%time_arr(t_prev) + real(tod) + tdiff = this%time_arr(t) + secspday - this%time_arr(t_prev) + else + t_prev = t - 1 + tdiff_end = real(tod) - this%time_arr(t_prev) + tdiff = this%time_arr(t) - this%time_arr(t_prev) + end if + + anomaly_val_start = this%o3_anomaly_grc(begg:endg, t_prev) + anomaly_val_end = this%o3_anomaly_grc(begg:endg, t) + tdiff_start = this%time_arr(t) - real(tod) + + ! interpolate + anomaly_scalar = (anomaly_val_start*tdiff_start + anomaly_val_end*tdiff_end)/tdiff + + forc_o3_down(begg:endg) = forc_o3(begg:endg)*anomaly_scalar end subroutine Interp !----------------------------------------------------------------------- end module DiurnalOzoneType - \ No newline at end of file diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 3b9001cf4a..73622117de 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -154,14 +154,14 @@ subroutine Init(this, bounds, o3_veg_stress_method) ! Local variables integer :: atm_ozone_frequency_val !----------------------------------------------------------------------- - - ! read what atm ozone frequency we have + + ! read what atm ozone frequency we have call shr_ozone_coupling_readnl("drv_flds_in", atm_ozone_frequency_val) this%atm_ozone_freq = atm_ozone_frequency_val - + ! if we have multi-day average input ozone, we need to convert to sub-daily using ! an input anomaly file - if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then + if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then ! initialize and read in data for diurnal O3 anomaly stream call read_O3_stream(this%diurnalOzoneAnomInst, bounds) end if @@ -431,14 +431,14 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & ! Ozone uptake for shaded leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssha(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesha(p)) ! Ozone uptake for sunlit leaves call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & rs=rssun(p), rb=rb(p), ram=ram(p), & tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & o3uptake=o3uptakesun(p)) From 0ecd18b7371f59cc4d9cb28d6716bb8a5f747460 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Wed, 24 Apr 2024 16:01:05 -0600 Subject: [PATCH 29/39] bug fix --- src/biogeophys/DiurnalOzoneType.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 8565455368..88f83426e0 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -114,11 +114,11 @@ subroutine Interp(this, forc_o3, forc_o3_down) integer :: tod ! time of day (seconds past 0Z) integer :: begg, endg ! bounds integer :: t_prev ! previous time index - real(r8) :: real(r8) :: anomaly_val_start real(r8) :: anomaly_val_end real(r8) :: anomaly_scalar real(r8) :: tdiff_end, tdiff_start + real(r8) :: tdiff !----------------------------------------------------------------------- begg = bounds%begg; endg = bounds%endg From f62bf19321e94d9e64032fbbd87069ebe9764d72 Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Thu, 25 Apr 2024 10:05:30 -0600 Subject: [PATCH 30/39] various updates to actual read namelist args --- bld/CLMBuildNamelist.pm | 1 + bld/namelist_files/namelist_defaults_ctsm.xml | 4 +- src/biogeophys/DiurnalOzoneType.F90 | 31 +++--- src/biogeophys/OzoneMod.F90 | 2 +- src/cpl/nuopc/lnd_import_export.F90 | 5 +- src/main/clm_varctl.F90 | 96 ++++++++++--------- src/main/controlMod.F90 | 25 +++-- 7 files changed, 87 insertions(+), 77 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 4d4522a4cd..2c356cc9e9 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -1581,6 +1581,7 @@ sub process_namelist_inline_logic { setup_logic_luna($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_hillslope($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_o3_veg_stress_method($opts, $nl_flags, $definition, $defaults, $nl,$physv); + setup_logic_do3_streams($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_hydrstress($opts, $nl_flags, $definition, $defaults, $nl); setup_logic_dynamic_roots($opts, $nl_flags, $definition, $defaults, $nl, $physv); setup_logic_params_file($opts, $nl_flags, $definition, $defaults, $nl); diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 6f07fc0ffe..2bced86626 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1733,8 +1733,8 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c .false. -/glade/work/afoster/ozone_damage_files/converted/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc -$DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc +/glade/work/afoster/ozone_update/ozone_damage_files/converted/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc +share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc bilinear diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 88f83426e0..7d332c241f 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -92,32 +92,32 @@ end subroutine InitAllocate !----------------------------------------------------------------------- !----------------------------------------------------------------------- - subroutine Interp(this, forc_o3, forc_o3_down) + subroutine Interp(this, bounds, forc_o3, forc_o3_down) ! ! !DESCRIPTION: ! Downscale/interpolate multi-day ozone data to subdaily ! ! !USES: - use clm_time_manager , only : get_curr_time + use clm_time_manager , only : get_curr_date use clm_varcon , only : secspday ! ! !ARGUMENTS: class(diurnal_ozone_anom_type), intent(in) :: this - real(r8), intent(in) :: forc_o3(bounds%begg:bounds%endg) ! ozone partial pressure (mol/mol) - real(r8), intent(out) :: forc_o3_down(bounds%begg:bounds%endg) ! ozone partial pressure, downscaled (mol/mol) + type(bounds_type), intent(in) :: bounds ! bounds type + real(r8), intent(in) :: forc_o3(:) ! ozone partial pressure (mol/mol) + real(r8), intent(out) :: forc_o3_down(:) ! ozone partial pressure, downscaled (mol/mol) + ! ! LOCAL VARIABLES: - integer :: t ! looping index - integer :: yr ! year - integer :: mon ! month + integer :: t ! looping index + integer :: yr ! year + integer :: mon ! month integer :: day ! day of month integer :: tod ! time of day (seconds past 0Z) integer :: begg, endg ! bounds integer :: t_prev ! previous time index - real(r8) :: anomaly_val_start - real(r8) :: anomaly_val_end - real(r8) :: anomaly_scalar - real(r8) :: tdiff_end, tdiff_start + real(r8) :: tdiff_end + real(r8) :: tdiff_start real(r8) :: tdiff !----------------------------------------------------------------------- @@ -135,6 +135,7 @@ subroutine Interp(this, forc_o3, forc_o3_down) ! interpolate, checking for edge cases if (t == 1) then + ! wrap around back t_prev = this%ntimes tdiff_end = secspday - this%time_arr(t_prev) + real(tod) tdiff = this%time_arr(t) + secspday - this%time_arr(t_prev) @@ -144,14 +145,12 @@ subroutine Interp(this, forc_o3, forc_o3_down) tdiff = this%time_arr(t) - this%time_arr(t_prev) end if - anomaly_val_start = this%o3_anomaly_grc(begg:endg, t_prev) - anomaly_val_end = this%o3_anomaly_grc(begg:endg, t) tdiff_start = this%time_arr(t) - real(tod) ! interpolate - anomaly_scalar = (anomaly_val_start*tdiff_start + anomaly_val_end*tdiff_end)/tdiff - - forc_o3_down(begg:endg) = forc_o3(begg:endg)*anomaly_scalar + forc_o3_down(begg:endg) = forc_o3(begg:endg)* & + ((this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_start + & + this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_end)/tdiff) end subroutine Interp diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 73622117de..5c799aae7f 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -419,7 +419,7 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & ) if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then - call this%diurnalOzoneAnomInst%Interp(forc_o3, forc_o3_down) + call this%diurnalOzoneAnomInst%Interp(bounds, forc_o3, forc_o3_down) else forc_o3_down(bounds%begg:bounds%endg) = forc_o3(bounds%begg:bounds%endg) end if diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 647d468960..30c9f6eec3 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -22,7 +22,6 @@ module lnd_import_export use shr_megan_mod , only : shr_megan_readnl, shr_megan_mechcomps_n use nuopc_shr_methods , only : chkerr use lnd_import_export_utils , only : check_for_errors, check_for_nans - use diurnalOzoneStreamMod , only : dO3_init implicit none private ! except @@ -1331,7 +1330,7 @@ subroutine ReadCapNamelist( NLFilename, rc ) integer, target :: tmp(1) type(ESMF_VM) :: vm character(*), parameter :: nml_name = "ctsm_nuopc_cap" ! MUST match with namelist name below - + namelist /ctsm_nuopc_cap/ force_send_to_atm @@ -1356,7 +1355,7 @@ subroutine ReadCapNamelist( NLFilename, rc ) ! Broadcast namelist to all processors call ESMF_VMBroadcast(vm, tmp, 1, 0, rc=rc) - + force_send_to_atm = (tmp(1) == 1) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 7d0b2b55ad..82f4cdb40b 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -27,27 +27,27 @@ module clm_varctl ! Run control variables ! ! case id - character(len=256), public :: caseid = ' ' + character(len=256), public :: caseid = ' ' ! case title - character(len=256), public :: ctitle = ' ' + character(len=256), public :: ctitle = ' ' ! Type of run - integer, public :: nsrest = iundef + integer, public :: nsrest = iundef logical, public :: is_cold_start = .false. ! Startup from initial conditions - integer, public, parameter :: nsrStartup = 0 + integer, public, parameter :: nsrStartup = 0 ! Continue from restart files - integer, public, parameter :: nsrContinue = 1 + integer, public, parameter :: nsrContinue = 1 ! Branch from restart files - integer, public, parameter :: nsrBranch = 2 + integer, public, parameter :: nsrBranch = 2 ! true => allow case name to remain the same for branch run ! by default this is not allowed - logical, public :: brnch_retain_casename = .false. + logical, public :: brnch_retain_casename = .false. ! true => run tests of ncdio_pio logical, public :: for_testing_run_ncdiopio_tests = .false. @@ -74,19 +74,19 @@ module clm_varctl logical, public :: for_testing_no_crop_seed_replenishment = .false. ! Hostname of machine running on - character(len=256), public :: hostname = ' ' + character(len=256), public :: hostname = ' ' ! username of user running program - character(len=256), public :: username = ' ' + character(len=256), public :: username = ' ' ! description of this source character(len=256), public :: source = "Community Terrestrial Systems Model" ! version of program - character(len=256), public :: version = " " + character(len=256), public :: version = " " ! dataset conventions - character(len=256), public :: conventions = "CF-1.0" + character(len=256), public :: conventions = "CF-1.0" ! component name for filenames (history or restart files) character(len=8), public :: compname = 'clm2' @@ -120,14 +120,14 @@ module clm_varctl !---------------------------------------------------------- ! Flag to read ndep rather than obtain it from coupler !---------------------------------------------------------- - + logical, public :: ndep_from_cpl = .false. !---------------------------------------------------------- ! Interpolation of finidat if requested !---------------------------------------------------------- - logical, public :: bound_h2osoi = .true. ! for debugging + logical, public :: bound_h2osoi = .true. ! for debugging ! If finidat_interp_source is non-blank and finidat is blank then interpolation will be ! done from finidat_interp_source to finidat_interp_dest. Note that @@ -150,8 +150,8 @@ module clm_varctl logical, public, parameter :: use_crop_agsys = .false. ! true => separate crop landunit is not created by default - logical, public :: create_crop_landunit = .false. - + logical, public :: create_crop_landunit = .false. + ! number of hillslopes per landunit integer, public :: nhillslope = 0 @@ -159,14 +159,14 @@ module clm_varctl integer, public :: max_columns_hillslope = 1 ! do not irrigate by default - logical, public :: irrigate = .false. + logical, public :: irrigate = .false. ! set saturated excess runoff to zero for crops logical, public :: crop_fsat_equals_zero = .false. ! remove this fraction of crop residues to a 1-year product pool (instead of going to litter) real(r8), public :: crop_residue_removal_frac = 0.0 - + !---------------------------------------------------------- ! Other subgrid logic !---------------------------------------------------------- @@ -175,7 +175,7 @@ module clm_varctl logical, public :: run_zero_weight_urban = .false. ! true => make ALL patches, cols & landunits active (even if weight is 0) - logical, public :: all_active = .false. + logical, public :: all_active = .false. ! true => any ocean (i.e., "wetland") points on the surface dataset are converted to ! bare ground (or whatever vegetation is given in that grid cell... but typically this @@ -198,33 +198,33 @@ module clm_varctl !---------------------------------------------------------- ! values of 'prognostic','diagnostic','constant' - character(len=16), public :: co2_type = 'constant' + character(len=16), public :: co2_type = 'constant' - ! State of the model for the accelerated decomposition (AD) spinup. + ! State of the model for the accelerated decomposition (AD) spinup. ! 0 (default) = normal model; 1 = AD SPINUP - integer, public :: spinup_state = 0 + integer, public :: spinup_state = 0 ! true => anoxia is applied to heterotrophic respiration also considered in CH4 model ! default value reset in controlMod - logical, public :: anoxia = .true. + logical, public :: anoxia = .true. ! used to override an error check on reading in restart files - logical, public :: override_bgc_restart_mismatch_dump = .false. + logical, public :: override_bgc_restart_mismatch_dump = .false. ! Set in CNAllocationInit (TODO - had to move it here to avoid circular dependency) - logical, private:: carbon_only + logical, private:: carbon_only - ! Set in CNNDynamicsInit + ! Set in CNNDynamicsInit ! NOTE (mvertens, 2014-9 had to move it here to avoid confusion when carbon data types - ! wehre split - TODO - should move it our of this module) + ! wehre split - TODO - should move it our of this module) ! NOTE(bandre, 2013-10) according to Charlie Koven, nfix_timeconst - ! is currently used as a flag and rate constant. + ! is currently used as a flag and rate constant. ! Rate constant: time over which to exponentially relax the npp flux for N fixation term ! (days) time over which to exponentially relax the npp flux for N fixation term - ! flag: (if <= 0. or >= 365; use old annual method). + ! flag: (if <= 0. or >= 365; use old annual method). ! Default value is junk that should always be overwritten by the namelist or init function! ! - real(r8), public :: nfix_timeconst = -1.2345_r8 + real(r8), public :: nfix_timeconst = -1.2345_r8 !---------------------------------------------------------- ! Physics @@ -244,10 +244,16 @@ module clm_varctl ! ozone vegitation stress method, valid values: unset, stress_lombardozzi2015, stress_falk character(len=64), public :: o3_veg_stress_method = 'unset' + ! other o3_streams parameters + logical, public :: use_do3_streams = .false. + character(len=fname_len), public :: stream_fldfilename_do3 + character(len=fname_len), public :: stream_meshfile_do3 + character(len=fname_len), public :: do3_mapalgo + real(r8), public :: o3_ppbv = 100._r8 ! number of wavelength bands used in SNICAR snow albedo calculation - integer, public :: snicar_numrad_snw = 5 + integer, public :: snicar_numrad_snw = 5 ! type of downward solar radiation spectrum for SNICAR snow albedo calculation ! options: @@ -316,7 +322,7 @@ module clm_varctl integer, public :: fates_parteh_mode = -9 ! 1 => carbon only ! 2 => C+N+P (not enabled yet) ! no others enabled - integer, public :: fates_spitfire_mode = 0 + integer, public :: fates_spitfire_mode = 0 ! 0 for no fire; 1 for constant ignitions; ! > 1 for external data (lightning and/or anthropogenic ignitions) ! see bld/namelist_files/namelist_definition_clm4_5.xml for details @@ -336,13 +342,13 @@ module clm_varctl ! Performing this output can be expensive, so we allow different history dimension ! levels. ! The first index is output at the model timescale - ! The second index is output at the dynamics (daily) timescale + ! The second index is output at the dynamics (daily) timescale ! 0 - no output ! 1 - include only column level means (3D) ! 2 - include output that includes the 4th dimension - + integer, dimension(2), public :: fates_history_dimlevel = (/2,2/) - + logical, public :: use_fates_luh = .false. ! true => use FATES landuse data mode character(len=256), public :: fluh_timeseries = '' ! filename for fates landuse timeseries data character(len=256), public :: fates_inventory_ctrl_filename = '' ! filename for inventory control @@ -351,9 +357,9 @@ module clm_varctl ! BUT... THEY CAN BOTH BE OFF (IF FATES IS OFF) logical, public :: use_fates_sp = .false. ! true => use FATES satellite phenology mode logical, public :: use_fates_bgc = .false. ! true => use FATES along with CLM soil biogeochemistry - + !---------------------------------------------------------- - ! LUNA switches + ! LUNA switches !---------------------------------------------------------- logical, public :: use_luna = .false. ! true => use LUNA @@ -373,7 +379,7 @@ module clm_varctl integer, public :: carbon_resp_opt = 0 !---------------------------------------------------------- - ! prescribed soil moisture streams switch + ! prescribed soil moisture streams switch !---------------------------------------------------------- logical, public :: use_soil_moisture_streams = .false. ! true => use prescribed soil moisture stream @@ -436,11 +442,11 @@ module clm_varctl ! glacier_mec control variables: default values (may be overwritten by namelist) !---------------------------------------------------------- - ! true => CLM glacier area & topography changes dynamically - logical , public :: glc_do_dynglacier = .false. + ! true => CLM glacier area & topography changes dynamically + logical , public :: glc_do_dynglacier = .false. ! number of days before one considers the perennially snow-covered point 'land ice' - integer , public :: glc_snow_persistence_max_days = 7300 + integer , public :: glc_snow_persistence_max_days = 7300 ! !---------------------------------------------------------- @@ -464,21 +470,21 @@ module clm_varctl !---------------------------------------------------------- ! number of segments per clump for decomp - integer, public :: nsegspc = 20 + integer, public :: nsegspc = 20 !---------------------------------------------------------- ! Derived variables (run, history and restart file) !---------------------------------------------------------- ! directory name for local restart pointer file - character(len=256), public :: rpntdir = '.' + character(len=256), public :: rpntdir = '.' ! file name for local restart pointer file - character(len=256), public :: rpntfil = 'rpointer.lnd' + character(len=256), public :: rpntfil = 'rpointer.lnd' ! moved hist_wrtch4diag from histFileMod.F90 to here - caused compiler error with intel ! namelist: write CH4 extra diagnostic output - logical, public :: hist_wrtch4diag = .false. + logical, public :: hist_wrtch4diag = .false. ! namelist: write list of all history fields to a file for use in documentation logical, public :: hist_fields_list_file = .false. @@ -532,7 +538,7 @@ subroutine clm_varctl_set( caseid_in, ctitle_in, brnch_retain_casename_in, & ! !ARGUMENTS: character(len=256), optional, intent(IN) :: caseid_in ! case id character(len=256), optional, intent(IN) :: ctitle_in ! case title - logical, optional, intent(IN) :: brnch_retain_casename_in ! true => allow case name to remain the + logical, optional, intent(IN) :: brnch_retain_casename_in ! true => allow case name to remain the ! same for branch run logical, optional, intent(IN) :: single_column_in ! true => single column mode real(r8), optional, intent(IN) :: scmlat_in ! single column lat diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index 46d9e9958a..fb61a0a958 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -244,8 +244,9 @@ subroutine control_init(dtime) use_fates_tree_damage, & fates_history_dimlevel - ! Ozone vegetation stress method - namelist / clm_inparm / o3_veg_stress_method + ! Ozone vegetation stress method and streams file + namelist / clm_inparm / o3_veg_stress_method, use_do3_streams, & + stream_fldfilename_do3, stream_meshfile_do3, do3_mapalgo ! CLM 5.0 nitrogen flags namelist /clm_inparm/ use_flexibleCN, use_luna @@ -465,7 +466,7 @@ subroutine control_init(dtime) else use_fates_bgc = .true. end if - + if (fates_parteh_mode == 1 .and. suplnitro == suplnNon .and. use_fates_bgc )then write(iulog,*) ' When FATES with fates_parteh_mode == 1 (ie carbon only mode),' write(iulog,*) ' you must have supplemental nitrogen turned on, there will be' @@ -474,7 +475,7 @@ subroutine control_init(dtime) call endrun(msg=' ERROR: fates_parteh_mode=1 must have suplnitro set to suplnAll.'//& errMsg(sourcefile, __LINE__)) end if - + if ( use_cn) then call endrun(msg=' ERROR: use_cn and use_fates cannot both be set to true.'//& errMsg(sourcefile, __LINE__)) @@ -506,21 +507,21 @@ subroutine control_init(dtime) end if else - + ! These do default to false anyway, but this emphasizes they ! are false when fates is false use_fates_sp = .false. use_fates_bgc = .false. - + end if ! Check compatibility with use_lai_streams if (use_lai_streams) then - if ((use_fates .and. .not. use_fates_sp) .or. use_cn) then + if ((use_fates .and. .not. use_fates_sp) .or. use_cn) then call endrun(msg=' ERROR: cannot use LAI streams unless in SP mode (use_cn = .false. or use_fates_sp=.true.).'//& errMsg(sourcefile, __LINE__)) - end if - end if + end if + end if ! If nfix_timeconst is equal to the junk default value, then it was not specified ! by the user namelist and we need to assign it the correct default value. If the @@ -774,7 +775,7 @@ subroutine control_spmd() ! BGC call mpi_bcast (co2_type, len(co2_type), MPI_CHARACTER, 0, mpicom, ier) - + call mpi_bcast (use_fates, 1, MPI_LOGICAL, 0, mpicom, ier) if (use_cn .or. use_fates) then @@ -987,6 +988,10 @@ subroutine control_print () write(iulog,*) ' use_grainproduct = ', use_grainproduct write(iulog,*) ' crop_residue_removal_frac = ', crop_residue_removal_frac write(iulog,*) ' o3_veg_stress_method = ', o3_veg_stress_method + write(iulog,*) ' use_do3_streams = ', use_do3_streams + write(iulog,*) ' stream_fldfilename_do3 = ', stream_fldfilename_do3 + write(iulog,*) ' stream_meshfile_do3 = ', stream_meshfile_do3 + write(iulog,*) ' do3_mapalgo = ', do3_mapalgo write(iulog,*) ' use_snicar_frc = ', use_snicar_frc write(iulog,*) ' snicar_use_aerosol = ',snicar_use_aerosol write(iulog,*) ' use_vancouver = ', use_vancouver From b017013f652a780862278319e5f4a9889a68af14 Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Fri, 26 Apr 2024 11:20:28 -0600 Subject: [PATCH 31/39] final updates --- src/biogeophys/OzoneMod.F90 | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 5c799aae7f..8c7dbb7b50 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -40,6 +40,7 @@ module OzoneMod real(r8), pointer :: o3uptakesha_patch(:) ! ozone dose, shaded leaves (mmol O3/m^2) real(r8), pointer :: o3uptakesun_patch(:) ! ozone dose, sunlit leaves (mmol O3/m^2) + real(r8), pointer :: o3force_grid(:) ! ozone forcing (mol/mol) ! NOTE(wjs, 2014-09-29) tlai_old_patch really belongs alongside tlai_patch in ! CanopyStateType. But there are problems with any way I can think to implement @@ -197,16 +198,20 @@ subroutine InitAllocate(this, bounds) ! ! !LOCAL VARIABLES: integer :: begp, endp + integer :: begg, endg !----------------------------------------------------------------------- begp = bounds%begp endp = bounds%endp + begg = bounds%begg + endg = bounds%endg call this%InitAllocateBase(bounds) allocate(this%o3uptakesha_patch(begp:endp)) ; this%o3uptakesha_patch(:) = nan allocate(this%o3uptakesun_patch(begp:endp)) ; this%o3uptakesun_patch(:) = nan allocate(this%tlai_old_patch(begp:endp)) ; this%tlai_old_patch(:) = nan + allocate(this%o3force_grid(begg:endg)) ; this%o3force_grid(:) = nan end subroutine InitAllocate @@ -225,12 +230,15 @@ subroutine InitHistory(this, bounds) ! ! !LOCAL VARIABLES: integer :: begp, endp + integer :: begg, endg character(len=*), parameter :: subname = 'InitHistory' !----------------------------------------------------------------------- begp = bounds%begp endp = bounds%endp + begg = bounds%begg + endg = bounds%endg this%o3uptakesun_patch(begp:endp) = spval call hist_addfld1d (fname='O3UPTAKESUN', units='mmol/m^2', & @@ -242,6 +250,11 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='total ozone flux into shaded leaves', & ptr_patch=this%o3uptakesha_patch) + this%o3force_grid(begg:endg) = spval + call hist_addfld1d (fname='FORCE_O3', units='mol/mol', & + avgflag='A', long_name='ozone partial pressure', & + ptr_lnd=this%o3force_grid) + if (this%stress_method==stress_method_lombardozzi2015) then ! For this and the following variables: how should we include leaf area in the ! patch averaging? @@ -313,18 +326,22 @@ subroutine InitCold(this, bounds) ! ! !LOCAL VARIABLES: integer :: begp, endp + integer :: begg, endg character(len=*), parameter :: subname = 'InitCold' !----------------------------------------------------------------------- begp = bounds%begp endp = bounds%endp + begg = bounds%begg + endg = bounds%endg call this%InitColdBase(bounds) this%o3uptakesha_patch(begp:endp) = 0._r8 this%o3uptakesun_patch(begp:endp) = 0._r8 this%tlai_old_patch(begp:endp) = 0._r8 + this%o3force_grid(begg:endg) = 0._r8 end subroutine InitCold @@ -365,6 +382,11 @@ subroutine Restart(this, bounds, ncid, flag) long_name='ozone uptake for sunlit leaves', units='mmol m^-3', & readvar=readvar, interpinic_flag='interp', data=this%o3uptakesun_patch) + call restartvar(ncid=ncid, flag=flag, varname='o3force', xtype=ncd_double, & + dim1name='gridcell', & + long_name='ozone forcing', units='mol mol^-1', & + readvar=readvar, interpinic_flag='interp', data=this%o3force_grid) + end subroutine Restart ! ======================================================================== @@ -423,6 +445,7 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & else forc_o3_down(bounds%begg:bounds%endg) = forc_o3(bounds%begg:bounds%endg) end if + this%o3force_grid(bounds%begg:bounds%endg) = forc_o3_down(bounds%begg:bounds%endg) do fp = 1, num_exposedvegp p = filter_exposedvegp(fp) From 526385bbe2287c7b827421b53c120d1e3ca826f8 Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Fri, 26 Apr 2024 11:45:48 -0600 Subject: [PATCH 32/39] remove ws diffs from buildnamelist --- bld/CLMBuildNamelist.pm | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 2c356cc9e9..81fa149b9d 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -97,7 +97,7 @@ OPTIONS CENTURY or MIMICS decomposition This toggles on the namelist variables: use_fates. use_lch4 and use_nitrif_denitrif are optional - + (Only for CLM4.5/CLM5.0) -[no-]chk_res Also check [do NOT check] to make sure the resolution and land-mask is valid. @@ -1011,7 +1011,7 @@ sub setup_cmdl_fire_light_res { if ( ! &value_is_true($nl_flags->{'neon'}) ) { if ( defined($opts->{'clm_usr_name'}) ) { $log->warning("The NEON lightning dataset does NOT cover the entire globe, make sure it covers the region for your grid"); - } else { + } else { $log->fatal_error("The NEON lightning dataset can NOT be used for global grids or regions or points outside of its area as it does NOT cover the entire globe."); } } @@ -2278,7 +2278,7 @@ sub setup_logic_crop_inparm { } add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, "initial_seed_at_planting", 'use_crop'=>$nl->get_value('use_crop') ); - + my $crop_residue_removal_frac = $nl->get_value('crop_residue_removal_frac'); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'crop_residue_removal_frac' ); if ( $crop_residue_removal_frac < 0.0 or $crop_residue_removal_frac > 1.0 ) { @@ -2619,8 +2619,8 @@ SIMYR: foreach my $sim_yr ( @sim_years ) { if ( defined($use_init_interp_default) ) { $log->fatal_error($err_msg." but can't find one without $useinitvar being set to true, change it to true in your user_nl_clm file in your case"); } else { - my $set = "Relevent settings: use_cndv = ". $nl_flags->{'use_cndv'} . " phys = " . - $physv->as_string() . " hgrid = " . $nl_flags->{'res'} . " sim_year = " . + my $set = "Relevent settings: use_cndv = ". $nl_flags->{'use_cndv'} . " phys = " . + $physv->as_string() . " hgrid = " . $nl_flags->{'res'} . " sim_year = " . $settings{'sim_year'} . " lnd_tuning_mode = " . $nl_flags->{'lnd_tuning_mode'} . "use_fates = " . $nl_flags->{'use_fates'}; $log->fatal_error($err_msg." but the default setting of $useinitvar is false, so set both $var to a startup file and $useinitvar==TRUE, or developers should modify the namelist_defaults file".$set); @@ -3163,7 +3163,7 @@ sub setup_logic_supplemental_nitrogen { add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'suplnitro', 'use_fates'=>$nl_flags->{'use_fates'}); } - + # # Error checking for suplnitro # @@ -3688,10 +3688,10 @@ sub setup_logic_nitrogen_deposition { 'use_cn'=>$nl_flags->{'use_cn'}, 'hgrid'=>$nl_flags->{'res'}, 'clm_accelerated_spinup'=>$nl_flags->{'clm_accelerated_spinup'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndep_taxmode', 'phys'=>$nl_flags->{'phys'}, - 'use_cn'=>$nl_flags->{'use_cn'}, + 'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'ndep_varlist', 'phys'=>$nl_flags->{'phys'}, - 'use_cn'=>$nl_flags->{'use_cn'}, + 'use_cn'=>$nl_flags->{'use_cn'}, 'lnd_tuning_mode'=>$nl_flags->{'lnd_tuning_mode'} ); add_default($opts, $nl_flags->{'inputdata_rootdir'}, $definition, $defaults, $nl, 'stream_year_first_ndep', 'phys'=>$nl_flags->{'phys'}, 'use_cn'=>$nl_flags->{'use_cn'}, 'sim_year'=>$nl_flags->{'sim_year'}, @@ -4556,8 +4556,8 @@ sub setup_logic_fates { my $suplnitro = $nl->get_value('suplnitro'); my $parteh_mode = $nl->get_value('fates_parteh_mode'); if ( ($parteh_mode == 1) && ($suplnitro !~ /ALL/) && not &value_is_true( $nl_flags->{'use_fates_sp'}) ) { - $log->fatal_error("supplemental Nitrogen (suplnitro) is NOT set to ALL, FATES is on, " . - "but and FATES-SP is not active, but fates_parteh_mode is 1, so Nitrogen is not active" . + $log->fatal_error("supplemental Nitrogen (suplnitro) is NOT set to ALL, FATES is on, " . + "but and FATES-SP is not active, but fates_parteh_mode is 1, so Nitrogen is not active" . "Change suplnitro back to ALL"); } # From 541d806fe36d4843f165b9886ff766450ab6e6c0 Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Fri, 26 Apr 2024 11:50:28 -0600 Subject: [PATCH 33/39] remove ws diffs --- bld/namelist_files/namelist_defaults_ctsm.xml | 4 +- .../namelist_definition_ctsm.xml | 151 +++++++++--------- 2 files changed, 77 insertions(+), 78 deletions(-) diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index 2bced86626..4b3b7d6c4b 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1506,10 +1506,10 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c lnd/clm2/surfdata_esmf/ctsm5.2.0/landuse.timeseries_4x5_SSP2-4.5_1850-2100_78pfts_c240216.nc -lnd/clm2/surfdata_esmf/ctsm5.2.0/landuse.timeseries_10x15_SSP2-4.5_1850-2100_78pfts_c240216.nc -lnd/clm2/surfdata_esmf/ctsm5.2.0/landuse.timeseries_360x720cru_SSP2-4.5_1850-2100_78pfts_c240216.nc - Full pathname of initial conditions file. If blank CLM will startup from arbitrary initial conditions. @@ -29,30 +29,30 @@ creating the output file specified by finidat_interp_dest. This requires that finidat be non-blank. - Full pathname of master restart file for a branch run. (only used if RUN_TYPE=branch) (Set with RUN_REFCASE and RUN_REFDATE) - Component name to use in history and restart files - Full pathname of land fraction data file. @@ -78,8 +78,8 @@ Type of CO2 feedback. -Supplemental Nitrogen mode and for what type of vegetation it's turned on for. -In this mode Nitrogen is unlimited rather than prognosed and in general vegetation is +Supplemental Nitrogen mode and for what type of vegetation it's turned on for. +In this mode Nitrogen is unlimited rather than prognosed and in general vegetation is over-productive. NONE = No vegetation types get supplemental Nitrogen ALL = Supplemental Nitrogen is active for all vegetation types @@ -123,7 +123,7 @@ Otherwise use the fraction straight up (the default for CLM5.0) 10SL_3.5m = standard CLM4 and CLM4.5 version -23SL_3.5m = more vertical layers for permafrost simulations +23SL_3.5m = more vertical layers for permafrost simulations 49SL_10m = 49 layer soil column, 10m of soil, 5 bedrock layers 20SL_8.5m = 20 layer soil column, 8m of soil, 5 bedrock layers 4SL_2m = 4 layer soil column, 2m of soil, 0 bedrock layers @@ -405,7 +405,7 @@ Index of solution method of Richards equation. Change method for richards equation solution and boundary conditions. -CLM 4.5 - soilwater_movement_method = 0 (Zeng and Decker, 2009, method). +CLM 4.5 - soilwater_movement_method = 0 (Zeng and Decker, 2009, method). CLM 5.0 - soilwater_movement_method = 1 (adaptive time stepping moisture form from Martyn Clark). 1 (adaptive time stepping moisture form @@ -425,7 +425,7 @@ lower_boundary_condition = 2 : zero-flux lower boundary condition lower_boundary_condition = 3 : water table head-based lower boundary condition w/ aquifer layer. (use with soilwater_movement_method=adaptive time stepping) lower_boundary_condition = 4 : 11-layer solution w/ aquifer layer (only used with soilwater_movement_method=Zeng&Decker 2009) -TODO(bja, 2015-09) these should be strings so they have meaningful names instead of ints. +TODO(bja, 2015-09) these should be strings so they have meaningful names instead of ints. If TRUE, irrigation will be active. - + If TRUE, fsat will be set to zero for crop columns. - + @@ -698,7 +698,7 @@ feature on will result in more memory usage. + group="clm_inparm" valid_values="" value=".false."> Toggle to turn on the tree damage module in FATES (Only relevant if FATES is on) @@ -709,7 +709,7 @@ Turn on spitfire module to simulate fire by setting fates_spitfire_mode > 0. Allowed values are: 0 : Simulations of fire are off 1 : use a global constant lightning rate found in fates_params. - 2 : use an external lightning dataset. + 2 : use an external lightning dataset. 3 : use an external confirmed ignitions dataset (not available through standard CSEM dataset collection). 4 : use external lightning and population datasets to simulate both natural and anthropogenic 5 : use gross domestic production and population datasets to simulate anthropogenic fire supression @@ -718,20 +718,20 @@ ignitions. + group="clm_inparm" valid_values="" value=".false."> Toggle to turn on fixed biogeography mode (Only relevant if FATES is on) -Toggle to turn on no competition mode (only relevant if FATES is being used). + group="clm_inparm" valid_values="" value=".false."> +Toggle to turn on no competition mode (only relevant if FATES is being used). -Toggle to turn on FATES satellite phenology mode (only relevant if FATES is being used). + group="clm_inparm" valid_values="" value=".false."> +Toggle to turn on FATES satellite phenology mode (only relevant if FATES is being used). - SNICAR (SNow, ICe, and Aerosol Radiative model) optical data file name - SNICAR (SNow, ICe, and Aerosol Radiative model) snow aging data file name @@ -1030,7 +1030,7 @@ Per tape series maximum number of time samples. -Per tape series history file density (i.e. output precision) +Per tape series history file density (i.e. output precision) 1=double precision 2=single precision Default: 2,2,2,2,2,2,2,2,2,2 @@ -1038,7 +1038,7 @@ Per tape series history file density (i.e. output precision) -Per tape series history write frequency. +Per tape series history write frequency. positive means in time steps 0=monthly negative means hours @@ -1085,7 +1085,7 @@ If TRUE, urban traffic flux will be activated (Currently NOT implemented). group="clm_humanindex_inparm" valid_values="ALL,FAST,NONE" > Human heat stress indices: ALL = All indices will be calculated - FAST = A subset of indices will be calculated (will not include the computationally + FAST = A subset of indices will be calculated (will not include the computationally expensive wet bulb calculation and associated indices) NONE = No indices will be calculated @@ -1146,7 +1146,7 @@ Turn on methane model. Standard part of CLM45BGC model. -CLM Biogeochemistry mode : Carbon Nitrogen model (CN) +CLM Biogeochemistry mode : Carbon Nitrogen model (CN) (or CLM45BGC if phys=clm4_5, vsoilc_centbgc='on', and clm4me='on') @@ -1164,7 +1164,7 @@ Requires the CN model to work (either CN or CNDV). -Nitrification/denitrification splits the prognostic mineral N pool into two +Nitrification/denitrification splits the prognostic mineral N pool into two mineral N pools: NO3 and NH4, and includes the transformations between them. Turned on for BGC FATES currently allows it to be true or false, but will be hardwired to true later @@ -1204,17 +1204,17 @@ Toggle to turn on the prognostic crop model -Toggle to turn on the prognostic fertilizer for crop model +Toggle to turn on the prognostic fertilizer for crop model -Toggle to turn on the 1-year grain product pool in the crop model +Toggle to turn on the 1-year grain product pool in the crop model -Fraction of post-harvest crop residues (leaf and stem) to move to +Fraction of post-harvest crop residues (leaf and stem) to move to 1-year product pool instead of letting them fall as litter. Default: 0.0 @@ -1223,7 +1223,7 @@ Fraction of post-harvest crop residues (leaf and stem) to move to group="crop_inparm" valid_values="constant,varytropicsbylat" value="constant"> Type of mapping to use for base temperature for prognostic crop model constant = Just use baset from the PFT parameter file -varytropicsbylat = Vary the tropics by latitude +varytropicsbylat = Vary the tropics by latitude - Parameter to set the type of ozone vegetation stress method - unset = (default) ozone stress vegetation method is off + Parameter to set the type of ozone vegetation stress method + unset = (default) ozone stress vegetation method is off stress_lombardozzi2015 = ozone stress vegetation functions from Danica Lombardozzi 2015 stress_falk = ozone stress vegetation functions from Stefanie Falk (issue #1224) Default: "unset" - - + + Phenology onset depends on the vegetation type @@ -1450,7 +1450,7 @@ by getco2_historical.ncl - Aerosol deposition file name (only used for aerdepregrid.ncl) @@ -1657,13 +1657,13 @@ mesh filename of input stream data for Zender's soil erodibility source function -Filename of input stream data for finundated inversion of observed (from Prigent dataset) +Filename of input stream data for finundated inversion of observed (from Prigent dataset) to hydrologic variables (either TWS or ZWT) -mesh filename of input stream data for finundated inversion of observed (from Prigent dataset) +mesh filename of input stream data for finundated inversion of observed (from Prigent dataset) to hydrologic variables (either TWS or ZWT) @@ -1748,7 +1748,7 @@ Filename of input stream data for LAI -dtlimit (ratio of max/min stream delta times) for LAI streams, which allows for cycling over a year of data +dtlimit (ratio of max/min stream delta times) for LAI streams, which allows for cycling over a year of data @@ -1798,7 +1798,6 @@ Mapping method from diurnal ozone input file to the model resolution copy = copy using the same indices - @@ -2009,10 +2008,10 @@ Mapping file to go from one resolution/land-mask to another resolution/land-mask Land mask description for mksurfdata input files - + @@ -2024,7 +2023,7 @@ Resolution of finundated inversion streams dataset (stream_fldfilename_ch4finund to use for methane model (only applies when CN and methane model are turned on) - + Resolution of Lightning dataset to use for CN or FATES fire model @@ -2043,46 +2042,46 @@ Add a note to the output namelist about the options given to build-namelist -CLM run type. +CLM run type. 'default' use the default type of clm_start type for this configuration 'cold' is a run from arbitrary initial conditions 'arb_ic' is a run using initial conditions if provided, OR arbitrary initial conditions if no files can be found - 'startup' is an initial run with initial conditions provided. + 'startup' is an initial run with initial conditions provided. 'continue' is a restart run. 'branch' is a restart run in which properties of the output history files may be changed. -Shared Socioeconomic Pathway (SSP) and Representative Concentration Pathway (RCP) combination for future scenarios +Shared Socioeconomic Pathway (SSP) and Representative Concentration Pathway (RCP) combination for future scenarios The form is SSPn-m.m Where n is the SSP number and m.m is RCP radiative forcing at peak or 2100 in W/m^2 n is just the whole number of the specific SSP scenario. The lower numbers have higher mitigation - the higher numbers less mitigation, more than one SSP can result in the same RCP forcing hist means do NOT use a future scenario, just use historical data. - + Land mask description - + General configuration of model version and atmospheric forcing to tune the model to run under. -This sets the model to run with constants and initial conditions that were set to run well under +This sets the model to run with constants and initial conditions that were set to run well under the configuration of model version and atmospheric forcing. To run well constants would need to be changed to run with a different type of atmospheric forcing. (Some options for the newest physics will be based on previous tuning, and buildnml will let you know about this) - + If 1, turn on the MEGAN model for BVOC's (Biogenic Volitile Organic Compounds) - + + + @@ -2144,8 +2143,8 @@ NOTE: THIS CORRESPONDS DIRECTLY TO THE env_run.xml VARIABLE OF THE SAME NAME. Command line arguement for biogeochemistry mode for CLM4.5 sp = Satellitte Phenology cn = Carbon Nitrogen model - bgc = CLM4.5 BGC model with: - CENTURY model pools + bgc = CLM4.5 BGC model with: + CENTURY model pools Nitrification/De-nitrification Methane model Vertically resolved Carbon @@ -2163,8 +2162,8 @@ Flag for overriding the crash that should occur if user tries to start the model -Flag for setting the state of the Accelerated decomposition spinup state for the BGC model. - 0 = normal model behavior; +Flag for setting the state of the Accelerated decomposition spinup state for the BGC model. + 0 = normal model behavior; 1 = AD spinup (standard) 2 = AD spinup (accelerated spinup from Ricciuto, doesn't work for CNDV and not implemented for CN soil decomposition) Entering and exiting spinup mode occurs automatically by comparing the namelist and restart file values for this variable. @@ -2224,7 +2223,7 @@ Soil decomposition method CENTURYKoven2013 -- CENTURY model in CTSM from Koven et. al. 2013 MIMICSWieder2015 -- MIMICS model in CTSM from Wieder et. al. 2015 -An active soil decomposition method requires the BGC or FATES model to work +An active soil decomposition method requires the BGC or FATES model to work And both BGC and FATES models require an active soil decomposition model @@ -2372,7 +2371,7 @@ Minimum lake depth to increase non-molecular thermal diffusivities by the factor group="clm_inparm" valid_values="" > Factor to increase non-molecular thermal diffusivities for lakes deeper than deepmixing_depthcrit to account for unresolved 3D processes. -Set to 1 to +Set to 1 to -Allows user to tune the value of aereoxid. If set to FALSE, then use the value of aereoxid from +Allows user to tune the value of aereoxid. If set to FALSE, then use the value of aereoxid from the parameter file (set to 0.0, but may be tuned with values in the range {0.0,1.0}. If set to TRUE, then don't fix aere (see ch4Mod.F90). Default: .true. @@ -2431,7 +2430,7 @@ so the coupled system will NOT conserve carbon in this mode if the methane model -Inundated fraction method type to use for the CH4 submodel (possibly affecting soil +Inundated fraction method type to use for the CH4 submodel (possibly affecting soil heterotrophic respiration and denitrification depending on the configuration), h2osfc ----------- Use prognostic saturated fraction h2osfc value calculated in Soil Hydrology @@ -2608,7 +2607,7 @@ Values less than 5 are mainly useful for testing, and should not be used for sci -Maximum snow depth in mm H2O equivalent. Additional mass gains will be capped when this depth +Maximum snow depth in mm H2O equivalent. Additional mass gains will be capped when this depth is exceeded. Changes in this value should possibly be accompanied by changes in: - nlevsno: larger values of h2osno_max should be accompanied by increases in nlevsno @@ -2732,8 +2731,8 @@ differently in areas below and above reset_snow_glc_ela. Only relevant if reset_snow_glc is .true. When resetting snow pack over glacier columns, one can choose to do this over all glacier -columns, or only those below a certain elevation. A typical use case is to reset only those -columns that have a seasonal snow pack in the real world, i.e. SMB less than 0, also known as +columns, or only those below a certain elevation. A typical use case is to reset only those +columns that have a seasonal snow pack in the real world, i.e. SMB less than 0, also known as the equilibrium line altitude (ELA). This parameter sets a single global ELA value. By setting this parameter to a large value (i.e. 10000 m), all glacier columns will be reset. @@ -2770,7 +2769,7 @@ the related bulk quantities. If .true., run with water isotopes - + From 0586a7add1bc8966af5f2166cdcd8ec39acec97b Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Fri, 26 Apr 2024 11:52:14 -0600 Subject: [PATCH 34/39] more ws --- src/cpl/nuopc/lnd_import_export.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cpl/nuopc/lnd_import_export.F90 b/src/cpl/nuopc/lnd_import_export.F90 index 30c9f6eec3..11cc807640 100644 --- a/src/cpl/nuopc/lnd_import_export.F90 +++ b/src/cpl/nuopc/lnd_import_export.F90 @@ -1330,7 +1330,7 @@ subroutine ReadCapNamelist( NLFilename, rc ) integer, target :: tmp(1) type(ESMF_VM) :: vm character(*), parameter :: nml_name = "ctsm_nuopc_cap" ! MUST match with namelist name below - + namelist /ctsm_nuopc_cap/ force_send_to_atm @@ -1355,7 +1355,7 @@ subroutine ReadCapNamelist( NLFilename, rc ) ! Broadcast namelist to all processors call ESMF_VMBroadcast(vm, tmp, 1, 0, rc=rc) - + force_send_to_atm = (tmp(1) == 1) if (ChkErr(rc,__LINE__,u_FILE_u)) return From dfe6489dbec474276334f011b74fd5d69aa548d3 Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Fri, 26 Apr 2024 11:56:14 -0600 Subject: [PATCH 35/39] even more ws --- src/main/clm_varctl.F90 | 98 ++++++++++++++++++++--------------------- src/main/controlMod.F90 | 20 ++++----- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 82f4cdb40b..0a94e0ca1a 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -27,27 +27,27 @@ module clm_varctl ! Run control variables ! ! case id - character(len=256), public :: caseid = ' ' + character(len=256), public :: caseid = ' ' ! case title - character(len=256), public :: ctitle = ' ' + character(len=256), public :: ctitle = ' ' ! Type of run - integer, public :: nsrest = iundef + integer, public :: nsrest = iundef logical, public :: is_cold_start = .false. ! Startup from initial conditions - integer, public, parameter :: nsrStartup = 0 + integer, public, parameter :: nsrStartup = 0 ! Continue from restart files - integer, public, parameter :: nsrContinue = 1 + integer, public, parameter :: nsrContinue = 1 ! Branch from restart files - integer, public, parameter :: nsrBranch = 2 + integer, public, parameter :: nsrBranch = 2 ! true => allow case name to remain the same for branch run ! by default this is not allowed - logical, public :: brnch_retain_casename = .false. + logical, public :: brnch_retain_casename = .false. ! true => run tests of ncdio_pio logical, public :: for_testing_run_ncdiopio_tests = .false. @@ -74,19 +74,19 @@ module clm_varctl logical, public :: for_testing_no_crop_seed_replenishment = .false. ! Hostname of machine running on - character(len=256), public :: hostname = ' ' + character(len=256), public :: hostname = ' ' ! username of user running program - character(len=256), public :: username = ' ' + character(len=256), public :: username = ' ' ! description of this source character(len=256), public :: source = "Community Terrestrial Systems Model" ! version of program - character(len=256), public :: version = " " + character(len=256), public :: version = " " ! dataset conventions - character(len=256), public :: conventions = "CF-1.0" + character(len=256), public :: conventions = "CF-1.0" ! component name for filenames (history or restart files) character(len=8), public :: compname = 'clm2' @@ -120,14 +120,14 @@ module clm_varctl !---------------------------------------------------------- ! Flag to read ndep rather than obtain it from coupler !---------------------------------------------------------- - + logical, public :: ndep_from_cpl = .false. !---------------------------------------------------------- ! Interpolation of finidat if requested !---------------------------------------------------------- - logical, public :: bound_h2osoi = .true. ! for debugging + logical, public :: bound_h2osoi = .true. ! for debugging ! If finidat_interp_source is non-blank and finidat is blank then interpolation will be ! done from finidat_interp_source to finidat_interp_dest. Note that @@ -150,8 +150,8 @@ module clm_varctl logical, public, parameter :: use_crop_agsys = .false. ! true => separate crop landunit is not created by default - logical, public :: create_crop_landunit = .false. - + logical, public :: create_crop_landunit = .false. + ! number of hillslopes per landunit integer, public :: nhillslope = 0 @@ -159,14 +159,14 @@ module clm_varctl integer, public :: max_columns_hillslope = 1 ! do not irrigate by default - logical, public :: irrigate = .false. + logical, public :: irrigate = .false. ! set saturated excess runoff to zero for crops logical, public :: crop_fsat_equals_zero = .false. ! remove this fraction of crop residues to a 1-year product pool (instead of going to litter) real(r8), public :: crop_residue_removal_frac = 0.0 - + !---------------------------------------------------------- ! Other subgrid logic !---------------------------------------------------------- @@ -175,7 +175,7 @@ module clm_varctl logical, public :: run_zero_weight_urban = .false. ! true => make ALL patches, cols & landunits active (even if weight is 0) - logical, public :: all_active = .false. + logical, public :: all_active = .false. ! true => any ocean (i.e., "wetland") points on the surface dataset are converted to ! bare ground (or whatever vegetation is given in that grid cell... but typically this @@ -198,33 +198,33 @@ module clm_varctl !---------------------------------------------------------- ! values of 'prognostic','diagnostic','constant' - character(len=16), public :: co2_type = 'constant' + character(len=16), public :: co2_type = 'constant' - ! State of the model for the accelerated decomposition (AD) spinup. + ! State of the model for the accelerated decomposition (AD) spinup. ! 0 (default) = normal model; 1 = AD SPINUP - integer, public :: spinup_state = 0 + integer, public :: spinup_state = 0 ! true => anoxia is applied to heterotrophic respiration also considered in CH4 model ! default value reset in controlMod - logical, public :: anoxia = .true. + logical, public :: anoxia = .true. ! used to override an error check on reading in restart files - logical, public :: override_bgc_restart_mismatch_dump = .false. + logical, public :: override_bgc_restart_mismatch_dump = .false. ! Set in CNAllocationInit (TODO - had to move it here to avoid circular dependency) - logical, private:: carbon_only + logical, private:: carbon_only - ! Set in CNNDynamicsInit + ! Set in CNNDynamicsInit ! NOTE (mvertens, 2014-9 had to move it here to avoid confusion when carbon data types - ! wehre split - TODO - should move it our of this module) + ! wehre split - TODO - should move it our of this module) ! NOTE(bandre, 2013-10) according to Charlie Koven, nfix_timeconst - ! is currently used as a flag and rate constant. + ! is currently used as a flag and rate constant. ! Rate constant: time over which to exponentially relax the npp flux for N fixation term ! (days) time over which to exponentially relax the npp flux for N fixation term - ! flag: (if <= 0. or >= 365; use old annual method). + ! flag: (if <= 0. or >= 365; use old annual method). ! Default value is junk that should always be overwritten by the namelist or init function! ! - real(r8), public :: nfix_timeconst = -1.2345_r8 + real(r8), public :: nfix_timeconst = -1.2345_r8 !---------------------------------------------------------- ! Physics @@ -241,19 +241,19 @@ module clm_varctl ! atmospheric CO2 molar ratio (by volume) (umol/mol) real(r8), public :: co2_ppmv = 355._r8 ! - ! ozone vegitation stress method, valid values: unset, stress_lombardozzi2015, stress_falk + ! ozone vegetation stress method, valid values: unset, stress_lombardozzi2015, stress_falk character(len=64), public :: o3_veg_stress_method = 'unset' - - ! other o3_streams parameters + + ! o3_streams parameters logical, public :: use_do3_streams = .false. character(len=fname_len), public :: stream_fldfilename_do3 character(len=fname_len), public :: stream_meshfile_do3 character(len=fname_len), public :: do3_mapalgo - + real(r8), public :: o3_ppbv = 100._r8 ! number of wavelength bands used in SNICAR snow albedo calculation - integer, public :: snicar_numrad_snw = 5 + integer, public :: snicar_numrad_snw = 5 ! type of downward solar radiation spectrum for SNICAR snow albedo calculation ! options: @@ -322,7 +322,7 @@ module clm_varctl integer, public :: fates_parteh_mode = -9 ! 1 => carbon only ! 2 => C+N+P (not enabled yet) ! no others enabled - integer, public :: fates_spitfire_mode = 0 + integer, public :: fates_spitfire_mode = 0 ! 0 for no fire; 1 for constant ignitions; ! > 1 for external data (lightning and/or anthropogenic ignitions) ! see bld/namelist_files/namelist_definition_clm4_5.xml for details @@ -342,13 +342,13 @@ module clm_varctl ! Performing this output can be expensive, so we allow different history dimension ! levels. ! The first index is output at the model timescale - ! The second index is output at the dynamics (daily) timescale + ! The second index is output at the dynamics (daily) timescale ! 0 - no output ! 1 - include only column level means (3D) ! 2 - include output that includes the 4th dimension - + integer, dimension(2), public :: fates_history_dimlevel = (/2,2/) - + logical, public :: use_fates_luh = .false. ! true => use FATES landuse data mode character(len=256), public :: fluh_timeseries = '' ! filename for fates landuse timeseries data character(len=256), public :: fates_inventory_ctrl_filename = '' ! filename for inventory control @@ -357,9 +357,9 @@ module clm_varctl ! BUT... THEY CAN BOTH BE OFF (IF FATES IS OFF) logical, public :: use_fates_sp = .false. ! true => use FATES satellite phenology mode logical, public :: use_fates_bgc = .false. ! true => use FATES along with CLM soil biogeochemistry - + !---------------------------------------------------------- - ! LUNA switches + ! LUNA switches !---------------------------------------------------------- logical, public :: use_luna = .false. ! true => use LUNA @@ -379,7 +379,7 @@ module clm_varctl integer, public :: carbon_resp_opt = 0 !---------------------------------------------------------- - ! prescribed soil moisture streams switch + ! prescribed soil moisture streams switch !---------------------------------------------------------- logical, public :: use_soil_moisture_streams = .false. ! true => use prescribed soil moisture stream @@ -442,11 +442,11 @@ module clm_varctl ! glacier_mec control variables: default values (may be overwritten by namelist) !---------------------------------------------------------- - ! true => CLM glacier area & topography changes dynamically - logical , public :: glc_do_dynglacier = .false. + ! true => CLM glacier area & topography changes dynamically + logical , public :: glc_do_dynglacier = .false. ! number of days before one considers the perennially snow-covered point 'land ice' - integer , public :: glc_snow_persistence_max_days = 7300 + integer , public :: glc_snow_persistence_max_days = 7300 ! !---------------------------------------------------------- @@ -470,21 +470,21 @@ module clm_varctl !---------------------------------------------------------- ! number of segments per clump for decomp - integer, public :: nsegspc = 20 + integer, public :: nsegspc = 20 !---------------------------------------------------------- ! Derived variables (run, history and restart file) !---------------------------------------------------------- ! directory name for local restart pointer file - character(len=256), public :: rpntdir = '.' + character(len=256), public :: rpntdir = '.' ! file name for local restart pointer file - character(len=256), public :: rpntfil = 'rpointer.lnd' + character(len=256), public :: rpntfil = 'rpointer.lnd' ! moved hist_wrtch4diag from histFileMod.F90 to here - caused compiler error with intel ! namelist: write CH4 extra diagnostic output - logical, public :: hist_wrtch4diag = .false. + logical, public :: hist_wrtch4diag = .false. ! namelist: write list of all history fields to a file for use in documentation logical, public :: hist_fields_list_file = .false. @@ -538,7 +538,7 @@ subroutine clm_varctl_set( caseid_in, ctitle_in, brnch_retain_casename_in, & ! !ARGUMENTS: character(len=256), optional, intent(IN) :: caseid_in ! case id character(len=256), optional, intent(IN) :: ctitle_in ! case title - logical, optional, intent(IN) :: brnch_retain_casename_in ! true => allow case name to remain the + logical, optional, intent(IN) :: brnch_retain_casename_in ! true => allow case name to remain the ! same for branch run logical, optional, intent(IN) :: single_column_in ! true => single column mode real(r8), optional, intent(IN) :: scmlat_in ! single column lat diff --git a/src/main/controlMod.F90 b/src/main/controlMod.F90 index fb61a0a958..a7787f4257 100644 --- a/src/main/controlMod.F90 +++ b/src/main/controlMod.F90 @@ -245,9 +245,9 @@ subroutine control_init(dtime) fates_history_dimlevel ! Ozone vegetation stress method and streams file - namelist / clm_inparm / o3_veg_stress_method, use_do3_streams, & + namelist / clm_inparm / o3_veg_stress_method, use_do3_streams, & stream_fldfilename_do3, stream_meshfile_do3, do3_mapalgo - + ! CLM 5.0 nitrogen flags namelist /clm_inparm/ use_flexibleCN, use_luna @@ -466,7 +466,7 @@ subroutine control_init(dtime) else use_fates_bgc = .true. end if - + if (fates_parteh_mode == 1 .and. suplnitro == suplnNon .and. use_fates_bgc )then write(iulog,*) ' When FATES with fates_parteh_mode == 1 (ie carbon only mode),' write(iulog,*) ' you must have supplemental nitrogen turned on, there will be' @@ -475,7 +475,7 @@ subroutine control_init(dtime) call endrun(msg=' ERROR: fates_parteh_mode=1 must have suplnitro set to suplnAll.'//& errMsg(sourcefile, __LINE__)) end if - + if ( use_cn) then call endrun(msg=' ERROR: use_cn and use_fates cannot both be set to true.'//& errMsg(sourcefile, __LINE__)) @@ -507,21 +507,21 @@ subroutine control_init(dtime) end if else - + ! These do default to false anyway, but this emphasizes they ! are false when fates is false use_fates_sp = .false. use_fates_bgc = .false. - + end if ! Check compatibility with use_lai_streams if (use_lai_streams) then - if ((use_fates .and. .not. use_fates_sp) .or. use_cn) then + if ((use_fates .and. .not. use_fates_sp) .or. use_cn) then call endrun(msg=' ERROR: cannot use LAI streams unless in SP mode (use_cn = .false. or use_fates_sp=.true.).'//& errMsg(sourcefile, __LINE__)) - end if - end if + end if + end if ! If nfix_timeconst is equal to the junk default value, then it was not specified ! by the user namelist and we need to assign it the correct default value. If the @@ -775,7 +775,7 @@ subroutine control_spmd() ! BGC call mpi_bcast (co2_type, len(co2_type), MPI_CHARACTER, 0, mpicom, ier) - + call mpi_bcast (use_fates, 1, MPI_LOGICAL, 0, mpicom, ier) if (use_cn .or. use_fates) then From f1778be901694611a9f5519aae1122a1b3fbb7d6 Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Mon, 6 May 2024 16:03:01 -0600 Subject: [PATCH 36/39] change logic for use_do3_streams --- bld/CLMBuildNamelist.pm | 2 +- bld/namelist_files/namelist_defaults_ctsm.xml | 3 +-- src/biogeophys/OzoneMod.F90 | 5 +++-- src/main/clm_varctl.F90 | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/bld/CLMBuildNamelist.pm b/bld/CLMBuildNamelist.pm index 6961558149..019fa281d6 100755 --- a/bld/CLMBuildNamelist.pm +++ b/bld/CLMBuildNamelist.pm @@ -4247,7 +4247,7 @@ sub setup_logic_do3_streams { } else { if ( defined($nl->get_value('stream_fldfilename_do3'))) { $log->fatal_error("One of the do3 streams namelist items (stream_fldfilename_do3, " . - " is defined, but use_do3_streams option NOT set to true"); + " is defined, but use_do3_streams option set to false"); } } } diff --git a/bld/namelist_files/namelist_defaults_ctsm.xml b/bld/namelist_files/namelist_defaults_ctsm.xml index c1a7720510..29e1c56606 100644 --- a/bld/namelist_files/namelist_defaults_ctsm.xml +++ b/bld/namelist_files/namelist_defaults_ctsm.xml @@ -1733,8 +1733,7 @@ lnd/clm2/surfdata_esmf/NEON/surfdata_1x1_NEON_TOOL_hist_78pfts_CMIP6_simyr2000_c nn -.false. - +.true. /glade/work/afoster/ozone_update/ozone_damage_files/converted/diurnal_factor_O3surface_ssp370_2015-2024_c20220502.nc share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc bilinear diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 8c7dbb7b50..4e01e47def 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -26,6 +26,7 @@ module OzoneMod use shr_ozone_coupling_mod , only : atm_ozone_frequency_multiday_average, shr_ozone_coupling_readnl use DiurnalOzoneType , only : diurnal_ozone_anom_type use diurnalOzoneStreamMod , only : read_O3_stream + use controlMod , only : use_do3_streams implicit none save @@ -162,7 +163,7 @@ subroutine Init(this, bounds, o3_veg_stress_method) ! if we have multi-day average input ozone, we need to convert to sub-daily using ! an input anomaly file - if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then + if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average .and. use_do3_streams) then ! initialize and read in data for diurnal O3 anomaly stream call read_O3_stream(this%diurnalOzoneAnomInst, bounds) end if @@ -440,7 +441,7 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & tlai_old => this%tlai_old_patch & ! Output: [real(r8) (:)] tlai from last time step ) - if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average) then + if (this%atm_ozone_freq == atm_ozone_frequency_multiday_average .and. use_do3_streams) then call this%diurnalOzoneAnomInst%Interp(bounds, forc_o3, forc_o3_down) else forc_o3_down(bounds%begg:bounds%endg) = forc_o3(bounds%begg:bounds%endg) diff --git a/src/main/clm_varctl.F90 b/src/main/clm_varctl.F90 index 0a94e0ca1a..59d8aeafff 100644 --- a/src/main/clm_varctl.F90 +++ b/src/main/clm_varctl.F90 @@ -245,7 +245,7 @@ module clm_varctl character(len=64), public :: o3_veg_stress_method = 'unset' ! o3_streams parameters - logical, public :: use_do3_streams = .false. + logical, public :: use_do3_streams = .true. character(len=fname_len), public :: stream_fldfilename_do3 character(len=fname_len), public :: stream_meshfile_do3 character(len=fname_len), public :: do3_mapalgo From 8875fba44cbc855a040a3030614bb2973caac69f Mon Sep 17 00:00:00 2001 From: Adrianna Foster Date: Mon, 6 May 2024 18:59:33 -0600 Subject: [PATCH 37/39] fix assert --- src/biogeophys/DiurnalOzoneType.F90 | 121 ++++++++++++++-------------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 7d332c241f..e77b69b6e2 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -6,7 +6,7 @@ module DiurnalOzoneType ! ozone anomaly file ! ! !USES: - #include "shr_assert.h" +#include "shr_assert.h" use shr_kind_mod , only : r8 => shr_kind_r8 use decompMod , only : bounds_type use clm_varcon , only : spval @@ -36,7 +36,6 @@ module DiurnalOzoneType character(len=*), parameter, private :: sourcefile = & __FILE__ - contains ! ======================================================================== @@ -64,7 +63,6 @@ subroutine Init(this, bounds, n) end subroutine Init - !----------------------------------------------------------------------- subroutine InitAllocate(this, bounds) ! @@ -87,72 +85,71 @@ subroutine InitAllocate(this, bounds) allocate(this%o3_anomaly_grc(begg:endg,1:this%ntimes)); this%o3_anomaly_grc(:,:) = nan allocate(this%time_arr(1:this%ntimes)); this%time_arr(:) = nan - end subroutine InitAllocate - - !----------------------------------------------------------------------- + end subroutine InitAllocate !----------------------------------------------------------------------- - subroutine Interp(this, bounds, forc_o3, forc_o3_down) - ! - ! !DESCRIPTION: - ! Downscale/interpolate multi-day ozone data to subdaily - ! - ! !USES: - use clm_time_manager , only : get_curr_date - use clm_varcon , only : secspday - ! - ! !ARGUMENTS: - class(diurnal_ozone_anom_type), intent(in) :: this - type(bounds_type), intent(in) :: bounds ! bounds type - real(r8), intent(in) :: forc_o3(:) ! ozone partial pressure (mol/mol) - real(r8), intent(out) :: forc_o3_down(:) ! ozone partial pressure, downscaled (mol/mol) - ! - ! LOCAL VARIABLES: - integer :: t ! looping index - integer :: yr ! year - integer :: mon ! month - integer :: day ! day of month - integer :: tod ! time of day (seconds past 0Z) - integer :: begg, endg ! bounds - integer :: t_prev ! previous time index - real(r8) :: tdiff_end - real(r8) :: tdiff_start - real(r8) :: tdiff - !----------------------------------------------------------------------- + subroutine Interp(this, bounds, forc_o3, forc_o3_down) + ! + ! !DESCRIPTION: + ! Downscale/interpolate multi-day ozone data to subdaily + ! + ! !USES: + use clm_time_manager , only : get_curr_date + use clm_varcon , only : secspday + ! + ! !ARGUMENTS: + class(diurnal_ozone_anom_type), intent(in) :: this + type(bounds_type), intent(in) :: bounds ! bounds type + real(r8), intent(in) :: forc_o3(:) ! ozone partial pressure (mol/mol) + real(r8), intent(out) :: forc_o3_down(:) ! ozone partial pressure, downscaled (mol/mol) - begg = bounds%begg; endg = bounds%endg + ! + ! LOCAL VARIABLES: + integer :: t ! looping index + integer :: yr ! year + integer :: mon ! month + integer :: day ! day of month + integer :: tod ! time of day (seconds past 0Z) + integer :: begg, endg ! bounds + integer :: t_prev ! previous time index + real(r8) :: tdiff_end + real(r8) :: tdiff_start + real(r8) :: tdiff + !----------------------------------------------------------------------- - ! Get current date/time - we really only need seconds - call get_curr_date(yr, mon, day, tod) + begg = bounds%begg; endg = bounds%endg - ! find the time interval we are in - do t = 1, this%ntimes - if (real(tod) <= this%time_arr(t)) then - exit + ! Get current date/time - we really only need seconds + call get_curr_date(yr, mon, day, tod) + + ! find the time interval we are in + do t = 1, this%ntimes + if (real(tod) <= this%time_arr(t)) then + exit + end if + end do + + ! interpolate, checking for edge cases + if (t == 1) then + ! wrap around back + t_prev = this%ntimes + tdiff_end = secspday - this%time_arr(t_prev) + real(tod) + tdiff = this%time_arr(t) + secspday - this%time_arr(t_prev) + else + t_prev = t - 1 + tdiff_end = real(tod) - this%time_arr(t_prev) + tdiff = this%time_arr(t) - this%time_arr(t_prev) end if - end do - - ! interpolate, checking for edge cases - if (t == 1) then - ! wrap around back - t_prev = this%ntimes - tdiff_end = secspday - this%time_arr(t_prev) + real(tod) - tdiff = this%time_arr(t) + secspday - this%time_arr(t_prev) - else - t_prev = t - 1 - tdiff_end = real(tod) - this%time_arr(t_prev) - tdiff = this%time_arr(t) - this%time_arr(t_prev) - end if - - tdiff_start = this%time_arr(t) - real(tod) - - ! interpolate - forc_o3_down(begg:endg) = forc_o3(begg:endg)* & - ((this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_start + & - this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_end)/tdiff) - - end subroutine Interp + + tdiff_start = this%time_arr(t) - real(tod) + + ! interpolate + forc_o3_down(begg:endg) = forc_o3(begg:endg)* & + ((this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_start + & + this%o3_anomaly_grc(begg:endg, t_prev)*tdiff_end)/tdiff) + + end subroutine Interp !----------------------------------------------------------------------- From ebcdeda8ddb813aea7728e9ecff94f4227571f21 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Wed, 8 May 2024 11:23:55 -0600 Subject: [PATCH 38/39] update indentation --- src/biogeophys/DiurnalOzoneType.F90 | 2 +- src/biogeophys/OzoneMod.F90 | 61 +++++++++++++++-------------- 2 files changed, 32 insertions(+), 31 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index e77b69b6e2..22d63a1d20 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -25,7 +25,7 @@ module DiurnalOzoneType real(r8), public, allocatable :: o3_anomaly_grc(:,:) ! o3 anomaly data [grc, ntimes] real(r8), public, allocatable :: time_arr(:) ! time dimension (units = seconds of day) - contains + contains ! Public routines procedure, public :: Init procedure, private :: InitAllocate diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 4e01e47def..4eb00999c4 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -62,7 +62,7 @@ module OzoneMod real(r8), pointer :: tlai_old_patch(:) ! tlai from last time step type(diurnal_ozone_anom_type) :: diurnalOzoneAnomInst - contains + contains ! Public routines procedure, public :: Init procedure, public :: Restart @@ -146,7 +146,7 @@ subroutine Init(this, bounds, o3_veg_stress_method) ! Initialize ozone data structure ! ! !USES: - use clm_varctl , only : use_luna + use clm_varctl , only : use_luna ! ! !ARGUMENTS: class(ozone_type), intent(inout) :: this @@ -251,10 +251,10 @@ subroutine InitHistory(this, bounds) avgflag='A', long_name='total ozone flux into shaded leaves', & ptr_patch=this%o3uptakesha_patch) - this%o3force_grid(begg:endg) = spval - call hist_addfld1d (fname='FORCE_O3', units='mol/mol', & - avgflag='A', long_name='ozone partial pressure', & - ptr_lnd=this%o3force_grid) + this%o3force_grid(begg:endg) = spval + call hist_addfld1d (fname='FORCE_O3', units='mol/mol', & + avgflag='A', long_name='ozone partial pressure', & + ptr_lnd=this%o3force_grid) if (this%stress_method==stress_method_lombardozzi2015) then ! For this and the following variables: how should we include leaf area in the @@ -446,30 +446,31 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & else forc_o3_down(bounds%begg:bounds%endg) = forc_o3(bounds%begg:bounds%endg) end if - this%o3force_grid(bounds%begg:bounds%endg) = forc_o3_down(bounds%begg:bounds%endg) - - do fp = 1, num_exposedvegp - p = filter_exposedvegp(fp) - c = patch%column(p) - g = patch%gridcell(p) - - ! Ozone uptake for shaded leaves - call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & - rs=rssha(p), rb=rb(p), ram=ram(p), & - tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & - o3uptake=o3uptakesha(p)) - - ! Ozone uptake for sunlit leaves - call CalcOzoneUptakeOnePoint( & - forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & - rs=rssun(p), rb=rb(p), ram=ram(p), & - tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & - o3uptake=o3uptakesun(p)) - - tlai_old(p) = tlai(p) - - end do + + this%o3force_grid(bounds%begg:bounds%endg) = forc_o3_down(bounds%begg:bounds%endg) + + do fp = 1, num_exposedvegp + p = filter_exposedvegp(fp) + c = patch%column(p) + g = patch%gridcell(p) + + ! Ozone uptake for shaded leaves + call CalcOzoneUptakeOnePoint( & + forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + rs=rssha(p), rb=rb(p), ram=ram(p), & + tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & + o3uptake=o3uptakesha(p)) + + ! Ozone uptake for sunlit leaves + call CalcOzoneUptakeOnePoint( & + forc_ozone=forc_o3_down(g), forc_pbot=forc_pbot(c), forc_th=forc_th(c), & + rs=rssun(p), rb=rb(p), ram=ram(p), & + tlai=tlai(p), tlai_old=tlai_old(p), pft_type=patch%itype(p), & + o3uptake=o3uptakesun(p)) + + tlai_old(p) = tlai(p) + + end do end associate From bfbe3502c1e8e3ac1514fb690722a1ad946d5986 Mon Sep 17 00:00:00 2001 From: adrifoster Date: Fri, 17 May 2024 08:53:50 -0600 Subject: [PATCH 39/39] fixing indentation inconsistencies --- src/biogeophys/DiurnalOzoneType.F90 | 8 ++++---- src/biogeophys/OzoneMod.F90 | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/biogeophys/DiurnalOzoneType.F90 b/src/biogeophys/DiurnalOzoneType.F90 index 22d63a1d20..bb8a327817 100644 --- a/src/biogeophys/DiurnalOzoneType.F90 +++ b/src/biogeophys/DiurnalOzoneType.F90 @@ -109,10 +109,10 @@ subroutine Interp(this, bounds, forc_o3, forc_o3_down) integer :: t ! looping index integer :: yr ! year integer :: mon ! month - integer :: day ! day of month - integer :: tod ! time of day (seconds past 0Z) - integer :: begg, endg ! bounds - integer :: t_prev ! previous time index + integer :: day ! day of month + integer :: tod ! time of day (seconds past 0Z) + integer :: begg, endg ! bounds + integer :: t_prev ! previous time index real(r8) :: tdiff_end real(r8) :: tdiff_start real(r8) :: tdiff diff --git a/src/biogeophys/OzoneMod.F90 b/src/biogeophys/OzoneMod.F90 index 4eb00999c4..6d2630d4ef 100644 --- a/src/biogeophys/OzoneMod.F90 +++ b/src/biogeophys/OzoneMod.F90 @@ -212,7 +212,7 @@ subroutine InitAllocate(this, bounds) allocate(this%o3uptakesha_patch(begp:endp)) ; this%o3uptakesha_patch(:) = nan allocate(this%o3uptakesun_patch(begp:endp)) ; this%o3uptakesun_patch(:) = nan allocate(this%tlai_old_patch(begp:endp)) ; this%tlai_old_patch(:) = nan - allocate(this%o3force_grid(begg:endg)) ; this%o3force_grid(:) = nan + allocate(this%o3force_grid(begg:endg)) ; this%o3force_grid(:) = nan end subroutine InitAllocate @@ -417,10 +417,10 @@ subroutine CalcOzoneUptake(this, bounds, num_exposedvegp, filter_exposedvegp, & ! ! !LOCAL VARIABLES: real(r8) :: forc_o3_down(bounds%begg:bounds%endg) ! downscaled ozone partial pressure (mol/mol) - integer :: fp ! filter index - integer :: p ! patch index - integer :: c ! column index - integer :: g ! gridcell index + integer :: fp ! filter index + integer :: p ! patch index + integer :: c ! column index + integer :: g ! gridcell index character(len=*), parameter :: subname = 'CalcOzoneUptake' !-----------------------------------------------------------------------