From e4663bdd01c23a538327ed45dad9a66aa5e07aec Mon Sep 17 00:00:00 2001 From: Bin Liu Date: Wed, 4 Aug 2021 14:02:16 -0400 Subject: [PATCH 01/28] Updates CDEPS to latest ESCOMP/master with HAFS coupling related changes (#35) --- .github/workflows/extbuild.yml | 4 +- cime_config/buildlib | 39 +++- cime_config/stream_cdeps.py | 17 +- cime_config/testdefs/testlist_cdeps.xml | 2 +- datm/cime_config/buildnml | 59 +++++- datm/cime_config/stream_definition_datm.xml | 11 +- datm/datm_datamode_era5_mod.F90 | 212 ++++++++++---------- dice/cime_config/buildnml | 2 +- dlnd/cime_config/buildnml | 2 +- docn/cime_config/buildnml | 2 +- drof/cime_config/buildnml | 2 +- dshr/dshr_mod.F90 | 35 +++- dwav/cime_config/buildnml | 2 +- streams/dshr_strdata_mod.F90 | 25 ++- streams/dshr_stream_mod.F90 | 8 +- 15 files changed, 259 insertions(+), 163 deletions(-) diff --git a/.github/workflows/extbuild.yml b/.github/workflows/extbuild.yml index 7dd99b5e9..12e57ea22 100644 --- a/.github/workflows/extbuild.yml +++ b/.github/workflows/extbuild.yml @@ -34,7 +34,9 @@ jobs: path: ~/ESMF key: ${{ runner.os }}-${{ env.ESMF_VERSION }}-ESMF - id: load-env - run: sudo apt-get install gfortran wget openmpi-bin netcdf-bin libopenmpi-dev libnetcdf-dev + run: | + sudo apt-get update + sudo apt-get install gfortran wget openmpi-bin netcdf-bin libopenmpi-dev libnetcdf-dev - id: build-ESMF if: steps.cache-esmf.outputs.cache-hit != 'true' run: | diff --git a/cime_config/buildlib b/cime_config/buildlib index 72a21593c..7d22f4a9d 100755 --- a/cime_config/buildlib +++ b/cime_config/buildlib @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """ build cime component model library. This buildlib script is used by all CDEPS components. @@ -11,7 +11,7 @@ if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "lib") sys.path.append(_LIBDIR) from standard_script_setup import * @@ -25,6 +25,7 @@ from CIME.XML.compilers import Compilers logger = logging.getLogger(__name__) def buildlib(bldroot, libroot, case, compname=None): + print("HERE cwd is {}".format(os.getcwd())) if bldroot.endswith("obj") and not compname: compname = os.path.basename(os.path.abspath(os.path.join(bldroot,os.pardir))) @@ -63,8 +64,31 @@ def buildlib(bldroot, libroot, case, compname=None): cmake_flags += " -DPIO_C_LIBRARY={path}/lib -DPIO_C_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) cmake_flags += " -DPIO_Fortran_LIBRARY={path}/lib -DPIO_Fortran_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) cmake_flags += srcpath + all_src_files = list(all_files_under(srcpath, ignoredirs=[".git","cmake","test",".github","cime_config","fox"])) + # Search SourceMods path for CDEPS files. We only look in the data component directories for these, files in cdeps share + # directories should be added to one of the data component directories + srcmodsdir = os.path.join(case.get_value("CASEROOT"),"SourceMods") + all_files_in_srcmods = [] + for comp_class in case.get_values("COMP_CLASSES"): + if comp_class == "CPL": + continue + comp = case.get_value("COMP_{}".format(comp_class)) + cdeps_comp_name = "d"+comp_class.lower() + if comp == cdeps_comp_name: + all_files_in_srcmods.extend(list(all_files_under(os.path.join(srcmodsdir,"src."+cdeps_comp_name)))) + + basenames1 = [os.path.basename(f) for f in all_src_files] + basenames2 = [os.path.basename(f) for f in all_files_in_srcmods] + srcmods = list(set(basenames1).intersection(set(basenames2))) + if srcmods: + logger.info("Found SourceMods {}".format(srcmods)) + for i, v in enumerate(all_src_files): + for sfile in all_files_in_srcmods: + if os.path.basename(sfile) == os.path.basename(v): + all_src_files[i] = v.replace(os.path.dirname(v), os.path.dirname(sfile)) + logger.debug("all_src_files: {}".format(all_src_files)) + latest_src_file = max(all_src_files, key=os.path.getmtime) - latest_src_file = max(all_files_under(srcpath), key=os.path.getmtime) src_time = os.path.getmtime(latest_src_file) if os.path.exists(os.path.join(bldroot,"CMakeFiles")): bld_time = os.path.getmtime(os.path.join(bldroot,"CMakeFiles")) @@ -87,7 +111,6 @@ def buildlib(bldroot, libroot, case, compname=None): if time_counter > time_to_wait: break expect(time_counter <= time_to_wait," Timeout waiting for {}".format(dwav_lib)) - print("HERE exeroot {} bldroot {}".format(exe_root, bldroot)) s,o,e = run_cmd("make install VERBOSE=1 DESTDIR={}".format(libroot), from_dir=bldroot, verbose=True) expect(not s,"ERROR from make output={}, error={}".format(o,e)) @@ -101,9 +124,10 @@ def buildlib(bldroot, libroot, case, compname=None): os.rmdir(comppath) symlink_force(os.path.join(bldroot,compname), comppath) -def all_files_under(path): +def all_files_under(path, ignoredirs=[]): """Iterates through all files that are under the given path.""" - for cur_path, dirnames, filenames in os.walk(path): + for cur_path, dirnames, filenames in os.walk(path, topdown=True): + [dirnames.remove(d) for d in list(dirnames) if d in ignoredirs] for filename in filenames: yield os.path.join(cur_path, filename) @@ -113,11 +137,9 @@ def get_compiler_names(case): compobj = Compilers(machobj) compiler = case.get_value("COMPILER") if case.get_value("MPILIB") == 'mpi-serial': - print("HERE Compiler {} mach={}".format(compiler, machine)) ccomp = compobj.get_value("SCC",{"COMPILER":compiler,"MACH":machine}).strip() cxxcomp = compobj.get_value("SCXX",{"COMPILER":compiler}).strip() fcomp = compobj.get_value("SFC",{"COMPILER":compiler}).strip() - print("HERE the compilers are {} {} {}".format(ccomp,cxxcomp, fcomp)) else: ccomp = compobj.get_value("MPICC",{"COMPILER":compiler}).strip() cxxcomp = compobj.get_value("MPICXX",{"COMPILER":compiler}).strip() @@ -128,6 +150,7 @@ def get_compiler_names(case): def _main_func(args): caseroot, libroot, bldroot = parse_input(args) + print("HERE cwd is {} caseroot is {}".format(os.getcwd(), caseroot)) with Case(caseroot) as case: buildlib(bldroot, libroot, case) diff --git a/cime_config/stream_cdeps.py b/cime_config/stream_cdeps.py index c2aaf0afb..733592ea1 100644 --- a/cime_config/stream_cdeps.py +++ b/cime_config/stream_cdeps.py @@ -54,9 +54,11 @@ def __init__(self, infile, schema): if os.path.exists(infile): GenericXML.read(self, infile, schema) - def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file): + def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file, available_neon_data=None): """ Create the stream xml file and append the required stream input data to the input data list file + available_neon_data is an optional list of NEON tower data available for the given case, if provided + this data will be used to populate the NEON streamdata list """ # write header of stream file with open(streams_xml_file, 'w') as stream_file: @@ -103,9 +105,16 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file elif node_name == 'stream_datafiles': # Get the resolved stream data files stream_vars[node_name] = "" + stream_datafiles = "" for child in self.get_children(root=node): - stream_datafiles = child.xml_element.text - stream_datafiles = self._resolve_values(case, stream_datafiles) + if available_neon_data and stream_name.startswith("NEON"): + rundir = case.get_value("RUNDIR") + for neon in available_neon_data: + stream_datafiles += os.path.join(rundir,"inputdata","atm",neon) + "\n" + else: + stream_datafiles = child.xml_element.text + stream_datafiles = self._resolve_values(case, stream_datafiles) + #endif neon if 'first_year' in child.xml_element.attrib and 'last_year' in child.xml_element.attrib: value = child.xml_element.get('first_year') value = self._resolve_values(case, value) @@ -122,7 +131,6 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file stream_vars[node_name] += "\n " + self._add_xml_delimiter(stream_datafiles.split("\n"), "file") else: stream_vars[node_name] = self._add_xml_delimiter(stream_datafiles.split("\n"), "file") - elif ( node_name == 'stream_meshfile' or node_name == 'stream_mapalgo' or node_name == 'stream_tintalgo' @@ -418,5 +426,4 @@ def update_input_data_list(self, data_list_file): stream_datafiles = [] for fnode in filenodes: stream_datafiles.append(self.text(fnode)) - print("HERE {}".format(data_list_file)) self._add_entries_to_inputdata_list(stream_meshfile, stream_datafiles, data_list_file) diff --git a/cime_config/testdefs/testlist_cdeps.xml b/cime_config/testdefs/testlist_cdeps.xml index 72f019c6c..03cbfb0c7 100644 --- a/cime_config/testdefs/testlist_cdeps.xml +++ b/cime_config/testdefs/testlist_cdeps.xml @@ -89,7 +89,7 @@ - + diff --git a/datm/cime_config/buildnml b/datm/cime_config/buildnml index da8a36c1b..24a6ba522 100755 --- a/datm/cime_config/buildnml +++ b/datm/cime_config/buildnml @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Namelist creator for CDEPS data atm model. """ @@ -19,16 +19,63 @@ _LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") sys.path.append(_LIBDIR) sys.path.append(_CDEPS_CONFIG) +from datetime import datetime from standard_script_setup import * from CIME.case import Case from CIME.nmlgen import NamelistGenerator -from CIME.utils import expect, get_model, safe_copy +from CIME.utils import expect, safe_copy, SharedArea from CIME.buildnml import create_namelist_infile, parse_input, copy_inputs_to_rundir from CIME.XML.files import Files +from CIME.XML.inputdata import Inputdata from stream_cdeps import StreamCDEPS logger = logging.getLogger(__name__) +def _get_neon_data_availability(case, neonsite): + """ + Read the NEON inventory file and check availablity of tower data for this case. + Put available data in datavaliddate list and return it + Currently the valid date information is not used + """ + rundir = case.get_value("RUNDIR") + fullpath = os.path.join(rundir,"listing.csv") + if not os.path.exists(fullpath): + inputdata = Inputdata() + protocol, address, user, passwd, _, _, inventory = inputdata.get_next_server(attributes={'CLM_USRDAT_NAME':'NEON'}) + success = case.check_input_data(protocol=protocol, address=address, download=True) + logger.debug("_get_neon_data_availablity: address {} inventory is {} success {}".format(address, inventory, success)) + + server = CIME.Servers.WGET.wget_login(address, user, passwd) + if server: + with SharedArea(): + success = server.getfile(inventory, fullpath) + expect(success, "Could not download NEON data listing file from server") + + expect(os.path.exists(fullpath), "Could not download NEON data listing file from server") + datavaliddate = [] + oldestdate = None + newestdate = None + neonatm = None + with open(fullpath, "r") as fd: + for line in fd.readlines(): + fpath, fname = os.path.split(line) + if fpath.endswith('cdeps/v1/'+neonsite): + neonatm, date = line.strip().split(',') + if neonatm.endswith('.nc'): + neonatm = neonatm.split('/')[-1] + newestdate = datetime.strptime(neonatm,"%Y-%m.nc") + if not oldestdate: + oldestdate = datetime.strptime(neonatm,"%Y-%m.nc") + neonatm = 'cdeps/v1/'+neonsite+'/'+neonatm + datavaliddate.append(neonatm) + expect(newestdate, "No tower data found on server for NEON site {}".format(neonsite)) + logger.info("Found tower data for {} through {}".format(oldestdate, newestdate)) + datavaliddate.sort() + + return datavaliddate + + + # pylint: disable=too-many-arguments,too-many-locals,too-many-branches,too-many-statements #################################################################################### def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path): @@ -69,10 +116,14 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path # Initialize namelist defaults config = {} + available_neon_data = None if 'CLM_USRDAT' in model_grid: config['model_grid'] = 'CLM_USRDAT' - if case.get_value("NEONSITE"): + neonsite = case.get_value("NEONSITE") + if neonsite: config['neon'] = "True" + # download and use the listing.csv file to determine data availablity + available_neon_data = _get_neon_data_availability(case, neonsite) else: config['model_grid'] = model_grid @@ -129,7 +180,7 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "datm","cime_config","stream_definition_datm.xml") streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, available_neon_data=available_neon_data) ############################################################################### def buildnml(case, caseroot, compname): diff --git a/datm/cime_config/stream_definition_datm.xml b/datm/cime_config/stream_definition_datm.xml index cce202ef7..c9d5b3fef 100644 --- a/datm/cime_config/stream_definition_datm.xml +++ b/datm/cime_config/stream_definition_datm.xml @@ -2587,13 +2587,12 @@ $DIN_LOC_ROOT/atm/datm7/ERA5/ERA5.TL639.2019.12.200618.nc - u10 Sa_u - v10 Sa_v - t2m Sa_tbot + u10 Sa_u10m + v10 Sa_v10m + t2m Sa_t2m skt Sa_tskn d2m Sa_tdew msl Sa_pslv - sp Sa_pbot tp Faxa_rain cp Faxa_rainc lsp Faxa_rainl @@ -2618,7 +2617,7 @@ u:v - 1900 + 2019 2019 2019 0 @@ -2626,7 +2625,7 @@ linear - cycle + limit 1.5 diff --git a/datm/datm_datamode_era5_mod.F90 b/datm/datm_datamode_era5_mod.F90 index 71e60a016..183e6c162 100644 --- a/datm/datm_datamode_era5_mod.F90 +++ b/datm/datm_datamode_era5_mod.F90 @@ -25,16 +25,13 @@ module datm_datamode_era5_mod ! export state data real(r8), pointer :: Sa_z(:) => null() - real(r8), pointer :: Sa_u(:) => null() - real(r8), pointer :: Sa_v(:) => null() - real(r8), pointer :: Sa_wspd(:) => null() - real(r8), pointer :: Sa_tbot(:) => null() - real(r8), pointer :: Sa_ptem(:) => null() - real(r8), pointer :: Sa_shum(:) => null() - real(r8), pointer :: Sa_dens(:) => null() - real(r8), pointer :: Sa_pbot(:) => null() - real(r8), pointer :: Faxa_lwdn(:) => null() - real(r8), pointer :: Faxa_lwnet(:) => null() + real(r8), pointer :: Sa_u10m(:) => null() + real(r8), pointer :: Sa_v10m(:) => null() + real(r8), pointer :: Sa_wspd10m(:) => null() + real(r8), pointer :: Sa_t2m(:) => null() + real(r8), pointer :: Sa_tskn(:) => null() + real(r8), pointer :: Sa_q2m(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() real(r8), pointer :: Faxa_rain(:) => null() real(r8), pointer :: Faxa_rainc(:) => null() real(r8), pointer :: Faxa_rainl(:) => null() @@ -44,18 +41,20 @@ module datm_datamode_era5_mod real(r8), pointer :: Faxa_swndf(:) => null() real(r8), pointer :: Faxa_swvdr(:) => null() real(r8), pointer :: Faxa_swvdf(:) => null() - real(r8), pointer :: Faxa_swnet(:) => null() real(r8), pointer :: Faxa_swdn(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_lwnet(:) => null() real(r8), pointer :: Faxa_sen(:) => null() real(r8), pointer :: Faxa_lat(:) => null() real(r8), pointer :: Faxa_taux(:) => null() real(r8), pointer :: Faxa_tauy(:) => null() ! stream data - real(r8), pointer :: strm_tdew(:) => null() + real(r8), pointer :: strm_tdew(:) => null() - real(r8) :: tbotmax ! units detector - real(r8) :: tdewmax ! units detector + real(r8) :: t2max ! units detector + real(r8) :: td2max ! units detector real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg @@ -87,16 +86,13 @@ subroutine datm_datamode_era5_advertise(exportState, fldsexport, & call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) call dshr_fldList_add(fldsExport, 'Sa_z' ) - call dshr_fldList_add(fldsExport, 'Sa_u' ) - call dshr_fldList_add(fldsExport, 'Sa_v' ) - call dshr_fldList_add(fldsExport, 'Sa_wspd' ) - call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_u10m' ) + call dshr_fldList_add(fldsExport, 'Sa_v10m' ) + call dshr_fldList_add(fldsExport, 'Sa_wspd10m' ) + call dshr_fldList_add(fldsExport, 'Sa_t2m' ) call dshr_fldList_add(fldsExport, 'Sa_tskn' ) - call dshr_fldList_add(fldsExport, 'Sa_ptem' ) - call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_q2m' ) call dshr_fldList_add(fldsExport, 'Sa_pslv' ) - call dshr_fldList_add(fldsExport, 'Sa_pbot' ) - call dshr_fldList_add(fldsExport, 'Sa_shum' ) call dshr_fldList_add(fldsExport, 'Faxa_rain' ) call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) @@ -109,7 +105,7 @@ subroutine datm_datamode_era5_advertise(exportState, fldsexport, & call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) - call dshr_fldList_add(fldsExport, 'Faxa_lwnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwnet' ) call dshr_fldList_add(fldsExport, 'Faxa_sen' ) call dshr_fldList_add(fldsExport, 'Faxa_lat' ) call dshr_fldList_add(fldsExport, 'Faxa_taux' ) @@ -144,57 +140,55 @@ subroutine datm_datamode_era5_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! get export state pointers - call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_wspd' , fldptr1=Sa_wspd , allowNullReturn=.true., rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_wspd10m' , fldptr1=Sa_wspd10m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_t2m' , fldptr1=Sa_t2m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_tskn' , fldptr1=Sa_tskn , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_q2m' , fldptr1=Sa_q2m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_dens' , fldptr1=Sa_dens , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_swdn' , fldptr1=Faxa_swdn , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swdn' , fldptr1=Faxa_swdn , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Faxa_lwnet' , fldptr1=Faxa_lwnet , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_sen' , fldptr1=Faxa_sen , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_sen' , fldptr1=Faxa_sen , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_lat' , fldptr1=Faxa_lat , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_lat' , fldptr1=Faxa_lat , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_taux' , fldptr1=Faxa_taux , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_taux' , fldptr1=Faxa_taux , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_tauy' , fldptr1=Faxa_tauy , rc=rc) + call dshr_state_getfldptr(exportState, 'Faxa_tauy' , fldptr1=Faxa_tauy , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end subroutine datm_datamode_era5_init_pointers @@ -217,7 +211,7 @@ subroutine datm_datamode_era5_advance(exportstate, masterproc, logunit, mpicom, integer :: n ! indices integer :: lsize ! size of attr vect real(r8) :: rtmp - real(r8) :: tbot, pbot + real(r8) :: t2, pslv real(r8) :: vp real(r8) :: e, qsat character(len=*), parameter :: subname='(datm_datamode_era5_advance): ' @@ -228,15 +222,17 @@ subroutine datm_datamode_era5_advance(exportstate, masterproc, logunit, mpicom, lsize = size(strm_tdew) if (first_time) then - ! determine tbotmax (see below for use) - rtmp = maxval(Sa_tbot(:)) - call shr_mpi_max(rtmp, tbotmax, mpicom, 'datm_tbot', all=.true.) - if (masterproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax + ! determine t2max (see below for use) + if (associated(Sa_t2m)) then + rtmp = maxval(Sa_t2m(:)) + call shr_mpi_max(rtmp, t2max, mpicom, 'datm_t2m', all=.true.) + if (masterproc) write(logunit,*) trim(subname),' t2max = ',t2max + end if ! determine tdewmax (see below for use) rtmp = maxval(strm_tdew(:)) - call shr_mpi_max(rtmp, tdewmax, mpicom, 'datm_tdew', all=.true.) - if (masterproc) write(logunit,*) trim(subname),' tdewmax = ',tdewmax + call shr_mpi_max(rtmp, td2max, mpicom, 'datm_td2m', all=.true.) + if (masterproc) write(logunit,*) trim(subname),' td2max = ',td2max ! reset first_time first_time = .false. @@ -244,72 +240,74 @@ subroutine datm_datamode_era5_advance(exportstate, masterproc, logunit, mpicom, do n = 1, lsize !--- bottom layer height --- - Sa_z(n) = 10.0_r8 + if (associated(Sa_z)) then + Sa_z(n) = 10.0_r8 + end if !--- calculate wind speed --- - if (associated(Sa_wspd)) then - Sa_wspd(n) = sqrt(Sa_u(n)*Sa_u(n)+Sa_v(n)*Sa_v(n)) + if (associated(Sa_wspd10m)) then + Sa_wspd10m(n) = sqrt(Sa_u10m(n)*Sa_u10m(n)+Sa_v10m(n)*Sa_v10m(n)) end if - !--- temperature --- - if (tbotmax < 50.0_r8) Sa_tbot(n) = Sa_tbot(n) + tkFrz - ! Limit very cold forcing to 180K - Sa_tbot(n) = max(180._r8, Sa_tbot(n)) - Sa_ptem(n) = Sa_tbot(n) - - !--- specific humidity --- - tbot = Sa_tbot(n) - pbot = Sa_pbot(n) - if (tdewmax < 50.0_r8) strm_tdew(n) = strm_tdew(n) + tkFrz - e = datm_eSat(strm_tdew(n),tbot) - qsat = (0.622_r8 * e)/(pbot - 0.378_r8 * e) - Sa_shum(n) = qsat - - !--- density --- - vp = (Sa_shum(n)*pbot) / (0.622_r8 + 0.378_r8 * Sa_shum(n)) - Sa_dens(n) = (pbot - 0.378_r8 * vp) / (tbot*rdair) - - !--- shortwave radiation (Faxa_* basically holds albedo) --- - Faxa_swvdr(n) = Faxa_swdn(n)*Faxa_swvdr(n) - Faxa_swndr(n) = Faxa_swdn(n)*Faxa_swndr(n) - Faxa_swvdf(n) = Faxa_swdn(n)*Faxa_swvdf(n) - Faxa_swndf(n) = Faxa_swdn(n)*Faxa_swndf(n) - - !--- TODO: need to understand relationship between shortwave bands and net shortwave rad. - !--- currently it is provided directly from ERA5 and the total of the bands are not - !--- consistent with the swnet - !--- swnet: a diagnostic quantity --- - !Faxa_swnet(n) = Faxa_swndr(n) + Faxa_swvdr(n) + Faxa_swndf(n) + Faxa_swvdf(n) + !--- specific humidity at 2m --- + if (associated(Sa_t2m) .and. associated(Sa_pslv) .and. associated(Sa_q2m)) then + t2 = Sa_t2m(n) + pslv = Sa_pslv(n) + if (td2max < 50.0_r8) strm_tdew(n) = strm_tdew(n) + tkFrz + e = datm_eSat(strm_tdew(n), t2) + qsat = (0.622_r8 * e)/(pslv - 0.378_r8 * e) + Sa_q2m(n) = qsat + end if end do + !---------------------------------------------------------- + ! shortwave bands + !---------------------------------------------------------- + + !--- shortwave radiation (Faxa_* basically holds albedo) --- + !--- see comments for Faxa_swnet + if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swdn(:)*Faxa_swvdr(:) + if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swdn(:)*Faxa_swndr(:) + if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swdn(:)*Faxa_swvdf(:) + if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swdn(:)*Faxa_swndf(:) + + !--- TODO: need to understand relationship between shortwave bands and + !--- net shortwave rad. currently it is provided directly from ERA5 + !--- and the total of the bands are not consistent with the swnet + !--- swnet: a diagnostic quantity --- + !if (associated(Faxa_swnet)) then + ! if (associated(Faxa_swndr) .and. associated(Faxa_swvdr) .and. & + ! associated(Faxa_swndf) .and. associated(Faxa_swvdf)) then + ! Faxa_swnet(:) = Faxa_swndr(:) + Faxa_swvdr(:) + Faxa_swndf(:) + Faxa_swvdf(:) + ! end if + !end if + !---------------------------------------------------------- ! unit conversions (temporal resolution is hourly) !---------------------------------------------------------- ! convert J/m^2 to W/m^2 - Faxa_lwdn(:) = Faxa_lwdn(:)/3600.0_r8 - if (associated(Faxa_lwnet)) then - Faxa_lwnet(:) = Faxa_lwnet(:)/3600.0_r8 - end if - Faxa_swdn(:) = Faxa_swdn(:)/3600.0_r8 - Faxa_swvdr(:) = Faxa_swvdr(:)/3600.0_r8 - Faxa_swndr(:) = Faxa_swndr(:)/3600.0_r8 - Faxa_swvdf(:) = Faxa_swvdf(:)/3600.0_r8 - Faxa_swndf(:) = Faxa_swndf(:)/3600.0_r8 - Faxa_swnet(:) = Faxa_swnet(:)/3600.0_r8 - Faxa_sen(:) = Faxa_sen(:)/3600.0_r8 - Faxa_lat(:) = Faxa_lat(:)/3600.0_r8 + if (associated(Faxa_lwdn)) Faxa_lwdn(:) = Faxa_lwdn(:)/3600.0_r8 + if (associated(Faxa_lwnet)) Faxa_lwnet(:) = Faxa_lwnet(:)/3600.0_r8 + if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swvdr(:)/3600.0_r8 + if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swndr(:)/3600.0_r8 + if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swvdf(:)/3600.0_r8 + if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swndf(:)/3600.0_r8 + if (associated(Faxa_swdn)) Faxa_swdn(:) = Faxa_swdn(:)/3600.0_r8 + if (associated(Faxa_swnet)) Faxa_swnet(:) = Faxa_swnet(:)/3600.0_r8 + if (associated(Faxa_sen)) Faxa_sen(:) = Faxa_sen(:)/3600.0_r8 + if (associated(Faxa_lat)) Faxa_lat(:) = Faxa_lat(:)/3600.0_r8 ! convert m to kg/m^2/s - Faxa_rain(:) = Faxa_rain(:)/3600.0_r8*rhofw - Faxa_rainc(:) = Faxa_rainc(:)/3600.0_r8*rhofw - Faxa_rainl(:) = Faxa_rainl(:)/3600.0_r8*rhofw - Faxa_snowc(:) = Faxa_snowc(:)/3600.0_r8*rhofw - Faxa_snowl(:) = Faxa_snowl(:)/3600.0_r8*rhofw + if (associated(Faxa_rain)) Faxa_rain(:) = Faxa_rain(:)/3600.0_r8*rhofw + if (associated(Faxa_rainc)) Faxa_rainc(:) = Faxa_rainc(:)/3600.0_r8*rhofw + if (associated(Faxa_rainl)) Faxa_rainl(:) = Faxa_rainl(:)/3600.0_r8*rhofw + if (associated(Faxa_snowc)) Faxa_snowc(:) = Faxa_snowc(:)/3600.0_r8*rhofw + if (associated(Faxa_snowl)) Faxa_snowl(:) = Faxa_snowl(:)/3600.0_r8*rhofw ! convert N/m^2 s to N/m^2 - Faxa_taux(:) = Faxa_taux(:)/3600.0_r8 - Faxa_tauy(:) = Faxa_tauy(:)/3600.0_r8 + if (associated(Faxa_taux)) Faxa_taux(:) = Faxa_taux(:)/3600.0_r8 + if (associated(Faxa_tauy)) Faxa_tauy(:) = Faxa_tauy(:)/3600.0_r8 end subroutine datm_datamode_era5_advance diff --git a/dice/cime_config/buildnml b/dice/cime_config/buildnml index 0266f68bf..00e698707 100755 --- a/dice/cime_config/buildnml +++ b/dice/cime_config/buildnml @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Namelist creator for CDEPS data ice model. """ diff --git a/dlnd/cime_config/buildnml b/dlnd/cime_config/buildnml index 3203f48c3..1faca3123 100755 --- a/dlnd/cime_config/buildnml +++ b/dlnd/cime_config/buildnml @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Namelist creator for CIME's data land model. """ diff --git a/docn/cime_config/buildnml b/docn/cime_config/buildnml index 1a748fa89..cb45d0f9b 100755 --- a/docn/cime_config/buildnml +++ b/docn/cime_config/buildnml @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Namelist creator for CDEPS data ocn model. """ diff --git a/drof/cime_config/buildnml b/drof/cime_config/buildnml index 4439256d3..1d0a7cc52 100755 --- a/drof/cime_config/buildnml +++ b/drof/cime_config/buildnml @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Namelist creator for CDEPS data river model. """ diff --git a/dshr/dshr_mod.F90 b/dshr/dshr_mod.F90 index d950dc331..5a6e71516 100644 --- a/dshr/dshr_mod.F90 +++ b/dshr/dshr_mod.F90 @@ -31,7 +31,7 @@ module dshr_mod use ESMF , only : ESMF_TERMORDER_SRCSEQ, ESMF_FieldRegridStore, ESMF_SparseMatrixWrite use ESMF , only : ESMF_Region_Flag, ESMF_REGION_TOTAL, ESMF_MAXSTR, ESMF_RC_NOT_VALID use ESMF , only : ESMF_UtilStringUpperCase - use shr_kind_mod , only : r8=>shr_kind_r8, cs=>shr_kind_cs, cl=>shr_kind_cl, cxx=>shr_kind_cxx, i8=>shr_kind_i8 + use shr_kind_mod , only : r8=>shr_kind_r8, cs=>shr_kind_cs, cl=>shr_kind_cl, cx=>shr_kind_cx, cxx=>shr_kind_cxx, i8=>shr_kind_i8 use shr_sys_mod , only : shr_sys_abort use shr_mpi_mod , only : shr_mpi_bcast use shr_cal_mod , only : shr_cal_noleap, shr_cal_gregorian, shr_cal_calendarname @@ -42,6 +42,7 @@ module dshr_mod use shr_pio_mod , only : shr_pio_getiosys, shr_pio_getiotype, shr_pio_getioformat #endif use dshr_strdata_mod , only : shr_strdata_type, SHR_STRDATA_GET_STREAM_COUNT + use shr_string_mod , only : shr_string_toLower use dshr_methods_mod , only : chkerr use pio @@ -124,10 +125,10 @@ subroutine dshr_init(gcomp, compname, sdat, mpicom, my_task, inst_index, inst_su ! local variables type(ESMF_VM) :: vm logical :: isPresent, isSet - character(len=CL) :: cvalue - character(len=CL) :: logmsg - character(len=CL) :: diro - character(len=CL) :: logfile + character(len=CX) :: cvalue + character(len=CX) :: logmsg + character(len=CX) :: diro + character(len=CX) :: logfile character(len=*),parameter :: subname='(dshr_advertise)' ! ---------------------------------------------- @@ -176,12 +177,24 @@ subroutine dshr_init(gcomp, compname, sdat, mpicom, my_task, inst_index, inst_su endif ! set output logging - if (my_task == master_task) then - call NUOPC_CompAttributeGet(gcomp, name="diro", value=diro, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - call NUOPC_CompAttributeGet(gcomp, name="logfile", value=logfile, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - open(newunit=logunit,file=trim(diro)//"/"//trim(logfile)) + call NUOPC_CompAttributeGet(gcomp, name="diro", value=diro, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (.not. (isPresent .and. isSet)) then + diro = "." + endif + + call NUOPC_CompAttributeGet(gcomp, name="logfile", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue,*) logfile + else + logfile = "d"//shr_string_toLower(compname)//".log" + endif + + if (my_task == master_task) then + call ESMF_LogWrite(trim(subname)//' : output logging is written to '//trim(diro)//"/"//trim(logfile), ESMF_LOGMSG_INFO) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + open(newunit=logunit, file=trim(diro)//"/"//trim(logfile)) else logUnit = 6 endif diff --git a/dwav/cime_config/buildnml b/dwav/cime_config/buildnml index b1f377af3..e4505a77e 100755 --- a/dwav/cime_config/buildnml +++ b/dwav/cime_config/buildnml @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 """Namelist creator for CIME's data wave model. """ diff --git a/streams/dshr_strdata_mod.F90 b/streams/dshr_strdata_mod.F90 index ae8578524..0f7dfa063 100644 --- a/streams/dshr_strdata_mod.F90 +++ b/streams/dshr_strdata_mod.F90 @@ -7,7 +7,7 @@ module dshr_strdata_mod use ESMF , only : ESMF_Clock, ESMF_VM, ESMF_VMGet, ESMF_VMGetCurrent use ESMF , only : ESMF_DistGrid, ESMF_SUCCESS, ESMF_MeshGet, ESMF_DistGridGet use ESMF , only : ESMF_VMBroadCast, ESMF_MeshIsCreated, ESMF_MeshCreate - use ESMF , only : ESMF_Calendar, ESMF_CALKIND_NOLEAP, ESMF_CALKIND_GREGORIAN + use ESMF , only : ESMF_CALKIND_NOLEAP, ESMF_CALKIND_GREGORIAN use ESMF , only : ESMF_CalKind_Flag, ESMF_Time, ESMF_TimeInterval use ESMF , only : ESMF_TimeIntervalGet, ESMF_TYPEKIND_R8, ESMF_FieldCreate use ESMF , only : ESMF_FILEFORMAT_ESMFMESH, ESMF_FieldCreate @@ -233,7 +233,7 @@ subroutine shr_strdata_init_from_config(sdat, streamfilename, model_mesh, clock, if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Now finish initializing sdat - call shr_strdata_init(sdat, clock, rc) + call shr_strdata_init(sdat, clock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end subroutine shr_strdata_init_from_config @@ -244,7 +244,7 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & stream_meshfile, stream_lev_dimname, stream_mapalgo, & stream_filenames, stream_fldlistFile, stream_fldListModel, & stream_yearFirst, stream_yearLast, stream_yearAlign, & - stream_offset, stream_taxmode, stream_dtlimit, stream_tintalgo, rc) + stream_offset, stream_taxmode, stream_dtlimit, stream_tintalgo, stream_name, rc) ! input/output variables type(shr_strdata_type) , intent(inout) :: sdat ! stream data type @@ -266,6 +266,7 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & character(*) , intent(in) :: stream_taxMode ! time axis mode real(r8) , intent(in) :: stream_dtlimit ! ratio of max/min stream delta times character(*) , intent(in) :: stream_tintalgo ! time interpolation algorithm + character(*), optional , intent(in) :: stream_name ! name of stream integer , intent(out) :: rc ! error code ! ---------------------------------------------- @@ -300,7 +301,7 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & logunit, trim(compname)) ! Now finish initializing sdat - call shr_strdata_init(sdat, model_clock, rc) + call shr_strdata_init(sdat, model_clock, stream_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end subroutine shr_strdata_init_from_inline @@ -369,11 +370,12 @@ subroutine shr_strdata_init_model_domain( sdat, rc) end subroutine shr_strdata_init_model_domain !=============================================================================== - subroutine shr_strdata_init(sdat, model_clock, rc) + subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) ! input/output variables type(shr_strdata_type) , intent(inout), target :: sdat type(ESMF_Clock) , intent(in) :: model_clock + character(*), optional , intent(in) :: stream_name integer , intent(out) :: rc ! local variables @@ -608,7 +610,11 @@ subroutine shr_strdata_init(sdat, model_clock, rc) ! print sdat output if (masterproc) then - call shr_strdata_print(sdat,'sdat data ') + if (present(stream_name)) then + call shr_strdata_print(sdat, trim(stream_name)) + else + call shr_strdata_print(sdat, 'stream_data') + end if write(sdat%logunit,*) ' successfully initialized sdat' endif end subroutine shr_strdata_init @@ -1149,19 +1155,16 @@ subroutine shr_strdata_print(sdat, name) write(sdat%logunit,F01) "pio_iotype = ",sdat%io_type write(sdat%logunit,F01) "nstreams = ",shr_strdata_get_stream_count(sdat) + write(sdat%logunit,F01) "nvectors = ",sdat%nvectors do ns = 1, shr_strdata_get_stream_count(sdat) write(sdat%logunit,F04) " taxMode (",ns,") = ",trim(sdat%stream(ns)%taxmode) write(sdat%logunit,F07) " dtlimit (",ns,") = ",sdat%stream(ns)%dtlimit write(sdat%logunit,F04) " mapalgo (",ns,") = ",trim(sdat%stream(ns)%mapalgo) write(sdat%logunit,F04) " tintalgo(",ns,") = ",trim(sdat%stream(ns)%tinterpalgo) write(sdat%logunit,F04) " readmode(",ns,") = ",trim(sdat%stream(ns)%readmode) + write(sdat%logunit,F04) " vectors (",ns,") = ",trim(sdat%stream(ns)%stream_vectors) write(sdat%logunit,F01) " " end do - - write(sdat%logunit,F01) "nvectors = ",sdat%nvectors - do n=1, sdat%nvectors - write(sdat%logunit,F04) " vectors (",n,") = ",trim(sdat%stream(n)%stream_vectors) - end do write(sdat%logunit,F90) end subroutine shr_strdata_print diff --git a/streams/dshr_stream_mod.F90 b/streams/dshr_stream_mod.F90 index fbad936b7..c758136a3 100644 --- a/streams/dshr_stream_mod.F90 +++ b/streams/dshr_stream_mod.F90 @@ -1149,7 +1149,7 @@ subroutine shr_stream_readTCoord(strm, k, isroot_task, rc) integer :: old_handle ! previous setting of pio error handling real(R8) :: nsec ! elapsed secs on calendar date real(R8),allocatable :: tvar(:) - character(*),parameter :: subname = ' (shr_stream_readTCoord) ' + character(*),parameter :: subname = '(shr_stream_readTCoord) ' !------------------------------------------------------------------------------- lrc = 0 @@ -1159,7 +1159,7 @@ subroutine shr_stream_readTCoord(strm, k, isroot_task, rc) ! open file if needed if (.not. pio_file_is_open(strm%file(k)%fileid)) then - if (isroot_task) then + if (debug > 0 .and. isroot_task) then write(strm%logunit, '(a)') trim(subname)//' opening stream filename = '//trim(filename) end if rcode = pio_openfile(strm%pio_subsystem, strm%file(k)%fileid, strm%pio_iotype, filename, pio_nowrite) @@ -1220,7 +1220,7 @@ subroutine shr_stream_readTCoord(strm, k, isroot_task, rc) deallocate(tvar) ! close file - if (isroot_task) then + if (debug > 0 .and. isroot_task) then write(strm%logunit, '(a)') trim(subname)//' closing stream filename = '//trim(filename) end if call pio_closefile(strm%file(k)%fileid) @@ -1424,7 +1424,7 @@ subroutine shr_stream_getCalendar(strm, k, calendar) character(CL) :: fileName,lcal integer :: old_handle integer :: rCode - character(*),parameter :: subName = ' (shr_stream_getCalendar) ' + character(*),parameter :: subName = '(shr_stream_getCalendar) ' !------------------------------------------------------------------------------- lcal = ' ' From bfbba9bb0e3a70e04cf606b10e3573b24cb81fb8 Mon Sep 17 00:00:00 2001 From: BinLi-NOAA Date: Mon, 18 Oct 2021 06:02:20 -0400 Subject: [PATCH 02/28] Update develop branch of cdeps to the most recent version of ESCOMP/CDEPS (#37) --- cime_config/stream_cdeps.py | 139 ++++++++++++++++---- cime_config/streams.xsd | 58 ++++---- datm/atm_comp_nuopc.F90 | 17 +-- datm/cime_config/buildnml | 46 +++---- datm/cime_config/stream_definition_datm.xml | 4 +- datm/cime_config/user_nl_datm_streams | 23 ++++ dice/cime_config/buildnml | 46 ++++--- dice/cime_config/user_nl_dice_streams | 23 ++++ dice/ice_comp_nuopc.F90 | 12 +- dlnd/cime_config/buildnml | 50 +++---- dlnd/cime_config/user_nl_dlnd_streams | 23 ++++ dlnd/lnd_comp_nuopc.F90 | 12 +- docn/cime_config/buildnml | 47 +++---- docn/cime_config/user_nl_docn_streams | 23 ++++ docn/ocn_comp_nuopc.F90 | 15 +-- drof/cime_config/buildnml | 47 +++---- drof/cime_config/user_nl_drof_streams | 23 ++++ drof/rof_comp_nuopc.F90 | 14 +- dshr/dshr_mod.F90 | 100 +++++++++++++- dwav/cime_config/buildnml | 48 +++---- dwav/cime_config/user_nl_dwav_streams | 23 ++++ dwav/wav_comp_nuopc.F90 | 11 +- streams/dshr_strdata_mod.F90 | 50 ++++++- streams/dshr_stream_mod.F90 | 116 +++++++++++----- 24 files changed, 678 insertions(+), 292 deletions(-) create mode 100644 datm/cime_config/user_nl_datm_streams create mode 100644 dice/cime_config/user_nl_dice_streams create mode 100644 dlnd/cime_config/user_nl_dlnd_streams create mode 100644 docn/cime_config/user_nl_docn_streams create mode 100644 drof/cime_config/user_nl_drof_streams create mode 100644 dwav/cime_config/user_nl_dwav_streams diff --git a/cime_config/stream_cdeps.py b/cime_config/stream_cdeps.py index 733592ea1..ae8364dad 100644 --- a/cime_config/stream_cdeps.py +++ b/cime_config/stream_cdeps.py @@ -19,30 +19,37 @@ _ymd_re = re.compile(r"%(?P[1-9][0-9]*)?y(?Pm(?Pd)?)?") -_stream_nuopc_file_template = """ +_stream_file_template = """ {stream_taxmode} - {stream_tintalgo} - {stream_readmode} + {stream_tintalgo} + {stream_readmode} {stream_mapalgo} {stream_dtlimit} - {stream_year_first} - {stream_year_last} - {stream_year_align} - {stream_vectors} - {stream_meshfile} - {stream_lev_dimname} - + {stream_year_first} + {stream_year_last} + {stream_year_align} + {stream_vectors} + {stream_meshfile} + {stream_lev_dimname} + {stream_datafiles} - - + + {stream_datavars} - - {stream_offset} - + + {stream_offset} + """ +valid_values = {} +valid_values["mapalgo"] = ["bilinear", "nn", "redist", "mapconsd", "mapconf"] +valid_values["tintalgo"] = ["lower", "upper", "nearest", "linear", "coszen"] +valid_values["taxmode"] = ["cycle", "extend", "limit"] + +xml_scalar_names = ["stream_meshfile", "stream_mapalgo", "stream_tintalgo", "stream_taxmode", "stream_dtlimit"] + class StreamCDEPS(GenericXML): def __init__(self, infile, schema): @@ -54,16 +61,77 @@ def __init__(self, infile, schema): if os.path.exists(infile): GenericXML.read(self, infile, schema) - def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file, available_neon_data=None): + def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file, user_mods_file, + available_neon_data=None): """ Create the stream xml file and append the required stream input data to the input data list file available_neon_data is an optional list of NEON tower data available for the given case, if provided this data will be used to populate the NEON streamdata list """ + + # determine if there are user mods + lines_input = [] + expect (os.path.isfile(user_mods_file), + "No file {} found in case directory".format(user_mods_file)) + with open(user_mods_file, "r", encoding='utf-8') as stream_mods_file: + lines_input = stream_mods_file.readlines() + stream_mod_dict = {} + n = len(lines_input) + + index = 0 + lines_input_new = [] + while index < len(lines_input): + line = lines_input[index].strip() + if line.startswith('!') or (not line): + index = index + 1 + continue + while line[-1] == '\\': + index += 1 + if index < len(lines_input): + line = line[:-1].strip() + ' ' + lines_input[index].strip() + else: + line = line.replace('\\', '').strip() + break + # endif + # end while + index += 1 + lines_input_new.append(line) + #end while + + for line in lines_input_new: + # read in a single line in user_nl_xxx_streams and parse it if it is not a comment + stream_mods = [x.strip() for x in line.strip().split(":") if x] + expect(len(stream_mods) == 2, + "input stream mod can only be of the form streamname:var=value(s)") + stream,varmod = stream_mods + expect (stream in stream_names, + "{} contains a streamname \'{}\' that is not part of valid streamnames {}". + format(user_mods_file,stream,stream_names)) + if stream not in stream_mod_dict: + stream_mod_dict[stream] = {} + # var=value and check the validity + varmod_args = [x.strip() for x in varmod.split("=") if x] + expect(len(varmod_args) == 2, + "input stream mod can only be of the form streamname:var=value(s)") + # allow multiple entries for varmod_args, most recent wins + varname,varval = varmod_args + if varname in stream_mod_dict[stream]: + logger.warning("varname {} is already in stream mod dictionary".format(varname)) + + if varname == "datavars" or varname == "datafiles": + if varname == "datavars": + varvals = ["{}".format(x.strip()) for x in varval.split(",") if x] + if varname == "datafiles": + varvals = ["{}".format(x.strip()) for x in varval.split(",") if x] + varval = " " + "\n ".join(varvals) + varval = varval.strip() + stream_mod_dict[stream][varname] = varval + # write header of stream file - with open(streams_xml_file, 'w') as stream_file: + with open(streams_xml_file, 'w', encoding='utf-8') as stream_file: stream_file.write('\n') stream_file.write('\n') + # write contents of stream file for stream_name in stream_names: if stream_name.startswith("NEON."): @@ -131,11 +199,8 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file stream_vars[node_name] += "\n " + self._add_xml_delimiter(stream_datafiles.split("\n"), "file") else: stream_vars[node_name] = self._add_xml_delimiter(stream_datafiles.split("\n"), "file") - elif ( node_name == 'stream_meshfile' - or node_name == 'stream_mapalgo' - or node_name == 'stream_tintalgo' - or node_name == 'stream_taxmode' - or node_name == 'stream_dtlimit'): + #endif + elif (node_name in xml_scalar_names): attributes['model_grid'] = case.get_value("GRID") attributes['compset'] = case.get_value("COMPSET") value = self._get_value_match(node, node_name[7:], attributes=attributes) @@ -148,10 +213,26 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file # Get the other dependencies stream_dict = self._add_value_to_dict(stream_vars, case, node) + # substitute user_mods in generated stream file (i.e. stream_vars) + mod_dict = {} + if stream_vars['streamname'] in stream_mod_dict: + mod_dict = stream_mod_dict[stream_vars['streamname']] + for var_key in mod_dict: + expect( 'stream_' + var_key in stream_vars, + "stream mod {} is not a valid name in {}".format(var_key,user_mods_file)) + if var_key in valid_values: + expect(mod_dict[var_key] in valid_values[var_key], + "{} can only have values of {} for stream {} in file {}". + format(var_key, valid_values[var_key], stream_name, user_mods_file)) + stream_vars['stream_' + var_key] = mod_dict[var_key] + if var_key == 'datafiles': + stream_datafiles = mod_dict[var_key] + stream_datafiles = stream_datafiles.replace('','').replace('','') + # append to stream xml file - stream_file_text = _stream_nuopc_file_template.format(**stream_vars) - with open(streams_xml_file, 'a') as stream_file: - stream_file.write(stream_file_text) + stream_file_text = _stream_file_template.format(**stream_vars) + with open(streams_xml_file, 'a', encoding='utf-8') as stream_file: + stream_file.write(case.get_resolved_value(stream_file_text)) # append to input_data_list if stream_vars['stream_meshfile']: @@ -159,7 +240,7 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file self._add_entries_to_inputdata_list(stream_meshfile, stream_datafiles.split("\n"), data_list_file) # write close of stream xml file - with open(streams_xml_file, 'a') as stream_file: + with open(streams_xml_file, 'a', encoding='utf-8') as stream_file: stream_file.write("\n") def _get_stream_first_and_last_dates(self, stream, case): @@ -181,7 +262,7 @@ def _add_entries_to_inputdata_list(self, stream_meshfile, stream_datafiles, data and writes out the new file """ lines_hash = self._get_input_file_hash(data_list_file) - with open(data_list_file, 'a') as input_data_list: + with open(data_list_file, 'a', encoding='utf-8') as input_data_list: # write out the mesh file separately string = "mesh = {}\n".format(stream_meshfile) hashValue = hashlib.md5(string.rstrip().encode('utf-8')).hexdigest() @@ -191,7 +272,7 @@ def _add_entries_to_inputdata_list(self, stream_meshfile, stream_datafiles, data for i, filename in enumerate(stream_datafiles): if filename.strip() == '': continue - string = "file{:d} = {}\n".format(i+1, filename) + string = "file{:d} = {}\n".format(i+1, filename.strip()) hashValue = hashlib.md5(string.rstrip().encode('utf-8')).hexdigest() if hashValue not in lines_hash: input_data_list.write(string) @@ -202,7 +283,7 @@ def _get_input_file_hash(self, data_list_file): """ lines_hash = set() if os.path.isfile(data_list_file): - with open(data_list_file, "r") as input_data_list: + with open(data_list_file, "r", encoding='utf-8') as input_data_list: for line in input_data_list: hashValue = hashlib.md5(line.rstrip().encode('utf-8')).hexdigest() logger.debug( "Found line {} with hash {}".format(line,hashValue)) diff --git a/cime_config/streams.xsd b/cime_config/streams.xsd index e1dd25a0e..d9415c721 100644 --- a/cime_config/streams.xsd +++ b/cime_config/streams.xsd @@ -12,25 +12,25 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + - + @@ -38,7 +38,7 @@ - + @@ -49,20 +49,20 @@ - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index b4491ff2f..ffb640454 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -34,7 +34,7 @@ module cdeps_datm_comp use dshr_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_setOrbs use dshr_mod , only : dshr_model_initphase, dshr_init use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_log_clock_advance - use dshr_mod , only : dshr_restart_read, dshr_restart_write, dshr_mesh_init + use dshr_mod , only : dshr_mesh_init, dshr_check_restart_alarm use dshr_mod , only : dshr_orbital_init, dshr_orbital_update use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add, dshr_fldlist_realize @@ -448,7 +448,7 @@ subroutine ModelAdvance(gcomp, rc) type(ESMF_Time) :: nextTime type(ESMF_TimeInterval) :: timeStep real(r8) :: nextsw_cday - logical :: restart_write ! restart alarm is ringing + logical :: restart_write ! restart alarm is ringing integer :: next_ymd ! model date integer :: next_tod ! model sec into model date integer :: yr, mon, day ! year, month, day @@ -485,18 +485,9 @@ subroutine ModelAdvance(gcomp, rc) orbEccen, orbObliqr, orbLambm0, orbMvelpp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - ! determine if will write restart - call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) + restart_write = dshr_check_restart_alarm(clock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_AlarmRingerOff( alarm, rc=rc ) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - restart_write = .true. - else - restart_write = .false. - endif - + ! Run datm call ESMF_TraceRegionEnter('datm_run') call datm_comp_run(importstate, exportstate, next_ymd, next_tod, mon, & diff --git a/datm/cime_config/buildnml b/datm/cime_config/buildnml index 24a6ba522..cbbe964b3 100755 --- a/datm/cime_config/buildnml +++ b/datm/cime_config/buildnml @@ -60,12 +60,12 @@ def _get_neon_data_availability(case, neonsite): for line in fd.readlines(): fpath, fname = os.path.split(line) if fpath.endswith('cdeps/v1/'+neonsite): - neonatm, date = line.strip().split(',') + neonatm, date, _ = line.strip().split(',') if neonatm.endswith('.nc'): neonatm = neonatm.split('/')[-1] - newestdate = datetime.strptime(neonatm,"%Y-%m.nc") + newestdate = datetime.strptime(neonatm[-10:],"%Y-%m.nc") if not oldestdate: - oldestdate = datetime.strptime(neonatm,"%Y-%m.nc") + oldestdate = datetime.strptime(neonatm[-10:],"%Y-%m.nc") neonatm = 'cdeps/v1/'+neonsite+'/'+neonatm datavaliddate.append(neonatm) expect(newestdate, "No tower data found on server for NEON site {}".format(neonsite)) @@ -171,27 +171,19 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path # Generate datm.streams.xml outfile = os.path.join(confdir, "datm.streams"+inst_string+".xml" ) - user_stream_file = os.path.join(case.get_value("CASEROOT"),os.path.basename(outfile)) - if os.path.isfile(user_stream_file): - schema_file = os.path.join(_CDEPS_CONFIG,"streams.xsd") - streams = StreamCDEPS(user_stream_file, schema_file) - streams.update_input_data_list(os.path.join(caseroot,"Buildconf","datm.input_data_list")) - else: - schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") - stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "datm","cime_config","stream_definition_datm.xml") - streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path, available_neon_data=available_neon_data) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "datm","cime_config","stream_definition_datm.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_datm_streams'+inst_string), + available_neon_data=available_neon_data) ############################################################################### def buildnml(case, caseroot, compname): ############################################################################### - - # Build the component namelist and required stream xml files - if compname != "datm": - raise AttributeError - rundir = case.get_value("RUNDIR") - ninst = case.get_value("NINST_ATM") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) if ninst is None: ninst = case.get_value("NINST") @@ -210,9 +202,9 @@ def buildnml(case, caseroot, compname): # NOTE: User definition *replaces* existing definition. files = Files(comp_interface="nuopc") - definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":"datm"})] + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] - user_definition = os.path.join(user_xml_dir, "namelist_definition_datm.xml") + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") if os.path.isfile(user_definition): definition_file = [user_definition] for file_ in definition_file: @@ -224,7 +216,7 @@ def buildnml(case, caseroot, compname): #---------------------------------------------------- # Clear out old data. #---------------------------------------------------- - data_list_path = os.path.join(caseroot, "Buildconf", "datm.input_data_list") + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") if os.path.exists(data_list_path): os.remove(data_list_path) @@ -263,6 +255,16 @@ def buildnml(case, caseroot, compname): # copy namelist files and stream text files, to rundir copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_datm* files needed in this case + This function is called by CIME to stage the user_nl_datm* files in the case + directory. + """ + user_nl_list = ["user_nl_datm", "user_nl_datm_streams"] + return user_nl_list + ############################################################################### def _main_func(): caseroot = parse_input(sys.argv) diff --git a/datm/cime_config/stream_definition_datm.xml b/datm/cime_config/stream_definition_datm.xml index c9d5b3fef..22237102a 100644 --- a/datm/cime_config/stream_definition_datm.xml +++ b/datm/cime_config/stream_definition_datm.xml @@ -3524,8 +3524,8 @@ bilinear null - 2015 - 2015 + 2014 + 2014 2101 0 diff --git a/datm/cime_config/user_nl_datm_streams b/datm/cime_config/user_nl_datm_streams new file mode 100644 index 000000000..6472afeb8 --- /dev/null +++ b/datm/cime_config/user_nl_datm_streams @@ -0,0 +1,23 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +!------------------------------------------------------------------------ diff --git a/dice/cime_config/buildnml b/dice/cime_config/buildnml index 00e698707..b6ae7b56b 100755 --- a/dice/cime_config/buildnml +++ b/dice/cime_config/buildnml @@ -44,6 +44,7 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path # Write out dice_in and dice.streams.xml #---------------------------------------------------- + caseroot = case.get_value("CASEROOT") dice_mode = case.get_value("DICE_MODE") ice_grid = case.get_value("ICE_GRID") ice_nx = case.get_value("ICE_NX") @@ -85,30 +86,25 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path namelist_file = os.path.join(confdir, "dice_in") nmlgen.write_output_file(namelist_file, data_list_path, groups=['dice_nml']) + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + # Generate dice.streams.xml outfile = os.path.join(confdir, "dice.streams"+inst_string+".xml" ) - user_stream_file = os.path.join(case.get_value("CASEROOT"),os.path.basename(outfile)) - if os.path.isfile(user_stream_file): - schema_file = os.path.join(_CDEPS_CONFIG,"streams.xsd") - streams = StreamCDEPS(user_stream_file, schema_file) - streams.update_input_data_list(os.path.join(caseroot,"Buildconf","dice.input_data_list")) - else: - streamlist = nmlgen.get_streams() - if type(streamlist) == type(str()): - streamlist = [] - schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") - stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dice","cime_config","stream_definition_dice.xml") - streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dice","cime_config","stream_definition_dice.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_dice_streams'+inst_string)) ############################################################################### def buildnml(case, caseroot, compname): ############################################################################### - if compname != "dice": - raise AttributeError - rundir = case.get_value("RUNDIR") - ninst = case.get_value("NINST_ICE") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) if ninst is None: ninst = case.get_value("NINST") @@ -127,9 +123,9 @@ def buildnml(case, caseroot, compname): # NOTE: User definition *replaces* existing definition. files = Files(comp_interface="nuopc") - definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":"dice"})] + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] - user_definition = os.path.join(user_xml_dir, "namelist_definition_dice.xml") + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") if os.path.isfile(user_definition): definition_file = [user_definition] for file_ in definition_file: @@ -141,7 +137,7 @@ def buildnml(case, caseroot, compname): #---------------------------------------------------- # Clear out old data. #---------------------------------------------------- - data_list_path = os.path.join(case.get_case_root(), "Buildconf", "dice.input_data_list") + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") if os.path.exists(data_list_path): os.remove(data_list_path) @@ -180,6 +176,16 @@ def buildnml(case, caseroot, compname): # copy namelist files and stream text files, to rundir copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_dice* files needed in this case + This function is called by CIME to stage the user_nl_dice* files in the case + directory. + """ + user_nl_list = ["user_nl_dice", "user_nl_dice_streams"] + return user_nl_list + ############################################################################### def _main_func(): # Build the component namelist and required stream txt files diff --git a/dice/cime_config/user_nl_dice_streams b/dice/cime_config/user_nl_dice_streams new file mode 100644 index 000000000..6472afeb8 --- /dev/null +++ b/dice/cime_config/user_nl_dice_streams @@ -0,0 +1,23 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +!------------------------------------------------------------------------ diff --git a/dice/ice_comp_nuopc.F90 b/dice/ice_comp_nuopc.F90 index a28d52428..5eb37ad1f 100644 --- a/dice/ice_comp_nuopc.F90 +++ b/dice/ice_comp_nuopc.F90 @@ -28,7 +28,7 @@ module cdeps_dice_comp use shr_sys_mod , only : shr_sys_abort use shr_cal_mod , only : shr_cal_ymd2date, shr_cal_ymd2julian use shr_mpi_mod , only : shr_mpi_bcast - use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_mesh_init + use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_mesh_init, dshr_check_restart_alarm use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_log_clock_advance use dshr_methods_mod , only : dshr_state_diagnose, chkerr, memcheck use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_init_from_config, shr_strdata_advance @@ -415,16 +415,8 @@ subroutine ModelAdvance(gcomp, rc) cosArg = 2.0_R8*shr_const_pi*(jday - jday0)/365.0_R8 ! Determine if will write restarts - call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) + restart_write = dshr_check_restart_alarm(clock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_AlarmRingerOff( alarm, rc=rc ) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - restart_write = .true. - else - restart_write = .false. - endif ! Run dice call dice_comp_run(importState, exportState, next_ymd, next_tod, cosarg, restart_write, rc) diff --git a/dlnd/cime_config/buildnml b/dlnd/cime_config/buildnml index 1faca3123..9c93d82d2 100755 --- a/dlnd/cime_config/buildnml +++ b/dlnd/cime_config/buildnml @@ -82,35 +82,25 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path namelist_file = os.path.join(confdir, "dlnd_in") nmlgen.write_output_file(namelist_file, data_list_path, groups=['dlnd_nml']) + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + # Generate dlnd.streams.xml outfile = os.path.join(confdir, "dlnd.streams"+inst_string+".xml" ) - user_stream_file = os.path.join(case.get_value("CASEROOT"),os.path.basename(outfile)) - if os.path.isfile(user_stream_file): - schema_file = os.path.join(_CDEPS_CONFIG,"streams.xsd") - streams = StreamCDEPS(user_stream_file, schema_file) - streams.update_input_data_list(os.path.join(caseroot,"Buildconf","dlnd.input_data_list")) - else: - # Determine streams - streamlist = nmlgen.get_streams() - if type(streamlist) == type(str()): - streamlist = [] - - schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") - stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dlnd","cime_config","stream_definition_dlnd.xml") - streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dlnd","cime_config","stream_definition_dlnd.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_dlnd_streams'+inst_string)) ############################################################################### def buildnml(case, caseroot, compname): ############################################################################### - - # Build the component namelist and required stream xml files - - if compname != "dlnd": - raise AttributeError - rundir = case.get_value("RUNDIR") - ninst = case.get_value("NINST_LND") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) if ninst is None: ninst = case.get_value("NINST") confdir = os.path.join(caseroot,"Buildconf",compname + "conf") @@ -127,9 +117,9 @@ def buildnml(case, caseroot, compname): # NOTE: User definition *replaces* existing definition. files = Files(comp_interface="nuopc") - definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":"dlnd"})] + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] - user_definition = os.path.join(user_xml_dir, "namelist_definition_dlnd.xml") + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") if os.path.isfile(user_definition): definition_file = [user_definition] for file_ in definition_file: @@ -142,7 +132,7 @@ def buildnml(case, caseroot, compname): # Clear out old data. #---------------------------------------------------- - data_list_path = os.path.join(case.get_case_root(), "Buildconf", "dlnd.input_data_list") + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") if os.path.exists(data_list_path): os.remove(data_list_path) @@ -181,6 +171,16 @@ def buildnml(case, caseroot, compname): # copy namelist files and stream text files, to rundir copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_dlnd* files needed in this case + This function is called by CIME to stage the user_nl_dlnd* files in the case + directory. + """ + user_nl_list = ["user_nl_dlnd", "user_nl_dlnd_streams"] + return user_nl_list + ############################################################################### def _main_func(): # Build the component namelist and required stream xml files diff --git a/dlnd/cime_config/user_nl_dlnd_streams b/dlnd/cime_config/user_nl_dlnd_streams new file mode 100644 index 000000000..6472afeb8 --- /dev/null +++ b/dlnd/cime_config/user_nl_dlnd_streams @@ -0,0 +1,23 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +!------------------------------------------------------------------------ diff --git a/dlnd/lnd_comp_nuopc.F90 b/dlnd/lnd_comp_nuopc.F90 index 5bb6d73dc..ea88469a3 100644 --- a/dlnd/lnd_comp_nuopc.F90 +++ b/dlnd/lnd_comp_nuopc.F90 @@ -29,7 +29,7 @@ module cdeps_dlnd_comp use dshr_methods_mod , only : dshr_state_getfldptr, dshr_state_diagnose, chkerr, memcheck use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_advance, shr_strdata_get_stream_domain use dshr_strdata_mod , only : shr_strdata_init_from_config - use dshr_mod , only : dshr_model_initphase, dshr_init + use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_check_restart_alarm use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_log_clock_advance use dshr_mod , only : dshr_restart_read, dshr_restart_write, dshr_mesh_init use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy @@ -325,6 +325,7 @@ subroutine ModelAdvance(gcomp, rc) integer :: yr ! year integer :: mon ! month integer :: day ! day in month + logical :: write_restart character(len=*),parameter :: subname=trim(modName)//':(ModelAdvance) ' !------------------------------------------------------------------------------- @@ -351,19 +352,16 @@ subroutine ModelAdvance(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! write_restart if alarm is ringing - call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) + write_restart = dshr_check_restart_alarm(clock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_AlarmRingerOff( alarm, rc=rc ) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - + if (write_restart) then call ESMF_TraceRegionEnter('dlnd_restart') call dshr_restart_write(rpfile, case_name, 'dlnd', inst_suffix, next_ymd, next_tod, & logunit, my_task, sdat) call ESMF_TraceRegionExit('dlnd_restart') endif + ! write diagnostics if (diagnose_data) then call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES',rc=rc) diff --git a/docn/cime_config/buildnml b/docn/cime_config/buildnml index cb45d0f9b..3096a2ce3 100755 --- a/docn/cime_config/buildnml +++ b/docn/cime_config/buildnml @@ -89,6 +89,11 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path namelist_file = os.path.join(confdir, "docn_in") nmlgen.write_output_file(namelist_file, data_list_path, groups=['docn_nml']) + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + # Generate docn.streams.xml if needed print("docn_mode is {}".format(docn_mode)) if (re.search(r'sst_aquap[0-9]+',docn_mode) is not None) or (docn_mode == 'sst_aquap_constant'): @@ -96,34 +101,20 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path else: generate_stream_file = True #endif - outfile = os.path.join(confdir, "docn.streams"+inst_string+".xml" ) - user_stream_file = os.path.join(case.get_value("CASEROOT"),os.path.basename(outfile)) - if os.path.isfile(user_stream_file): - schema_file = os.path.join(_CDEPS_CONFIG,"streams.xsd") - streams = StreamCDEPS(user_stream_file, schema_file) - streams.update_input_data_list(os.path.join(caseroot,"Buildconf","docn.input_data_list")) - elif generate_stream_file: - # Determine streams - streamlist = nmlgen.get_streams() - if type(streamlist) == type(str()): - streamlist = [] - + if generate_stream_file: + outfile = os.path.join(confdir, "docn.streams"+inst_string+".xml" ) schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "docn","cime_config","stream_definition_docn.xml") streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path) - #endif + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_docn_streams'+inst_string)) ############################################################################### def buildnml(case, caseroot, compname): ############################################################################### - - # Build the component namelist and required stream xml files - if compname != "docn": - raise AttributeError - rundir = case.get_value("RUNDIR") - ninst = case.get_value("NINST_OCN") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) if ninst is None: ninst = case.get_value("NINST") @@ -142,9 +133,9 @@ def buildnml(case, caseroot, compname): # NOTE: User definition *replaces* existing definition. files = Files(comp_interface="nuopc") - definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":"docn"})] + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] - user_definition = os.path.join(user_xml_dir, "namelist_definition_docn.xml") + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") if os.path.isfile(user_definition): definition_file = [user_definition] for file_ in definition_file: @@ -156,7 +147,7 @@ def buildnml(case, caseroot, compname): #---------------------------------------------------- # Clear out old data. #---------------------------------------------------- - data_list_path = os.path.join(case.get_case_root(), "Buildconf", "docn.input_data_list") + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") if os.path.exists(data_list_path): os.remove(data_list_path) @@ -194,6 +185,16 @@ def buildnml(case, caseroot, compname): copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_docn* files needed in this case + This function is called by CIME to stage the user_nl_docn* files in the case + directory. + """ + user_nl_list = ["user_nl_docn", "user_nl_docn_streams"] + return user_nl_list + ############################################################################### def _main_func(): # Build the component namelist and required stream xml files diff --git a/docn/cime_config/user_nl_docn_streams b/docn/cime_config/user_nl_docn_streams new file mode 100644 index 000000000..6472afeb8 --- /dev/null +++ b/docn/cime_config/user_nl_docn_streams @@ -0,0 +1,23 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +!------------------------------------------------------------------------ diff --git a/docn/ocn_comp_nuopc.F90 b/docn/ocn_comp_nuopc.F90 index 0887f9746..b132c3a8d 100644 --- a/docn/ocn_comp_nuopc.F90 +++ b/docn/ocn_comp_nuopc.F90 @@ -30,7 +30,7 @@ module cdeps_docn_comp use dshr_methods_mod , only : dshr_state_diagnose, chkerr, memcheck use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_advance, shr_strdata_init_from_config use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_mesh_init - use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock + use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_check_restart_alarm use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_realize @@ -239,7 +239,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call shr_mpi_bcast(sst_constant_value , mpicom, 'sst_constant_value') ! Special logic for prescribed aquaplanet - if (datamode(1:9) == 'sst_aquap') then + if (datamode(1:9) == 'sst_aquap' .and. trim(datamode) /= 'sst_aquap_constant') then ! First determine the prescribed aquaplanet option if (len_trim(datamode) == 10) then read(datamode(10:10),'(i1)') aquap_option @@ -422,16 +422,7 @@ subroutine ModelAdvance(gcomp, rc) call shr_cal_ymd2date(yr, mon, day, next_ymd) ! determine if will write restart - call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_AlarmRingerOff( alarm, rc=rc ) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - restart_write = .true. - else - restart_write = .false. - end if + restart_write = dshr_check_restart_alarm(clock, rc=rc) ! run docn call docn_comp_run(importState, exportState, clock, next_ymd, next_tod, restart_write, rc=rc) diff --git a/drof/cime_config/buildnml b/drof/cime_config/buildnml index 1d0a7cc52..f33982011 100755 --- a/drof/cime_config/buildnml +++ b/drof/cime_config/buildnml @@ -81,34 +81,29 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path namelist_file = os.path.join(confdir, "drof_in") nmlgen.write_output_file(namelist_file, data_list_path, groups=['drof_nml']) + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + # Generate drof.streams.xml outfile = os.path.join(confdir, "drof.streams"+inst_string+".xml" ) - user_stream_file = os.path.join(case.get_value("CASEROOT"),os.path.basename(outfile)) - if os.path.isfile(user_stream_file): - schema_file = os.path.join(_CDEPS_CONFIG,"streams.xsd") - streams = StreamCDEPS(user_stream_file, schema_file) - streams.update_input_data_list(os.path.join(caseroot,"Buildconf","drof.input_data_list")) - else: - streamlist = nmlgen.get_streams() - if type(streamlist) == type(str()): - streamlist = [] - schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") - stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "drof","cime_config","stream_definition_drof.xml") - streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "drof","cime_config","stream_definition_drof.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_drof_streams'+inst_string)) ############################################################################### def buildnml(case, caseroot, compname): ############################################################################### - # Build the component namelist and required stream txt files - if compname != "drof": - raise AttributeError - rundir = case.get_value("RUNDIR") - ninst = case.get_value("NINST_ROF") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) if ninst is None: ninst = case.get_value("NINST") + # Determine configuration directory confdir = os.path.join(caseroot,"Buildconf",compname + "conf") if not os.path.isdir(confdir): @@ -124,9 +119,9 @@ def buildnml(case, caseroot, compname): # NOTE: User definition *replaces* existing definition. files = Files(comp_interface="nuopc") - definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":"drof"})] + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] - user_definition = os.path.join(user_xml_dir, "namelist_definition_drof.xml") + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") if os.path.isfile(user_definition): definition_file = [user_definition] for file_ in definition_file: @@ -138,8 +133,7 @@ def buildnml(case, caseroot, compname): #---------------------------------------------------- # Clear out old data. #---------------------------------------------------- - data_list_path = os.path.join(case.get_case_root(), "Buildconf", - "drof.input_data_list") + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") if os.path.exists(data_list_path): os.remove(data_list_path) @@ -178,6 +172,15 @@ def buildnml(case, caseroot, compname): # copy namelist files and stream text files, to rundir copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_drof* files needed in this case + This function is called by CIME to stage the user_nl_drof* files in the case + directory. + """ + user_nl_list = ["user_nl_drof", "user_nl_drof_streams"] + return user_nl_list ############################################################################### def _main_func(): diff --git a/drof/cime_config/user_nl_drof_streams b/drof/cime_config/user_nl_drof_streams new file mode 100644 index 000000000..6472afeb8 --- /dev/null +++ b/drof/cime_config/user_nl_drof_streams @@ -0,0 +1,23 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +!------------------------------------------------------------------------ diff --git a/drof/rof_comp_nuopc.F90 b/drof/rof_comp_nuopc.F90 index 396f8f3ae..0d35b5fab 100644 --- a/drof/rof_comp_nuopc.F90 +++ b/drof/rof_comp_nuopc.F90 @@ -32,7 +32,7 @@ module cdeps_drof_comp use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_advance, shr_strdata_get_stream_domain use dshr_strdata_mod , only : shr_strdata_init_from_config use dshr_mod , only : dshr_model_initphase, dshr_init - use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock + use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_check_restart_alarm use dshr_mod , only : dshr_restart_read, dshr_restart_write, dshr_mesh_init use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add, dshr_fldlist_realize @@ -339,17 +339,9 @@ subroutine ModelAdvance(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call shr_cal_ymd2date(yr, mon, day, next_ymd) - ! write_restart if alarm is ringing - call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) + ! write restart if alarm is ringing + restart_write = dshr_check_restart_alarm(clock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_AlarmRingerOff( alarm, rc=rc ) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - restart_write = .true. - else - restart_write = .false. - endif ! run drof call drof_comp_run(exportState, next_ymd, next_tod, restart_write, rc=rc) diff --git a/dshr/dshr_mod.F90 b/dshr/dshr_mod.F90 index 5a6e71516..a8b219828 100644 --- a/dshr/dshr_mod.F90 +++ b/dshr/dshr_mod.F90 @@ -77,6 +77,7 @@ module dshr_mod character(len=*) , parameter :: orb_fixed_year = 'fixed_year' character(len=*) , parameter :: orb_variable_year = 'variable_year' character(len=*) , parameter :: orb_fixed_parameters = 'fixed_parameters' + logical :: write_restart_at_endofrun integer , parameter :: master_task = 0 character(*), parameter :: u_FILE_u = & @@ -213,6 +214,12 @@ subroutine dshr_init(gcomp, compname, sdat, mpicom, my_task, inst_index, inst_su inst_index=1 endif + call NUOPC_CompAttributeGet(gcomp, name="write_restart_at_endofrun", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.true.') write_restart_at_endofrun = .true. + end if + #ifdef CESMCOUPLED sdat%pio_subsystem => shr_pio_getiosys(trim(compname)) sdat%io_type = shr_pio_getiotype(trim(compname)) @@ -453,10 +460,14 @@ subroutine dshr_set_runclock(gcomp, rc) type(ESMF_Time) :: mstoptime type(ESMF_TimeInterval) :: mtimestep, dtimestep character(len=256) :: cvalue - character(len=256) :: restart_option ! Restart option units - integer :: restart_n ! Number until restart interval - integer :: restart_ymd ! Restart date (YYYYMMDD) + character(len=256) :: restart_option ! Restart option units + integer :: restart_n ! Number until restart interval + integer :: restart_ymd ! Restart date (YYYYMMDD) type(ESMF_ALARM) :: restart_alarm + character(len=256) :: stop_option ! Stop option units + integer :: stop_n ! Number until stop interval + integer :: stop_ymd ! Stop date (YYYYMMDD) + type(ESMF_ALARM) :: stop_alarm character(len=128) :: name integer :: alarmcount character(len=*),parameter :: subname='dshr_mod:(ModelSetRunClock) ' @@ -510,6 +521,30 @@ subroutine dshr_set_runclock(gcomp, rc) call ESMF_AlarmSet(restart_alarm, clock=mclock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + !---------------- + ! Stop alarm + !---------------- + call NUOPC_CompAttributeGet(gcomp, name="stop_option", value=stop_option, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call NUOPC_CompAttributeGet(gcomp, name="stop_n", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_n + + call NUOPC_CompAttributeGet(gcomp, name="stop_ymd", value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) stop_ymd + + call dshr_alarm_init(mclock, stop_alarm, stop_option, & + opt_n = stop_n, & + opt_ymd = stop_ymd, & + RefTime = mcurrTime, & + alarmname = 'alarm_stop', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_AlarmSet(stop_alarm, clock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if ! Advance model clock to trigger alarms then reset model clock back to currtime @@ -577,6 +612,7 @@ subroutine dshr_alarm_init( clock, alarm, option, & optMonthly = "monthly" , & optYearly = "yearly" , & optDate = "date" , & + optEnd = "end" , & optIfdays0 = "ifdays0" character(len=*), parameter :: subname = '(dshr_alarm_init): ' !------------------------------------------------------------------------------- @@ -623,6 +659,13 @@ subroutine dshr_alarm_init( clock, alarm, option, & if (chkerr(rc,__LINE__,u_FILE_u)) return update_nextalarm = .false. + case (optEnd) + call ESMF_TimeIntervalSet(AlarmInterval, yy=9999, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_TimeSet( NextAlarm, yy=9999, mm=12, dd=1, s=0, calendar=cal, rc=rc ) + if (chkerr(rc,__LINE__,u_FILE_u)) return + update_nextalarm = .false. + case (optDate) if (.not. present(opt_ymd)) then call shr_sys_abort(subname//trim(option)//' requires opt_ymd') @@ -1844,5 +1887,56 @@ subroutine dshr_pio_init(gcomp, sdat, logunit, rc) pio_rearr_comm_max_pend_req_io2comp) end subroutine dshr_pio_init +! +! Returns trun if the restart alarm is ringing or its the end of the run and +! REST_OPTION is not none or never +! + logical function dshr_check_restart_alarm(clock, rc) + use ESMF, only : ESMF_ClockGetAlarm, ESMF_AlarmIsRinging, ESMF_AlarmRingerOff + integer, intent(out) :: rc + type(ESMF_CLOCK), intent(in) :: clock + + type(ESMF_ALARM) :: alarm + logical :: nlend, rstwr + !-------------------------------- + ! Determine if time to stop + !-------------------------------- + + rc = ESMF_SUCCESS + + call ESMF_ClockGetAlarm(clock, alarmname='alarm_stop', alarm=alarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (ESMF_AlarmIsRinging(alarm, rc=rc)) then + if (ChkErr(rc,__LINE__,u_FILE_u)) return + nlend = .true. + call ESMF_AlarmRingerOff( alarm, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + nlend = .false. + endif + + !-------------------------------- + ! Determine if time to write restart + !-------------------------------- + + if (nlend .and. write_restart_at_endofrun) then + rstwr = .true. + else + call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (ESMF_AlarmIsRinging(alarm, rc=rc)) then + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rstwr = .true. + call ESMF_AlarmRingerOff( alarm, rc=rc ) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + rstwr = .false. + endif + end if + dshr_check_restart_alarm = rstwr + end function dshr_check_restart_alarm + end module dshr_mod diff --git a/dwav/cime_config/buildnml b/dwav/cime_config/buildnml index e4505a77e..4c53dc646 100755 --- a/dwav/cime_config/buildnml +++ b/dwav/cime_config/buildnml @@ -80,33 +80,25 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path namelist_file = os.path.join(confdir, "dwav_in") nmlgen.write_output_file(namelist_file, data_list_path, groups=['dwav_nml']) + # Determine streams + streamlist = nmlgen.get_streams() + if type(streamlist) == type(str()): + streamlist = [] + # Generate dwav.streams.xml outfile = os.path.join(confdir, "dwav.streams"+inst_string+".xml" ) - user_stream_file = os.path.join(case.get_value("CASEROOT"),os.path.basename(outfile)) - if os.path.isfile(user_stream_file): - schema_file = os.path.join(_CDEPS_CONFIG,"streams.xsd") - streams = StreamCDEPS(user_stream_file, schema_file) - streams.update_input_data_list(os.path.join(caseroot,"Buildconf","dwav.input_data_list")) - else: - streamlist = nmlgen.get_streams() - if type(streamlist) == type(str()): - streamlist = [] - schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") - stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dwav","cime_config","stream_definition_dwav.xml") - streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path) + schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") + stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "dwav","cime_config","stream_definition_dwav.xml") + streams = StreamCDEPS(stream_file, schema_file) + streams.create_stream_xml(streamlist, case, outfile, data_list_path, + os.path.join(caseroot,'user_nl_dwav_streams'+inst_string)) ############################################################################### def buildnml(case, caseroot, compname): ############################################################################### - - # Build the component namelist and required stream txt files - - if compname != "dwav": - raise AttributeError - rundir = case.get_value("RUNDIR") - ninst = case.get_value("NINST_WAV") + inst_name = compname.upper()[1:] + ninst = case.get_value("NINST_"+inst_name) if ninst is None: ninst = case.get_value("NINST") @@ -125,9 +117,9 @@ def buildnml(case, caseroot, compname): # NOTE: User definition *replaces* existing definition. files = Files(comp_interface="nuopc") - definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":"dwav"})] + definition_file = [files.get_value("NAMELIST_DEFINITION_FILE", {"component":compname})] - user_definition = os.path.join(user_xml_dir, "namelist_definition_dwav.xml") + user_definition = os.path.join(user_xml_dir, "namelist_definition_"+compname+".xml") if os.path.isfile(user_definition): definition_file = [user_definition] for file_ in definition_file: @@ -139,7 +131,7 @@ def buildnml(case, caseroot, compname): #---------------------------------------------------- # Clear out old data. #---------------------------------------------------- - data_list_path = os.path.join(case.get_case_root(), "Buildconf", "dwav.input_data_list") + data_list_path = os.path.join(caseroot, "Buildconf", compname+".input_data_list") if os.path.exists(data_list_path): os.remove(data_list_path) @@ -178,6 +170,16 @@ def buildnml(case, caseroot, compname): # copy namelist files and stream text files, to rundir copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) +############################################################################### +def get_user_nl_list(case): +############################################################################### + """Returns a list of user_nl_dwav* files needed in this case + This function is called by CIME to stage the user_nl_dwav* files in the case + directory. + """ + user_nl_list = ["user_nl_dwav", "user_nl_dwav_streams"] + return user_nl_list + ############################################################################### def _main_func(): # Build the component namelist and required stream txt files diff --git a/dwav/cime_config/user_nl_dwav_streams b/dwav/cime_config/user_nl_dwav_streams new file mode 100644 index 000000000..6472afeb8 --- /dev/null +++ b/dwav/cime_config/user_nl_dwav_streams @@ -0,0 +1,23 @@ +!------------------------------------------------------------------------ +! This file is used to modify datm.streams.xml generated in $RUNDIR +! Entries should have the form +! :<= new stream_value> +! The following are accepted values for an assume streamname of foo +! foo:meshfile = character string +! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) +! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) +! foo:taxmode = one of [cycle, extend, limit] +! foo:tintalgo = one of [lower,upper,nearest,linear,coszen] +! foo:readmode = single (only suported mode right now) +! foo:mapalgo = one of [bilinear,redist,nn,consf,consd,none] +! foo:dtlimit = real (1.5 is default) +! foo:year_first = integer +! foo:year_last = integer +! foo:year_align = integer +! foo:vectors = one of [none,u:v] +! foo:lev_dimname: = one of [null,name of level dimenion name] +! foo:offset = integer +! As an example: +! foo:year_first = 1950 +! would change the stream year_first stream_entry to 1950 for the foo stream block +!------------------------------------------------------------------------ diff --git a/dwav/wav_comp_nuopc.F90 b/dwav/wav_comp_nuopc.F90 index 6975b534e..c9b8f9291 100644 --- a/dwav/wav_comp_nuopc.F90 +++ b/dwav/wav_comp_nuopc.F90 @@ -29,7 +29,7 @@ module cdeps_dwav_comp use dshr_methods_mod , only : dshr_state_getfldptr, chkerr, memcheck, dshr_state_diagnose use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_advance use dshr_strdata_mod , only : shr_strdata_init_from_config - use dshr_mod , only : dshr_model_initphase, dshr_init + use dshr_mod , only : dshr_model_initphase, dshr_init, dshr_check_restart_alarm use dshr_mod , only : dshr_state_setscalar, dshr_set_runclock, dshr_log_clock_advance use dshr_mod , only : dshr_restart_read, dshr_restart_write, dshr_mesh_init use dshr_dfield_mod , only : dfield_type, dshr_dfield_add, dshr_dfield_copy @@ -307,6 +307,7 @@ subroutine ModelAdvance(gcomp, rc) integer :: day ! day in month integer :: next_ymd ! model date integer :: next_tod ! model sec into model date + logical :: write_restart character(len=*),parameter :: subname=trim(modName)//':(ModelAdvance) ' !------------------------------------------------------------------------------- @@ -334,13 +335,9 @@ subroutine ModelAdvance(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! write_restart if alarm is ringing - call ESMF_ClockGetAlarm(clock, alarmname='alarm_restart', alarm=alarm, rc=rc) + write_restart = dshr_check_restart_alarm(clock, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (ESMF_AlarmIsRinging(alarm, rc=rc)) then - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_AlarmRingerOff( alarm, rc=rc ) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - + if (write_restart) then call ESMF_TraceRegionEnter('dwav_restart') call NUOPC_CompAttributeGet(gcomp, name='case_name', value=case_name, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/streams/dshr_strdata_mod.F90 b/streams/dshr_strdata_mod.F90 index 0f7dfa063..38fb8524d 100644 --- a/streams/dshr_strdata_mod.F90 +++ b/streams/dshr_strdata_mod.F90 @@ -12,7 +12,9 @@ module dshr_strdata_mod use ESMF , only : ESMF_TimeIntervalGet, ESMF_TYPEKIND_R8, ESMF_FieldCreate use ESMF , only : ESMF_FILEFORMAT_ESMFMESH, ESMF_FieldCreate use ESMF , only : ESMF_FieldBundleCreate, ESMF_MESHLOC_ELEMENT, ESMF_FieldBundleAdd - use ESMF , only : ESMF_POLEMETHOD_ALLAVG, ESMF_EXTRAPMETHOD_NEAREST_STOD, ESMF_REGRIDMETHOD_BILINEAR, ESMF_REGRIDMETHOD_NEAREST_STOD + use ESMF , only : ESMF_POLEMETHOD_ALLAVG, ESMF_EXTRAPMETHOD_NEAREST_STOD + use ESMF , only : ESMF_REGRIDMETHOD_BILINEAR, ESMF_REGRIDMETHOD_NEAREST_STOD + use ESMF , only : ESMF_REGRIDMETHOD_CONSERVE, ESMF_NORMTYPE_FRACAREA, ESMF_NORMTYPE_DSTAREA use ESMF , only : ESMF_ClockGet, operator(-), operator(==), ESMF_CALKIND_NOLEAP use ESMF , only : ESMF_FieldReGridStore, ESMF_FieldRedistStore, ESMF_UNMAPPEDACTION_IGNORE use ESMF , only : ESMF_TERMORDER_SRCSEQ, ESMF_FieldRegrid, ESMF_FieldFill @@ -522,6 +524,8 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) sdat%pstrm(ns)%field_stream = ESMF_FieldCreate(stream_mesh, & ESMF_TYPEKIND_r8, meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldFill(sdat%pstrm(ns)%field_stream, dataFillScheme="const", const1=1.0_r8, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return end if endif @@ -556,6 +560,24 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) srcMaskValues = (/0/), & ! ignore source points where the mask is 0 srcTermProcessing=srcTermProcessing_Value, ignoreDegenerate=.true., & unmappedaction=ESMF_UNMAPPEDACTION_IGNORE, rc=rc) + else if (trim(sdat%stream(ns)%mapalgo) == 'consf') then + call ESMF_FieldReGridStore(sdat%pstrm(ns)%field_stream, lfield_dst, & + routehandle=sdat%pstrm(ns)%routehandle, & + regridmethod=ESMF_REGRIDMETHOD_CONSERVE, & + normType=ESMF_NORMTYPE_FRACAREA, & + dstMaskValues = (/0/), & ! ignore destination points where the mask is 0 + srcMaskValues = (/0/), & ! ignore source points where the mask is 0 + srcTermProcessing=srcTermProcessing_Value, ignoreDegenerate=.true., & + unmappedaction=ESMF_UNMAPPEDACTION_IGNORE, rc=rc) + else if (trim(sdat%stream(ns)%mapalgo) == 'consd') then + call ESMF_FieldReGridStore(sdat%pstrm(ns)%field_stream, lfield_dst, & + routehandle=sdat%pstrm(ns)%routehandle, & + regridmethod=ESMF_REGRIDMETHOD_CONSERVE, & + normType=ESMF_NORMTYPE_DSTAREA, & + dstMaskValues = (/0/), & ! ignore destination points where the mask is 0 + srcMaskValues = (/0/), & ! ignore source points where the mask is 0 + srcTermProcessing=srcTermProcessing_Value, ignoreDegenerate=.true., & + unmappedaction=ESMF_UNMAPPEDACTION_IGNORE, rc=rc) else if (trim(sdat%stream(ns)%mapalgo) == 'none') then ! single point stream data, no action required. else @@ -1342,6 +1364,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & character(*), parameter :: subname = '(shr_strdata_readstrm) ' character(*), parameter :: F00 = "('(shr_strdata_readstrm) ',8a)" character(*), parameter :: F02 = "('(shr_strdata_readstrm) ',2a,i8)" + character(CL) :: errmsg !------------------------------------------------------------------------------- rc = ESMF_SUCCESS @@ -1490,6 +1513,12 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & call shr_sys_abort(' ERROR: reading in variable: '// trim(per_stream%fldlist_stream(nf))) end if if (handlefill) then + ! Single point streams are not allowed to have missing values + if (stream%mapalgo == 'none' .and. any(data_real2d == fillvalue_r4)) then + write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) + if(sdat%masterproc) write(sdat%logunit,*) trim(errmsg) + call shr_sys_abort(errmsg) + endif do lev = 1,stream_nlev do n = 1,size(dataptr2d, dim=2) if (.not. shr_infnan_isnan(data_real2d(n,lev)) .and. data_real2d(n,lev) .ne. fillvalue_r4) then @@ -1516,6 +1545,13 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & call shr_sys_abort(' ERROR: reading in variable: '// trim(per_stream%fldlist_stream(nf))) end if if (handlefill) then + ! Single point streams are not allowed to have missing values + if (stream%mapalgo == 'none' .and. any(data_real1d == fillvalue_r4)) then + write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) + if(sdat%masterproc) write(sdat%logunit,*) trim(errmsg) + call shr_sys_abort(errmsg) + endif + do n=1,size(dataptr1d) if(.not. shr_infnan_isnan(data_real1d(n)) .and. data_real1d(n) .ne. fillvalue_r4) then dataptr1d(n) = real(data_real1d(n), kind=r8) @@ -1542,6 +1578,12 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & call shr_sys_abort(' ERROR: reading in 2d double variable: '// trim(per_stream%fldlist_stream(nf))) end if if (handlefill) then + ! Single point streams are not allowed to have missing values + if (stream%mapalgo == 'none' .and. any(data_dbl2d == fillvalue_r8)) then + write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) + if(sdat%masterproc) write(sdat%logunit,*) trim(errmsg) + call shr_sys_abort(errmsg) + endif do lev = 1,stream_nlev do n = 1,size(dataptr2d, dim=2) if (.not. shr_infnan_isnan(data_dbl2d(n,lev)) .and. data_dbl2d(n,lev) .ne. fillvalue_r8) then @@ -1568,6 +1610,12 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & call shr_sys_abort(' ERROR: reading in variable: '// trim(per_stream%fldlist_stream(nf))) end if if (handlefill) then + ! Single point streams are not allowed to have missing values + if (stream%mapalgo == 'none' .and. any(data_dbl1d == fillvalue_r8)) then + write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) + if(sdat%masterproc) write(sdat%logunit,*) trim(errmsg) + call shr_sys_abort(errmsg) + endif do n = 1,size(dataptr1d) if (.not. shr_infnan_isnan(data_dbl1d(n)) .and. data_dbl1d(n) .ne. fillvalue_r8) then dataptr1d(n) = data_dbl1d(n) diff --git a/streams/dshr_stream_mod.F90 b/streams/dshr_stream_mod.F90 index c758136a3..349eb7a43 100644 --- a/streams/dshr_stream_mod.F90 +++ b/streams/dshr_stream_mod.F90 @@ -60,10 +60,27 @@ module dshr_stream_mod public :: shr_stream_dataDump ! internal stream data for debugging public :: shr_stream_restIO ! read or write to netcdf restart file + character(CS),parameter,public :: shr_stream_file_null = 'not_set' + + ! valid values for time extrapoloation character(CS),parameter,public :: shr_stream_taxis_cycle = 'cycle' character(CS),parameter,public :: shr_stream_taxis_extend = 'extend' character(CS),parameter,public :: shr_stream_taxis_limit = 'limit' - character(CS),parameter,public :: shr_stream_file_null = 'not_set' + + ! valid values for time interpolation + character(CS),parameter,public :: shr_stream_tinterp_lower = 'lower' + character(CS),parameter,public :: shr_stream_tinterp_upper = 'upper' + character(CS),parameter,public :: shr_stream_tinterp_nearest = 'nearest' + character(CS),parameter,public :: shr_stream_tinterp_linear = 'linear' + character(CS),parameter,public :: shr_stream_tinterp_coszen = 'coszen' + + ! valid values for mapping interpolation + character(CS),parameter,public :: shr_stream_mapalgo_bilinear = 'bilinear' + character(CS),parameter,public :: shr_stream_mapalgo_redist = 'redist' + character(CS),parameter,public :: shr_stream_mapalgo_nn = 'nn' + character(CS),parameter,public :: shr_stream_mapalgo_consf = 'consf' + character(CS),parameter,public :: shr_stream_mapalgo_consd = 'consd' + character(CS),parameter,public :: shr_stream_mapalgo_none = 'none' ! a useful derived type to use inside shr_streamType --- type shr_stream_file_type @@ -82,10 +99,10 @@ module dshr_stream_mod type shr_stream_streamType !private ! no public access to internal components - integer :: logunit ! stdout log unit type(iosystem_desc_t), pointer :: pio_subsystem integer :: pio_iotype integer :: pio_ioformat + integer :: logunit ! stdout log unit logical :: init = .false. ! has stream been initialized integer :: nFiles = 0 ! number of data files integer :: yearFirst = -1 ! first year to use in t-axis (yyyymmdd) @@ -138,23 +155,23 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu ! ! ! - ! - ! + ! ! + ! ! - ! - ! - ! - ! - ! - ! - ! + ! + ! + ! + ! + ! + ! + ! ! - ! - ! + ! + ! ! - ! - ! + ! + ! ! ! ! --------------------------------------------------------------------- @@ -195,7 +212,7 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu streamlist => getElementsByTagname(Sdoc, "stream_info") nstrms = getLength(streamlist) - ! allocate an array of shr_stream_streamtype objects on just isroot_task + ! allocate an array of shr_streamtype objects on just isroot_task allocate(streamdat(nstrms)) ! fill in non-default values for the streamdat attributes @@ -205,82 +222,111 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu p => item(getElementsByTagname(streamnode, "taxmode"), 0) if (associated(p)) then call extractDataContent(p, streamdat(i)%taxmode) + if (streamdat(i)%taxmode /= shr_stream_taxis_cycle .and. & + streamdat(i)%taxmode /= shr_stream_taxis_extend .and. & + streamdat(i)%taxmode /= shr_stream_taxis_limit) then + call shr_sys_abort("tintalgo must have a value of either cycle, extend or limit") + end if endif p => item(getElementsByTagname(streamnode, "mapalgo"), 0) - if(associated(p)) then + if (associated(p)) then call extractDataContent(p, streamdat(i)%mapalgo) + if (streamdat(i)%mapalgo /= shr_stream_mapalgo_bilinear .and. & + streamdat(i)%mapalgo /= shr_stream_mapalgo_redist .and. & + streamdat(i)%mapalgo /= shr_stream_mapalgo_nn .and. & + streamdat(i)%mapalgo /= shr_stream_mapalgo_consf .and. & + streamdat(i)%mapalgo /= shr_stream_mapalgo_consd .and. & + streamdat(i)%mapalgo /= shr_stream_mapalgo_none) then + call shr_sys_abort("mapaglo must have a value of either bilinear, redist, nn, consf or consd") + end if endif - p => item(getElementsByTagname(streamnode, "tInterpAlgo"), 0) - if(associated(p)) then + + p => item(getElementsByTagname(streamnode, "tintalgo"), 0) + if (associated(p)) then call extractDataContent(p, streamdat(i)%tInterpAlgo) + if (streamdat(i)%tInterpAlgo /= shr_stream_tinterp_lower .and. & + streamdat(i)%tInterpAlgo /= shr_stream_tinterp_upper .and. & + streamdat(i)%tInterpAlgo /= shr_stream_tinterp_nearest .and. & + streamdat(i)%tInterpAlgo /= shr_stream_tinterp_linear .and. & + streamdat(i)%tInterpAlgo /= shr_stream_tinterp_coszen) then + call shr_sys_abort("tintalgo must have a value of either lower, upper, nearest, linear or coszen") + end if endif - p => item(getElementsByTagname(streamnode, "readMode"), 0) - if(associated(p)) then + + p => item(getElementsByTagname(streamnode, "readmode"), 0) + if (associated(p)) then call extractDataContent(p, streamdat(i)%readMode) endif - p=> item(getElementsByTagname(streamnode, "yearFirst"), 0) + + p=> item(getElementsByTagname(streamnode, "year_first"), 0) if(associated(p)) then call extractDataContent(p, streamdat(i)%yearFirst) else call shr_sys_abort("yearFirst must be provided") endif - p=> item(getElementsByTagname(streamnode, "yearLast"), 0) + + p=> item(getElementsByTagname(streamnode, "year_last"), 0) if(associated(p)) then call extractDataContent(p, streamdat(i)%yearLast) else call shr_sys_abort("yearLast must be provided") endif - p=> item(getElementsByTagname(streamnode, "yearAlign"), 0) + + p=> item(getElementsByTagname(streamnode, "year_align"), 0) if(associated(p)) then call extractDataContent(p, streamdat(i)%yearAlign) else call shr_sys_abort("yearAlign must be provided") endif + p=> item(getElementsByTagname(streamnode, "dtlimit"), 0) if(associated(p)) then call extractDataContent(p, streamdat(i)%dtlimit) endif - p=> item(getElementsByTagname(streamnode, "stream_offset"), 0) + + p=> item(getElementsByTagname(streamnode, "offset"), 0) if(associated(p)) then call extractDataContent(p, streamdat(i)%offset) endif - p=> item(getElementsByTagname(streamnode, "stream_mesh_file"), 0) + + p=> item(getElementsByTagname(streamnode, "meshfile"), 0) if (associated(p)) then call extractDataContent(p, streamdat(i)%meshfile) else call shr_sys_abort("mesh file name must be provided") endif - p => item(getElementsByTagname(streamnode, "stream_vectors"), 0) + + p => item(getElementsByTagname(streamnode, "vectors"), 0) if (associated(p)) then call extractDataContent(p, streamdat(i)%stream_vectors) else call shr_sys_abort("stream vectors must be provided") endif - p => item(getElementsByTagname(streamnode, "stream_lev_dimname"), 0) + ! Determine name of vertical dimension + p => item(getElementsByTagname(streamnode, "lev_dimname"), 0) if (associated(p)) then call extractDataContent(p, streamdat(i)%lev_dimname) else call shr_sys_abort("stream vertical level dimension name must be provided") endif - p => item(getElementsByTagname(streamnode, "stream_data_files"), 0) + ! Determine input data files + p => item(getElementsByTagname(streamnode, "datafiles"), 0) if (.not. associated(p)) then call shr_sys_abort("stream data files must be provided") endif - filelist => getElementsByTagname(p,"file") streamdat(i)%nfiles = getLength(filelist) - allocate(streamdat(i)%file( streamdat(i)%nfiles)) do n=1, streamdat(i)%nfiles p => item(filelist, n-1) call extractDataContent(p, streamdat(i)%file(n)%name) enddo - ! Determine name of stream variables in file and model - p => item(getElementsByTagname(streamnode, "stream_data_variables"), 0) + ! Determine name(s) of stream variable(s) in file and model + p => item(getElementsByTagname(streamnode, "datavars"), 0) varlist => getElementsByTagname(p, "var") streamdat(i)%nvars = getLength(varlist) allocate(streamdat(i)%varlist(streamdat(i)%nvars)) @@ -290,8 +336,12 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu streamdat(i)%varlist(n)%nameinfile = tmpstr(1:index(tmpstr, " ")) streamdat(i)%varlist(n)%nameinmodel = tmpstr(index(trim(tmpstr), " ", .true.)+1:) enddo + enddo +#ifndef CPRPGI +! PGI compiler has an issue with this call (empty procedure) call destroy(Sdoc) +#endif endif ! allocate streamdat instance on all tasks From b1c89467897fce25fd53edca1e55691fa3b5859b Mon Sep 17 00:00:00 2001 From: BinLi-NOAA Date: Thu, 16 Dec 2021 08:52:10 -0500 Subject: [PATCH 03/28] Add Fortran code used by GFS v16 data mode (#40) --- datm/CMakeLists.txt | 1 + datm/atm_comp_nuopc.F90 | 25 +++- datm/datm_datamode_gfs_mod.F90 | 252 +++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+), 1 deletion(-) create mode 100644 datm/datm_datamode_gfs_mod.F90 diff --git a/datm/CMakeLists.txt b/datm/CMakeLists.txt index d96060ab2..86098c9fc 100644 --- a/datm/CMakeLists.txt +++ b/datm/CMakeLists.txt @@ -6,6 +6,7 @@ set(SRCFILES atm_comp_nuopc.F90 datm_datamode_jra_mod.F90 datm_datamode_gefs_mod.F90 datm_datamode_cfsr_mod.F90 + datm_datamode_gfs_mod.F90 datm_datamode_era5_mod.F90) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index ffb640454..8472b9cdf 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -81,6 +81,12 @@ module cdeps_datm_comp use datm_datamode_cfsr_mod , only : datm_datamode_cfsr_restart_write use datm_datamode_cfsr_mod , only : datm_datamode_cfsr_restart_read + use datm_datamode_gfs_mod , only : datm_datamode_gfs_advertise + use datm_datamode_gfs_mod , only : datm_datamode_gfs_init_pointers + use datm_datamode_gfs_mod , only : datm_datamode_gfs_advance + use datm_datamode_gfs_mod , only : datm_datamode_gfs_restart_write + use datm_datamode_gfs_mod , only : datm_datamode_gfs_restart_read + implicit none private ! except @@ -295,6 +301,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) trim(datamode) == 'CPLHIST' .or. & trim(datamode) == 'GEFS' .or. & trim(datamode) == 'CFSR' .or. & + trim(datamode) == 'GFS' .or. & trim(datamode) == 'ERA5') then else call shr_sys_abort(' ERROR illegal datm datamode = '//trim(datamode)) @@ -327,6 +334,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) case ('CFSR') call datm_datamode_cfsr_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('GFS') + call datm_datamode_gfs_advertise(exportState, fldsExport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end subroutine InitializeAdvertise @@ -448,7 +458,7 @@ subroutine ModelAdvance(gcomp, rc) type(ESMF_Time) :: nextTime type(ESMF_TimeInterval) :: timeStep real(r8) :: nextsw_cday - logical :: restart_write ! restart alarm is ringing + logical :: restart_write ! restart alarm is ringing integer :: next_ymd ! model date integer :: next_tod ! model sec into model date integer :: yr, mon, day ! year, month, day @@ -570,6 +580,9 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('CFSR') call datm_datamode_cfsr_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GFS') + call datm_datamode_gfs_init_pointers(exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Read restart if needed @@ -589,6 +602,8 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_gefs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) case('CFSR') call datm_datamode_cfsr_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) + case('GFS') + call datm_datamode_gfs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) end select end if @@ -643,6 +658,10 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_cfsr_advance(exportstate, masterproc, logunit, mpicom, target_ymd, & target_tod, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GFS') + call datm_datamode_gfs_advance(exportstate, masterproc, logunit, mpicom, target_ymd, & + target_tod, sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Write restarts if needed @@ -671,6 +690,10 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_cfsr_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GFS') + call datm_datamode_gfs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & + logunit, my_task, sdat) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end if diff --git a/datm/datm_datamode_gfs_mod.F90 b/datm/datm_datamode_gfs_mod.F90 new file mode 100644 index 000000000..f918c899e --- /dev/null +++ b/datm/datm_datamode_gfs_mod.F90 @@ -0,0 +1,252 @@ +module datm_datamode_gfs_mod + + use ESMF , only : ESMF_State, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp + use shr_mpi_mod , only : shr_mpi_max + use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_mod , only : dshr_restart_read, dshr_restart_write + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_gfs_advertise + public :: datm_datamode_gfs_init_pointers + public :: datm_datamode_gfs_advance + public :: datm_datamode_gfs_restart_write + public :: datm_datamode_gfs_restart_read + + ! export state data + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_u10m(:) => null() + real(r8), pointer :: Sa_v10m(:) => null() + real(r8), pointer :: Sa_t2m(:) => null() + real(r8), pointer :: Sa_q2m(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rain(:) => null() + real(r8), pointer :: Faxa_snow(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + + ! stream data + real(r8), pointer :: strm_mask(:) => null() + + real(r8) :: tbotmax ! units detector + real(r8) :: maskmax ! units detector + + real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg + real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 + + character(*), parameter :: nullstr = 'undefined' + character(*), parameter :: rpfile = 'rpointer.atm' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_gfs_advertise(exportState, fldsexport, & + flds_scalar_name, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Sa_u10m' ) + call dshr_fldList_add(fldsExport, 'Sa_v10m' ) + call dshr_fldList_add(fldsExport, 'Sa_t2m' ) + call dshr_fldList_add(fldsExport, 'Sa_q2m' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Faxa_rain' ) + call dshr_fldList_add(fldsExport, 'Faxa_snow' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_gfs_advertise + + !=============================================================================== + subroutine datm_datamode_gfs_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers for module level stream arrays + call shr_strdata_get_stream_pointer( sdat, 'Sa_mask' , strm_mask , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_t2m' , fldptr1=Sa_t2m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_q2m' , fldptr1=Sa_q2m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snow' , fldptr1=Faxa_snow, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_datamode_gfs_init_pointers + + !=============================================================================== + subroutine datm_datamode_gfs_advance(exportstate, masterproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: masterproc + integer , intent(in) :: logunit + integer , intent(in) :: mpicom + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n ! indices + integer :: lsize ! size of attr vect + real(r8) :: rtmp + real(r8) :: tbot, pbot + character(len=*), parameter :: subname='(datm_datamode_gfs_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(strm_mask) + + if (first_time) then + ! determine tbotmax (see below for use) + rtmp = maxval(Sa_tbot(:)) + call shr_mpi_max(rtmp, tbotmax, mpicom, 'datm_tbot', all=.true.) + if (masterproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax + + ! determine maskmax (see below for use) + rtmp = maxval(strm_mask(:)) + call shr_mpi_max(rtmp, maskmax, mpicom, 'datm_mask', all=.true.) + if (masterproc) write(logunit,*) trim(subname),' maskmax = ',maskmax + + ! reset first_time + first_time = .false. + end if + + do n = 1, lsize + !--- temperature --- + if (tbotmax < 50.0_r8) Sa_tbot(n) = Sa_tbot(n) + tkFrz + ! Limit very cold forcing to 180K + Sa_tbot(n) = max(180._r8, Sa_tbot(n)) + end do + + end subroutine datm_datamode_gfs_advance + + !=============================================================================== + subroutine datm_datamode_gfs_restart_write(case_name, inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + ! input/output variables + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + end subroutine datm_datamode_gfs_restart_write + + !=============================================================================== + subroutine datm_datamode_gfs_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) + + ! input/output arguments + character(len=*) , intent(inout) :: rest_filem + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) + + end subroutine datm_datamode_gfs_restart_read + +end module datm_datamode_gfs_mod From ad4282a002c6a13b7017ae00f6ec08b175617972 Mon Sep 17 00:00:00 2001 From: BinLi-NOAA Date: Thu, 20 Jan 2022 10:56:20 -0500 Subject: [PATCH 04/28] Update develop branch to include the most recent changes from ESCOMP/CDEPS (#42) --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- cime_config/buildlib | 218 ++++++++++++++++--------------- cime_config/buildlib_comps | 46 +++++++ cime_config/stream_cdeps.py | 8 +- datm/cime_config/buildlib | 2 +- dice/cime_config/buildlib | 2 +- dlnd/cime_config/buildlib | 2 +- docn/cime_config/buildlib | 2 +- drof/cime_config/buildlib | 2 +- dwav/cime_config/buildlib | 2 +- streams/dshr_strdata_mod.F90 | 2 +- streams/dshr_stream_mod.F90 | 1 + streams/dshr_tinterp_mod.F90 | 19 +-- 13 files changed, 174 insertions(+), 134 deletions(-) create mode 100755 cime_config/buildlib_comps diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index ec3a63d36..103a71c61 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ Contributors other than yourself, if any: -CMEPS Issues Fixed (include github issue #): +CDEPS Issues Fixed (include github issue #): Are there dependencies on other component PRs - [ ] CIME (list) diff --git a/cime_config/buildlib b/cime_config/buildlib index a2b794c17..27e3776eb 100755 --- a/cime_config/buildlib +++ b/cime_config/buildlib @@ -15,19 +15,51 @@ _LIBDIR = os.path.join(_CIMEROOT, "scripts", "lib") sys.path.append(_LIBDIR) from standard_script_setup import * -from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import run_cmd, symlink_force, expect from CIME.build import get_standard_cmake_args -from CIME.XML.machines import Machines -from CIME.XML.compilers import Compilers logger = logging.getLogger(__name__) -def buildlib(bldroot, libroot, case, compname=None): - print("HERE cwd is {}".format(os.getcwd())) - if bldroot.endswith("obj") and not compname: - compname = os.path.basename(os.path.abspath(os.path.join(bldroot,os.pardir))) +def parse_command_line(args, description): +############################################################################### + parser = argparse.ArgumentParser( + usage="""\n{0} [--debug] +OR +{0} --verbose +OR +{0} --help + +\033[1mEXAMPLES:\033[0m + \033[1;32m# Run \033[0m + > {0} +""" .format (os.path.basename(args[0])), + +description=description, + +formatter_class=argparse.ArgumentDefaultsHelpFormatter +) + + CIME.utils.setup_standard_logging_options(parser) + + parser.add_argument("buildroot", + help="build path root") + + parser.add_argument("installpath", + help="install path ") + + parser.add_argument("caseroot", nargs="?", default=os.getcwd(), + help="Case directory to build") + + args = CIME.utils.parse_args_and_handle_standard_logging_options(args, parser) + + return args.buildroot, args.installpath, args.caseroot + + +def buildlib(bldroot, libroot, case): + expect(not bldroot.endswith("obj"), + "It appears that the main CDEPS buildlib is being called for a specific component\n" + "(specific data model components should use buildlib_comps)") if case.get_value("DEBUG"): strdebug = "debug" @@ -42,88 +74,76 @@ def buildlib(bldroot, libroot, case, compname=None): sharedpath = os.path.join(case.get_value("COMPILER"),mpilib, strdebug, strthread, "nuopc") - exe_root = case.get_value("EXEROOT") - - if compname: - s, o, e = run_cmd("make d{}".format(compname), from_dir=bldroot, verbose=True) - libname = "lib{}.a".format(compname) - dlibname = "libd{}.a".format(compname) - dlibpath = os.path.join(bldroot, dlibname) - if os.path.exists(dlibpath): - symlink_force(os.path.join(bldroot,dlibname), os.path.join(libroot,libname)) - else: - expect(False, "ERROR in {} build {} {}".format(compname,o,e)) + logger.info("Running cmake for CDEPS") + srcpath = os.path.abspath(os.path.join(os.path.dirname(__file__),os.pardir)) + cmake_flags = get_standard_cmake_args(case, os.path.join(sharedpath,"cdeps"), shared_lib=True) + # base path of install to be completed by setting DESTDIR in make install + cmake_flags += " -DCMAKE_INSTALL_PREFIX:PATH=/" + cmake_flags += " -DLIBROOT={} ".format(libroot) + cmake_flags += " -DMPILIB={} ".format(mpilib) + cmake_flags += " -DPIO_C_LIBRARY={path}/lib -DPIO_C_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) + cmake_flags += " -DPIO_Fortran_LIBRARY={path}/lib -DPIO_Fortran_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) + cmake_flags += srcpath + all_src_files = list(all_files_under(srcpath, ignoredirs=[".git","cmake","test",".github","cime_config","fox"])) + # Search SourceMods path for CDEPS files. We only look in the data component directories for these, files in cdeps share + # directories should be added to one of the data component directories + srcmodsdir = os.path.join(case.get_value("CASEROOT"),"SourceMods") + all_files_in_srcmods = [] + for comp_class in case.get_values("COMP_CLASSES"): + if comp_class == "CPL": + continue + comp = case.get_value("COMP_{}".format(comp_class)) + cdeps_comp_name = "d"+comp_class.lower() + if comp == cdeps_comp_name: + all_files_in_srcmods.extend(list(all_files_under(os.path.join(srcmodsdir,"src."+cdeps_comp_name)))) + + basenames1 = [os.path.basename(f) for f in all_src_files] + basenames2 = [os.path.basename(f) for f in all_files_in_srcmods] + srcmods = list(set(basenames1).intersection(set(basenames2))) + if srcmods: + logger.info("Found SourceMods {}".format(srcmods)) + for i, v in enumerate(all_src_files): + for sfile in all_files_in_srcmods: + if os.path.basename(sfile) == os.path.basename(v): + all_src_files[i] = v.replace(os.path.dirname(v), os.path.dirname(sfile)) + logger.debug("all_src_files: {}".format(all_src_files)) + latest_src_file = max(all_src_files, key=os.path.getmtime) + + src_time = os.path.getmtime(latest_src_file) + if os.path.exists(os.path.join(bldroot,"CMakeFiles")): + bld_time = os.path.getmtime(os.path.join(bldroot,"CMakeFiles")) + else: + bld_time = src_time - 1 + + # if any file in src is newer than CmakeFiles in the build directory, rerun cmake + + if src_time > bld_time: + logger.info("cmake_flags {}".format(cmake_flags)) + s,o,e = run_cmd("cmake {} ".format(cmake_flags), from_dir=bldroot, verbose=True) + expect(not s,"ERROR from cmake output={}, error={}".format(o,e)) else: - logger.info("Running cmake for CDEPS") - srcpath = os.path.abspath(os.path.join(os.path.dirname(__file__),os.pardir)) - cmake_flags = get_standard_cmake_args(case, os.path.join(sharedpath,"cdeps"), shared_lib=True) - # base path of install to be completed by setting DESTDIR in make install - cmake_flags += " -DCMAKE_INSTALL_PREFIX:PATH=/" - cmake_flags += " -DLIBROOT={} ".format(libroot) - cmake_flags += " -DMPILIB={} ".format(mpilib) - cmake_flags += " -DPIO_C_LIBRARY={path}/lib -DPIO_C_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) - cmake_flags += " -DPIO_Fortran_LIBRARY={path}/lib -DPIO_Fortran_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) - cmake_flags += srcpath - all_src_files = list(all_files_under(srcpath, ignoredirs=[".git","cmake","test",".github","cime_config","fox"])) - # Search SourceMods path for CDEPS files. We only look in the data component directories for these, files in cdeps share - # directories should be added to one of the data component directories - srcmodsdir = os.path.join(case.get_value("CASEROOT"),"SourceMods") - all_files_in_srcmods = [] - for comp_class in case.get_values("COMP_CLASSES"): - if comp_class == "CPL": - continue - comp = case.get_value("COMP_{}".format(comp_class)) - cdeps_comp_name = "d"+comp_class.lower() - if comp == cdeps_comp_name: - all_files_in_srcmods.extend(list(all_files_under(os.path.join(srcmodsdir,"src."+cdeps_comp_name)))) - - basenames1 = [os.path.basename(f) for f in all_src_files] - basenames2 = [os.path.basename(f) for f in all_files_in_srcmods] - srcmods = list(set(basenames1).intersection(set(basenames2))) - if srcmods: - logger.info("Found SourceMods {}".format(srcmods)) - for i, v in enumerate(all_src_files): - for sfile in all_files_in_srcmods: - if os.path.basename(sfile) == os.path.basename(v): - all_src_files[i] = v.replace(os.path.dirname(v), os.path.dirname(sfile)) - logger.debug("all_src_files: {}".format(all_src_files)) - latest_src_file = max(all_src_files, key=os.path.getmtime) - - src_time = os.path.getmtime(latest_src_file) - if os.path.exists(os.path.join(bldroot,"CMakeFiles")): - bld_time = os.path.getmtime(os.path.join(bldroot,"CMakeFiles")) - else: - bld_time = src_time - 1 - - # if any file in src is newer than CmakeFiles in the build directory, rerun cmake - - if src_time > bld_time: - logger.info("cmake_flags {}".format(cmake_flags)) - s,o,e = run_cmd("cmake {} ".format(cmake_flags), from_dir=bldroot, verbose=True) - expect(not s,"ERROR from cmake output={}, error={}".format(o,e)) - else: - # The dwav_lib is the last file built in cdeps, wait for it to be built - dwav_lib = os.path.join(bldroot,"dwav","libdwav.a") - time_to_wait = 300 - time_counter = 0 - while not os.path.exists(dwav_lib): - time.sleep(1) - time_counter += 1 - if time_counter > time_to_wait: - break - expect(time_counter <= time_to_wait," Timeout waiting for {}".format(dwav_lib)) - - s,o,e = run_cmd("make install VERBOSE=1 DESTDIR={}".format(libroot), from_dir=bldroot, verbose=True) - expect(not s,"ERROR from make output={}, error={}".format(o,e)) - - # Link the CDEPS component directories to the location expected by cime - for comp in ("atm", "lnd", "ice", "ocn", "rof", "wav"): - compname = case.get_value("COMP_{}".format(comp.upper())) - comppath = os.path.join(case.get_value("EXEROOT"),comp,"obj") - if compname == "d"+comp: - if not os.path.islink(comppath): - os.rmdir(comppath) - symlink_force(os.path.join(bldroot,compname), comppath) + # The dwav_lib is the last file built in cdeps, wait for it to be built + dwav_lib = os.path.join(bldroot,"dwav","libdwav.a") + time_to_wait = 300 + time_counter = 0 + while not os.path.exists(dwav_lib): + time.sleep(1) + time_counter += 1 + if time_counter > time_to_wait: + break + expect(time_counter <= time_to_wait," Timeout waiting for {}".format(dwav_lib)) + + s,o,e = run_cmd("make install VERBOSE=1 DESTDIR={}".format(libroot), from_dir=bldroot, verbose=True) + expect(not s,"ERROR from make output={}, error={}".format(o,e)) + + # Link the CDEPS component directories to the location expected by cime + for comp in ("atm", "lnd", "ice", "ocn", "rof", "wav"): + compname = case.get_value("COMP_{}".format(comp.upper())) + comppath = os.path.join(case.get_value("EXEROOT"),comp,"obj") + if compname == "d"+comp: + if not os.path.islink(comppath): + os.rmdir(comppath) + symlink_force(os.path.join(bldroot,compname), comppath) def all_files_under(path, ignoredirs=[]): """Iterates through all files that are under the given path.""" @@ -132,28 +152,10 @@ def all_files_under(path, ignoredirs=[]): for filename in filenames: yield os.path.join(cur_path, filename) -def get_compiler_names(case): - machine=case.get_value("MACH") - machobj = Machines(machine=machine) - compobj = Compilers(machobj) - compiler = case.get_value("COMPILER") - if case.get_value("MPILIB") == 'mpi-serial': - ccomp = compobj.get_value("SCC",{"COMPILER":compiler,"MACH":machine}).strip() - cxxcomp = compobj.get_value("SCXX",{"COMPILER":compiler}).strip() - fcomp = compobj.get_value("SFC",{"COMPILER":compiler}).strip() - else: - ccomp = compobj.get_value("MPICC",{"COMPILER":compiler}).strip() - cxxcomp = compobj.get_value("MPICXX",{"COMPILER":compiler}).strip() - fcomp = compobj.get_value("MPIFC",{"COMPILER":compiler}).strip() - - return ccomp, cxxcomp, fcomp - - def _main_func(args): - caseroot, libroot, bldroot = parse_input(args) - print("HERE cwd is {} caseroot is {}".format(os.getcwd(), caseroot)) + bldroot, installpath, caseroot = parse_command_line(args, __doc__) with Case(caseroot) as case: - buildlib(bldroot, libroot, case) + buildlib(bldroot, installpath, case) if __name__ == "__main__": _main_func(sys.argv) diff --git a/cime_config/buildlib_comps b/cime_config/buildlib_comps new file mode 100755 index 000000000..7e640eb0d --- /dev/null +++ b/cime_config/buildlib_comps @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 + +""" +build cime component model library. This buildlib script is used by all CDEPS components. +""" + +import sys, os + +_CIMEROOT = os.environ.get("CIMEROOT") +if _CIMEROOT is None: + raise SystemExit("ERROR: must set CIMEROOT environment variable") +sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) + +_LIBDIR = os.path.join(_CIMEROOT, "scripts", "lib") +sys.path.append(_LIBDIR) + +from standard_script_setup import * +from CIME.buildlib import parse_input +from CIME.case import Case +from CIME.utils import run_cmd, symlink_force, expect + +logger = logging.getLogger(__name__) + +def buildlib(bldroot, libroot, case, compname=None): + if not compname: + expect(bldroot.endswith("obj"), + "It appears that buildlib_comps is being called for the main CDEPS build\n" + "(the main CDEPS build should use buildlib, not buildlib_comps)") + compname = os.path.basename(os.path.abspath(os.path.join(bldroot,os.pardir))) + + _, o, e = run_cmd("make d{}".format(compname), from_dir=bldroot, verbose=True) + libname = "lib{}.a".format(compname) + dlibname = "libd{}.a".format(compname) + dlibpath = os.path.join(bldroot, dlibname) + if os.path.exists(dlibpath): + symlink_force(os.path.join(bldroot,dlibname), os.path.join(libroot,libname)) + else: + expect(False, "ERROR in {} build {} {}".format(compname,o,e)) + +def _main_func(args): + caseroot, libroot, bldroot = parse_input(args) + with Case(caseroot) as case: + buildlib(bldroot, libroot, case) + +if __name__ == "__main__": + _main_func(sys.argv) diff --git a/cime_config/stream_cdeps.py b/cime_config/stream_cdeps.py index ae8364dad..1c05645ea 100644 --- a/cime_config/stream_cdeps.py +++ b/cime_config/stream_cdeps.py @@ -44,7 +44,7 @@ """ valid_values = {} -valid_values["mapalgo"] = ["bilinear", "nn", "redist", "mapconsd", "mapconf"] +valid_values["mapalgo"] = ["bilinear", "nn", "redist", "mapconsd", "mapconf", "none"] valid_values["tintalgo"] = ["lower", "upper", "nearest", "linear", "coszen"] valid_values["taxmode"] = ["cycle", "extend", "limit"] @@ -94,7 +94,7 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file break # endif # end while - index += 1 + index += 1 lines_input_new.append(line) #end while @@ -104,9 +104,9 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file expect(len(stream_mods) == 2, "input stream mod can only be of the form streamname:var=value(s)") stream,varmod = stream_mods - expect (stream in stream_names, + expect (stream in stream_names, "{} contains a streamname \'{}\' that is not part of valid streamnames {}". - format(user_mods_file,stream,stream_names)) + format(user_mods_file,stream,stream_names)) if stream not in stream_mod_dict: stream_mod_dict[stream] = {} # var=value and check the validity diff --git a/datm/cime_config/buildlib b/datm/cime_config/buildlib index 0559e0371..0c5e984ac 120000 --- a/datm/cime_config/buildlib +++ b/datm/cime_config/buildlib @@ -1 +1 @@ -../../cime_config/buildlib \ No newline at end of file +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/dice/cime_config/buildlib b/dice/cime_config/buildlib index 0559e0371..0c5e984ac 120000 --- a/dice/cime_config/buildlib +++ b/dice/cime_config/buildlib @@ -1 +1 @@ -../../cime_config/buildlib \ No newline at end of file +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/dlnd/cime_config/buildlib b/dlnd/cime_config/buildlib index 0559e0371..0c5e984ac 120000 --- a/dlnd/cime_config/buildlib +++ b/dlnd/cime_config/buildlib @@ -1 +1 @@ -../../cime_config/buildlib \ No newline at end of file +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/docn/cime_config/buildlib b/docn/cime_config/buildlib index 0559e0371..0c5e984ac 120000 --- a/docn/cime_config/buildlib +++ b/docn/cime_config/buildlib @@ -1 +1 @@ -../../cime_config/buildlib \ No newline at end of file +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/drof/cime_config/buildlib b/drof/cime_config/buildlib index 0559e0371..0c5e984ac 120000 --- a/drof/cime_config/buildlib +++ b/drof/cime_config/buildlib @@ -1 +1 @@ -../../cime_config/buildlib \ No newline at end of file +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/dwav/cime_config/buildlib b/dwav/cime_config/buildlib index 0559e0371..0c5e984ac 120000 --- a/dwav/cime_config/buildlib +++ b/dwav/cime_config/buildlib @@ -1 +1 @@ -../../cime_config/buildlib \ No newline at end of file +../../cime_config/buildlib_comps \ No newline at end of file diff --git a/streams/dshr_strdata_mod.F90 b/streams/dshr_strdata_mod.F90 index 772ecb35c..eddac413f 100644 --- a/streams/dshr_strdata_mod.F90 +++ b/streams/dshr_strdata_mod.F90 @@ -1261,7 +1261,7 @@ subroutine shr_strdata_readLBUB(sdat, ns, mDate, mSec, newData, istr, rc) call ESMF_TraceRegionExit(trim(istr)//'_setup') ! if model current date is outside of model lower or upper bound - find the stream bounds - if (rDateM < rDateLB .or. rDateM > rDateUB) then + if (rDateM < rDateLB .or. rDateM >= rDateUB) then call ESMF_TraceRegionEnter(trim(istr)//'_fbound') call shr_stream_findBounds(stream, mDate, mSec, sdat%masterproc, & sdat%pstrm(ns)%ymdLB, dDateLB, sdat%pstrm(ns)%todLB, n_lb, filename_lb, & diff --git a/streams/dshr_stream_mod.F90 b/streams/dshr_stream_mod.F90 index 349eb7a43..3d954dffa 100644 --- a/streams/dshr_stream_mod.F90 +++ b/streams/dshr_stream_mod.F90 @@ -698,6 +698,7 @@ subroutine shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, streamdat(i)%varlist(n)%nameinfile = strm_tmpstrings(n)(1:index(trim(strm_tmpstrings(n)), " ")) streamdat(i)%varlist(n)%nameinmodel = strm_tmpstrings(n)(index(trim(strm_tmpstrings(n)), " ", .true.)+1:) enddo + deallocate(strm_tmpstrings) else call shr_sys_abort("stream data variables must be provided") endif diff --git a/streams/dshr_tinterp_mod.F90 b/streams/dshr_tinterp_mod.F90 index 10fa7b847..064915f31 100644 --- a/streams/dshr_tinterp_mod.F90 +++ b/streams/dshr_tinterp_mod.F90 @@ -238,6 +238,11 @@ subroutine shr_tInterp_getAvgCosz(tavCosz, lon, lat, & do while( reday < reday2) ! mid-interval t-steps thru interval [LB,UB] + !--- get next cosz value for t-avg --- + call shr_tInterp_getCosz(cosz,lon,lat,ymd,tod,eccen,mvelpp,lambm0,obliqr,calendar) + n = n + ldt + tavCosz = tavCosz + cosz*real(ldt,r8) ! add to partial sum + !--- advance to next time in [LB,UB] --- ymd0 = ymd tod0 = tod @@ -245,20 +250,6 @@ subroutine shr_tInterp_getAvgCosz(tavCosz, lon, lat, & call shr_cal_advDateInt(ldt,'seconds',ymd0,tod0,ymd,tod,calendar) call shr_cal_timeSet(reday,ymd,tod,calendar) - if (reday > reday2) then - ymd = ymd2 - tod = tod2 - timeint = reday2-reday0 - call ESMF_TimeIntervalGet(timeint, s_i8=dtsec, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - ldt = int(dtsec, shr_kind_in) - endif - - !--- get next cosz value for t-avg --- - call shr_tInterp_getCosz(cosz,lon,lat,ymd,tod,eccen,mvelpp,lambm0,obliqr,calendar) - n = n + ldt - tavCosz = tavCosz + cosz*real(ldt,r8) ! add to partial sum - end do tavCosz = tavCosz/real(n,r8) ! form t-avg From 7e2dc6c367504d844446333504eb30fdf73c0534 Mon Sep 17 00:00:00 2001 From: "Bin.Li" Date: Fri, 18 Mar 2022 14:18:33 +0000 Subject: [PATCH 05/28] update datm/atm_comp_nuopc.F90 update datm/datm_datamode_gfs_mod.F90 --- datm/atm_comp_nuopc.F90 | 2 +- datm/datm_datamode_gfs_mod.F90 | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 7f82f12ef..c0b14c725 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -659,7 +659,7 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe target_tod, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case('GFS') - call datm_datamode_gfs_advance(exportstate, masterproc, logunit, mpicom, target_ymd, & + call datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & target_tod, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end select diff --git a/datm/datm_datamode_gfs_mod.F90 b/datm/datm_datamode_gfs_mod.F90 index f918c899e..79c2c36e8 100644 --- a/datm/datm_datamode_gfs_mod.F90 +++ b/datm/datm_datamode_gfs_mod.F90 @@ -165,11 +165,11 @@ subroutine datm_datamode_gfs_init_pointers(exportState, sdat, rc) end subroutine datm_datamode_gfs_init_pointers !=============================================================================== - subroutine datm_datamode_gfs_advance(exportstate, masterproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) + subroutine datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) ! input/output variables type(ESMF_State) , intent(inout) :: exportState - logical , intent(in) :: masterproc + logical , intent(in) :: mainproc integer , intent(in) :: logunit integer , intent(in) :: mpicom integer , intent(in) :: target_ymd @@ -194,12 +194,12 @@ subroutine datm_datamode_gfs_advance(exportstate, masterproc, logunit, mpicom, t ! determine tbotmax (see below for use) rtmp = maxval(Sa_tbot(:)) call shr_mpi_max(rtmp, tbotmax, mpicom, 'datm_tbot', all=.true.) - if (masterproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax + if (mainproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax ! determine maskmax (see below for use) rtmp = maxval(strm_mask(:)) call shr_mpi_max(rtmp, maskmax, mpicom, 'datm_mask', all=.true.) - if (masterproc) write(logunit,*) trim(subname),' maskmax = ',maskmax + if (mainproc) write(logunit,*) trim(subname),' maskmax = ',maskmax ! reset first_time first_time = .false. From c509d89ac97ce214077668b4a4e5c77952e8825e Mon Sep 17 00:00:00 2001 From: BinLi-NOAA Date: Tue, 26 Jul 2022 06:17:15 -0400 Subject: [PATCH 06/28] Update CDEPS to include the recent changes from ESCOMP/CDEPS (#47) --- .gitignore | 3 + cime_config/buildlib | 10 +- cime_config/buildlib_comps | 2 +- cime_config/stream_cdeps.py | 2 +- datm/atm_comp_nuopc.F90 | 12 +- datm/cime_config/buildnml | 2 +- datm/cime_config/config_component.xml | 16 +- datm/cime_config/namelist_definition_datm.xml | 24 +- datm/cime_config/stream_definition_datm.xml | 479 ++++++++++++++++-- datm/cime_config/user_nl_datm_streams | 6 +- datm/datm_datamode_clmncep_mod.F90 | 10 +- dice/cime_config/buildnml | 2 +- dlnd/cime_config/buildnml | 2 +- docn/cime_config/buildnml | 2 +- docn/ocn_comp_nuopc.F90 | 18 +- drof/cime_config/buildnml | 2 +- drof/cime_config/namelist_definition_drof.xml | 3 + drof/cime_config/stream_definition_drof.xml | 96 ++++ dshr/dshr_mod.F90 | 23 +- dwav/cime_config/buildnml | 2 +- streams/dshr_strdata_mod.F90 | 163 ++++-- streams/dshr_stream_mod.F90 | 200 +++++--- streams/dshr_tinterp_mod.F90 | 26 +- 23 files changed, 910 insertions(+), 195 deletions(-) diff --git a/.gitignore b/.gitignore index 259148fa1..34b286f3e 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ *.exe *.out *.app + +# ignore pycache +__pycache__ diff --git a/cime_config/buildlib b/cime_config/buildlib index 3d794cb83..a723fadfb 100755 --- a/cime_config/buildlib +++ b/cime_config/buildlib @@ -9,7 +9,7 @@ import sys, os, time _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) +sys.path.append(os.path.join(_CIMEROOT, "CIME", "Tools")) _LIBDIR = os.path.join(_CIMEROOT, "scripts", "lib") sys.path.append(_LIBDIR) @@ -82,8 +82,12 @@ def buildlib(bldroot, libroot, case): cmake_flags += " -DLIBROOT={} ".format(libroot) cmake_flags += " -DMPILIB={} ".format(mpilib) cmake_flags += " -DSRCROOT={} ".format(case.get_value("SRCROOT")) - cmake_flags += " -DPIO_C_LIBRARY={path}/lib -DPIO_C_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) - cmake_flags += " -DPIO_Fortran_LIBRARY={path}/lib -DPIO_Fortran_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) + if os.environ["PIO_LIBDIR"]: + cmake_flags += " -DPIO_C_LIBRARY={libdir} -DPIO_C_INCLUDE_DIR={incdir} ".format(libdir=os.environ["PIO_LIBDIR"], incdir=os.environ["PIO_INCDIR"]) + cmake_flags += " -DPIO_Fortran_LIBRARY={libdir} -DPIO_Fortran_INCLUDE_DIR={incdir} ".format(libdir=os.environ["PIO_LIBDIR"], incdir=os.environ["PIO_INCDIR"]) + else: + cmake_flags += " -DPIO_C_LIBRARY={path}/lib -DPIO_C_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) + cmake_flags += " -DPIO_Fortran_LIBRARY={path}/lib -DPIO_Fortran_INCLUDE_DIR={path}/include ".format(path=os.path.join(case.get_value("EXEROOT"),sharedpath)) cmake_flags += srcpath all_src_files = list(all_files_under(srcpath, ignoredirs=[".git","cmake","test",".github","cime_config","fox"])) # Search SourceMods path for CDEPS files. We only look in the data component directories for these, files in cdeps share diff --git a/cime_config/buildlib_comps b/cime_config/buildlib_comps index 7e640eb0d..1eba5bee6 100755 --- a/cime_config/buildlib_comps +++ b/cime_config/buildlib_comps @@ -9,7 +9,7 @@ import sys, os _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -sys.path.append(os.path.join(_CIMEROOT, "scripts", "Tools")) +sys.path.append(os.path.join(_CIMEROOT, "CIME", "Tools")) _LIBDIR = os.path.join(_CIMEROOT, "scripts", "lib") sys.path.append(_LIBDIR) diff --git a/cime_config/stream_cdeps.py b/cime_config/stream_cdeps.py index 1c05645ea..c989532e0 100644 --- a/cime_config/stream_cdeps.py +++ b/cime_config/stream_cdeps.py @@ -100,7 +100,7 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file for line in lines_input_new: # read in a single line in user_nl_xxx_streams and parse it if it is not a comment - stream_mods = [x.strip() for x in line.strip().split(":") if x] + stream_mods = [x.strip() for x in line.strip().split(":",maxsplit=1) if x] expect(len(stream_mods) == 2, "input stream mod can only be of the form streamname:var=value(s)") stream,varmod = stream_mods diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index c0b14c725..3a4921c46 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -137,6 +137,7 @@ module cdeps_datm_comp character(CL) :: restfilm = nullstr ! model restart file namelist integer :: nx_global ! global nx integer :: ny_global ! global ny + logical :: skip_restart_read = .false. ! true => skip restart read in continuation run ! linked lists type(fldList_type) , pointer :: fldsImport => null() @@ -233,7 +234,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) namelist / datm_nml / datamode, & model_meshfile, model_maskfile, & nx_global, ny_global, restfilm, iradsw, factorFn_data, factorFn_mesh, & - flds_presaero, flds_co2, flds_wiso, bias_correct, anomaly_forcing + flds_presaero, flds_co2, flds_wiso, bias_correct, anomaly_forcing, & + skip_restart_read rc = ESMF_SUCCESS @@ -274,6 +276,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call shr_mpi_bcast(flds_presaero , mpicom, 'flds_presaero') call shr_mpi_bcast(flds_co2 , mpicom, 'flds_co2') call shr_mpi_bcast(flds_wiso , mpicom, 'flds_wiso') + call shr_mpi_bcast(skip_restart_read , mpicom, 'skip_restart_read') ! write namelist input to standard out if (my_task == main_task) then @@ -290,6 +293,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F02)' flds_presaero = ',flds_presaero write(logunit,F02)' flds_co2 = ',flds_co2 write(logunit,F02)' flds_wiso = ',flds_wiso + write(logunit,F02)' skip_restart_read = ',skip_restart_read end if ! Validate sdat datamode @@ -413,7 +417,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! Initialize and update orbital values call dshr_orbital_init(gcomp, logunit, my_task == main_task, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_orbital_update(clock, logunit, my_task == main_task, & + call dshr_orbital_update(currTime, logunit, my_task == main_task, & orbEccen, orbObliqr, orbLambm0, orbMvelpp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -491,7 +495,7 @@ subroutine ModelAdvance(gcomp, rc) call shr_cal_ymd2date(yr, mon, day, next_ymd) ! Update the orbital values - call dshr_orbital_update(clock, logunit, my_task == main_task, & + call dshr_orbital_update(nextTime, logunit, my_task == main_task, & orbEccen, orbObliqr, orbLambm0, orbMvelpp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -586,7 +590,7 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe end select ! Read restart if needed - if (restart_read) then + if (restart_read .and. .not. skip_restart_read) then select case (trim(datamode)) case('CORE2_NYF','CORE2_IAF') call datm_datamode_core2_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) diff --git a/datm/cime_config/buildnml b/datm/cime_config/buildnml index 671fa7584..122db7cdc 100755 --- a/datm/cime_config/buildnml +++ b/datm/cime_config/buildnml @@ -15,7 +15,7 @@ _CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pard _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") sys.path.append(_LIBDIR) sys.path.append(_CDEPS_CONFIG) diff --git a/datm/cime_config/config_component.xml b/datm/cime_config/config_component.xml index 0e961df1a..c8ff2f3ec 100644 --- a/datm/cime_config/config_component.xml +++ b/datm/cime_config/config_component.xml @@ -10,7 +10,7 @@ This file may have atm desc entries. --> - Data driven ATM + Data driven ATM QIAN data set QIAN with water isotopes CRUNCEP data set @@ -23,6 +23,9 @@ COREv2 interannual forcing interannual JRA55 forcing interannual JRA55 forcing, v1.4, through 2018 + JRA55 Repeat Year Forcing v1.3 1984-1985 + JRA55 Repeat Year Forcing v1.3 1990-1991 + JRA55 Repeat Year Forcing v1.3 2003-2004 ERA5 interannual forcing @@ -292,6 +295,17 @@ ending year to loop data over + + logical + TRUE,FALSE + FALSE + run_component_datm + env_run.xml + If set to true, than datm restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + ========================================= DATM naming conventions in compset name diff --git a/datm/cime_config/namelist_definition_datm.xml b/datm/cime_config/namelist_definition_datm.xml index 22c70ae90..4a137b4f9 100644 --- a/datm/cime_config/namelist_definition_datm.xml +++ b/datm/cime_config/namelist_definition_datm.xml @@ -50,7 +50,16 @@ CORE2_IAF.GCGCS.PREC,CORE2_IAF.GISS.LWDN,CORE2_IAF.GISS.SWDN,CORE2_IAF.GISS.SWUP,CORE2_IAF.NCEP.DN10,CORE2_IAF.NCEP.Q_10,CORE2_IAF.NCEP.SLP_,CORE2_IAF.NCEP.T_10,CORE2_IAF.NCEP.U_10,CORE2_IAF.NCEP.V_10,CORE2_IAF.CORE2.ArcFactor - CORE_IAF_JRA_1p4_2018.GCGCS.PREC,CORE_IAF_JRA_1p4_2018.GISS.LWDN,CORE_IAF_JRA_1p4_2018.GISS.SWDN,CORE_IAF_JRA_1p4_2018.NCEP.Q_10,CORE_IAF_JRA_1p4_2018.NCEP.SLP_,CORE_IAF_JRA_1p4_2018.NCEP.T_10,CORE_IAF_JRA_1p4_2018.NCEP.U_10,CORE_IAF_JRA_1p4_2018.NCEP.V_10 + CORE_IAF_JRA_1p4_2018.GCGCS.PREC,CORE_IAF_JRA_1p4_2018.GISS.LWDN,CORE_IAF_JRA_1p4_2018.GISS.SWDN,CORE_IAF_JRA_1p4_2018.NCEP.Q_10,CORE_IAF_JRA_1p4_2018.NCEP.SLP_,CORE_IAF_JRA_1p4_2018.NCEP.T_10,CORE_IAF_JRA_1p4_2018.NCEP.U_10,CORE_IAF_JRA_1p4_2018.NCEP.V_10 + + + CORE_RYF8485_JRA.GISS.LWDN,CORE_RYF8485_JRA.GISS.SWDN,CORE_RYF8485_JRA.GCGCS,CORE_RYF8485_JRA.NCEP + + + CORE_RYF9091_JRA.GISS.LWDN,CORE_RYF9091_JRA.GISS.SWDN,CORE_RYF9091_JRA.GCGCS,CORE_RYF9091_JRA.NCEP + + + CORE_RYF0304_JRA.GISS.LWDN,CORE_RYF0304_JRA.GISS.SWDN,CORE_RYF0304_JRA.GCGCS,CORE_RYF0304_JRA.NCEP CORE_IAF_JRA.PREC,CORE_IAF_JRA.LWDN,CORE_IAF_JRA.SWDN,CORE_IAF_JRA.Q_10,CORE_IAF_JRA.SLP_,CORE_IAF_JRA.T_10,CORE_IAF_JRA.U_10,CORE_IAF_JRA.V_10 @@ -316,4 +325,17 @@ + + logical + datm + datm_nml + + If set to true, than datm restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DATM_SKIP_RESTART_READ + + + diff --git a/datm/cime_config/stream_definition_datm.xml b/datm/cime_config/stream_definition_datm.xml index af7928349..de7974ede 100644 --- a/datm/cime_config/stream_definition_datm.xml +++ b/datm/cime_config/stream_definition_datm.xml @@ -37,6 +37,9 @@ CORE2_IAF = CORE2 intra-annual year forcing (for forcing POP and CICE) CORE_IAF_JRA = JRA55 intra-annual year forcing (for forcing POP and CICE) CORE_IAF_JRA_1p4_2018 = JRA55 intra-annual year forcing, v1.4, through 2018 (for forcing POP and CICE) + CORE_RYF8485_JRA = JRA55 repeat year forcing, v1.3, 1984-1985 (for forcing POP and CICE) + CORE_RYF9091_JRA = JRA55 repeat year forcing, v1.3, 1990-1991 (for forcing POP and CICE) + CORE_RYF0304_JRA = JRA55 repeat year forcing, v1.3, 2003-2004 (for forcing POP and CICE) ERA5 = ERA5 intra-annual year forcing CPLHIST = Streams for lnd or ocn/ice forcing used for spinup @@ -1291,7 +1294,7 @@ bilinear - u:v + null 1 1 1 @@ -1322,7 +1325,7 @@ bilinear - u:v + null 1 1 1 @@ -1358,7 +1361,7 @@ bilinear - u:v + Sa_u:Sa_v 1 1 1 @@ -1393,7 +1396,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1424,7 +1427,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1455,7 +1458,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1486,7 +1489,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1517,7 +1520,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1548,7 +1551,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1579,7 +1582,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1610,7 +1613,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1641,7 +1644,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1672,7 +1675,7 @@ bilinear - u:v + null 1 2010 2011 @@ -1704,7 +1707,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1736,7 +1739,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1768,7 +1771,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1800,7 +1803,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1834,7 +1837,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1868,7 +1871,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1902,7 +1905,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1936,7 +1939,7 @@ bilinear - u:v + null 1 1948 2009 @@ -1970,7 +1973,7 @@ bilinear - u:v + null 1 1948 2009 @@ -2004,7 +2007,7 @@ bilinear - u:v + null 1 1948 2009 @@ -2035,7 +2038,7 @@ bilinear - u:v + null 1 1948 2009 @@ -2078,7 +2081,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2109,7 +2112,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2140,7 +2143,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2171,7 +2174,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2202,7 +2205,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2233,7 +2236,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2264,7 +2267,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2295,7 +2298,7 @@ bilinear - u:v + null 1 1958 2018 @@ -2312,6 +2315,402 @@ single + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.radiation.lwdn.TL319.180404.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.radiation.swdn.TL319.180404.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.prec.TL319.180404.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_8485.JRA.v1.3.states.TL319.180404.nc + + + u_10 Sa_u + v_10 Sa_v + t_10 Sa_tbot + q_10 Sa_shum + slp Sa_pslv + + null + + bilinear + + Sa_u:Sa_v + 1 + 1984 + 1984 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.radiation.lwdn.TL319.180404.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.radiation.swdn.TL319.180404.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.prec.TL319.180404.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_9091.JRA.v1.3.states.TL319.180404.nc + + + u_10 Sa_u + v_10 Sa_v + t_10 Sa_tbot + q_10 Sa_shum + slp Sa_pslv + + null + + bilinear + + Sa_u:Sa_v + 1 + 1990 + 1990 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.radiation.lwdn.TL319.180404.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.radiation.swdn.TL319.180404.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.prec.TL319.180404.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_0304.JRA.v1.3.states.TL319.180404.nc + + + u_10 Sa_u + v_10 Sa_v + t_10 Sa_tbot + q_10 Sa_shum + slp Sa_pslv + + null + + bilinear + + Sa_u:Sa_v + 1 + 2003 + 2003 + 0 + + linear + + + cycle + + + 1.5 + + single + + @@ -2330,7 +2729,7 @@ bilinear - u:v + null 1 1958 2016 @@ -2361,7 +2760,7 @@ bilinear - u:v + null 1 1958 2016 @@ -2392,7 +2791,7 @@ bilinear - u:v + null 1 1958 2016 @@ -2423,7 +2822,7 @@ bilinear - u:v + null 1 1958 2016 @@ -2454,7 +2853,7 @@ bilinear - u:v + null 1 1958 2016 @@ -2485,7 +2884,7 @@ bilinear - u:v + null 1 1958 2016 @@ -2516,7 +2915,7 @@ bilinear - u:v + null 1 1958 2016 @@ -2547,7 +2946,7 @@ bilinear - u:v + null 1 1958 2016 diff --git a/datm/cime_config/user_nl_datm_streams b/datm/cime_config/user_nl_datm_streams index 856ee8944..b01a4fe80 100644 --- a/datm/cime_config/user_nl_datm_streams +++ b/datm/cime_config/user_nl_datm_streams @@ -1,8 +1,8 @@ !------------------------------------------------------------------------ ! This file is used to modify datm.streams.xml generated in $RUNDIR ! Entries should have the form -! :<= new stream_value> -! The following are accepted values for an assume streamname of foo +! := (NO Quotes!!!) +! The following are accepted values for a stream named foo ! foo:meshfile = character string ! foo:datafiles = comma separated string of full pathnames (e.g. file1,file2,file3...) ! foo:datavars = comma separated string of field pairs (e.g. foo foobar,foo2 foobar2...) @@ -14,7 +14,7 @@ ! foo:year_first = integer ! foo:year_last = integer ! foo:year_align = integer -! foo:vectors = one of [none,u:v] +! foo:vectors = null or the names of the vector fields in the model (i.e. Sa_u:Sa_v) ! foo:lev_dimname: = one of [null,name of level dimenion name] ! foo:offset = integer ! As an example: diff --git a/datm/datm_datamode_clmncep_mod.F90 b/datm/datm_datamode_clmncep_mod.F90 index 26d881cc1..4ae0b205e 100644 --- a/datm/datm_datamode_clmncep_mod.F90 +++ b/datm/datm_datamode_clmncep_mod.F90 @@ -208,6 +208,8 @@ subroutine datm_datamode_clmncep_init_pointers(importState, exportState, sdat, r if (ChkErr(rc,__LINE__,u_FILE_u)) return call shr_strdata_get_stream_pointer( sdat, 'Sa_rh' , strm_rh , rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer( sdat, 'Sa_z' , strm_z , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdndf' , strm_swdndf, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call shr_strdata_get_stream_pointer( sdat, 'Faxa_swdndr' , strm_swdndr, rc) @@ -384,7 +386,13 @@ subroutine datm_datamode_clmncep_advance(mainproc, logunit, mpicom, rc) Sa_ptem(n) = Sa_tbot(n) !--- pressure --- - if (.not. associated(strm_pbot)) Sa_pbot(n) = pstd + if (.not. associated(strm_pbot)) then + Sa_pbot(n) = pstd + else if (Sa_pbot(n) == 0._r8) then + ! This happens if you are using points over ocean where the mask is 0 + Sa_pbot(n) = pstd + end if + Sa_pslv(n) = Sa_pbot(n) !--- u, v wind velocity --- diff --git a/dice/cime_config/buildnml b/dice/cime_config/buildnml index b6ae7b56b..c59539b56 100755 --- a/dice/cime_config/buildnml +++ b/dice/cime_config/buildnml @@ -15,7 +15,7 @@ _CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pard _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") sys.path.append(_LIBDIR) sys.path.append(_CDEPS_CONFIG) diff --git a/dlnd/cime_config/buildnml b/dlnd/cime_config/buildnml index 9c93d82d2..058c01339 100755 --- a/dlnd/cime_config/buildnml +++ b/dlnd/cime_config/buildnml @@ -15,7 +15,7 @@ _CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pard _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") sys.path.append(_LIBDIR) sys.path.append(_CDEPS_CONFIG) diff --git a/docn/cime_config/buildnml b/docn/cime_config/buildnml index 3096a2ce3..546e43acc 100755 --- a/docn/cime_config/buildnml +++ b/docn/cime_config/buildnml @@ -15,7 +15,7 @@ _CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pard _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") sys.path.append(_LIBDIR) sys.path.append(_CDEPS_CONFIG) diff --git a/docn/ocn_comp_nuopc.F90 b/docn/ocn_comp_nuopc.F90 index 4e06b3ae2..964beabeb 100644 --- a/docn/ocn_comp_nuopc.F90 +++ b/docn/ocn_comp_nuopc.F90 @@ -17,7 +17,7 @@ module cdeps_docn_comp use ESMF , only : ESMF_StateGet, operator(+), ESMF_AlarmRingerOff, ESMF_LogWrite use ESMF , only : ESMF_Field, ESMF_FieldGet, ESMF_VmLogMemInfo use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize - use NUOPC , only : NUOPC_Advertise, NUOPC_CompAttributeGet + use NUOPC , only : NUOPC_Advertise, NUOPC_CompAttributeGet, NUOPC_CompAttributeSet use NUOPC_Model , only : model_routine_SS => SetServices use NUOPC_Model , only : model_label_Advance => label_Advance use NUOPC_Model , only : model_label_SetRunClock => label_SetRunClock @@ -302,6 +302,9 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) integer :: fieldcount real(r8), pointer :: fldptr(:) integer :: n + integer :: imask + real(r8) :: rmask + character(CL) :: cvalue character(len=*), parameter :: subname=trim(module_name)//':(InitializeRealize) ' !------------------------------------------------------------------------------- @@ -309,6 +312,19 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) call ESMF_VMLogMemInfo("Entering "//trim(subname)) ! Initialize model mesh, restart flag, logunit, model_mask and model_frac call ESMF_TraceRegionEnter('docn_strdata_init') + + ! If aquaplanet overwrite model mask and model frac to 1 + if (aquaplanet) then + imask = 1 + write(cvalue,*) imask + call NUOPC_CompAttributeSet(gcomp, name='scol_ocnmask', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + rmask = 1._r8 + write(cvalue,*) rmask + call NUOPC_CompAttributeSet(gcomp, name='scol_ocnfrac', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + call dshr_mesh_init(gcomp, sdat, nullstr, logunit, 'OCN', nx_global, ny_global, & model_meshfile, model_maskfile, model_mesh, model_mask, model_frac, restart_read, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/drof/cime_config/buildnml b/drof/cime_config/buildnml index f33982011..c3bd3a482 100755 --- a/drof/cime_config/buildnml +++ b/drof/cime_config/buildnml @@ -15,7 +15,7 @@ _CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pard _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") sys.path.append(_LIBDIR) sys.path.append(_CDEPS_CONFIG) diff --git a/drof/cime_config/namelist_definition_drof.xml b/drof/cime_config/namelist_definition_drof.xml index 1428a9338..ead6e9209 100644 --- a/drof/cime_config/namelist_definition_drof.xml +++ b/drof/cime_config/namelist_definition_drof.xml @@ -21,6 +21,9 @@ rof.diatren_iaf_ais55_rx1 rof.iaf_jra_1p4_2018 rof.iaf_jra + rof.ryf8485_jra + rof.ryf9091_jra + rof.ryf0304_jra diff --git a/drof/cime_config/stream_definition_drof.xml b/drof/cime_config/stream_definition_drof.xml index 8c3362a9d..d14e5cbbe 100644 --- a/drof/cime_config/stream_definition_drof.xml +++ b/drof/cime_config/stream_definition_drof.xml @@ -475,6 +475,102 @@ single + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/JRA.v1.4.runoff.1958_ESMFmesh_cdf5_20201020.nc + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/RAF_8485.JRA.v1.3.runoff.180404.nc + + + rofl Forr_rofl + rofi Forr_rofi + + null + + bilinear + + null + 1 + 1984 + 1984 + 0 + + upper + + + cycle + + + 3.0 + + single + + + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/JRA.v1.4.runoff.1958_ESMFmesh_cdf5_20201020.nc + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/RAF_9091.JRA.v1.3.runoff.180404.nc + + + rofl Forr_rofl + rofi Forr_rofi + + null + + bilinear + + null + 1 + 1990 + 1990 + 0 + + upper + + + cycle + + + 3.0 + + single + + + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/JRA.v1.4.runoff.1958_ESMFmesh_cdf5_20201020.nc + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/RAF_0304.JRA.v1.3.runoff.180404.nc + + + rofl Forr_rofl + rofi Forr_rofi + + null + + bilinear + + null + 1 + 2003 + 2003 + 0 + + upper + + + cycle + + + 3.0 + + single + + $ROF_DOMAIN_MESH diff --git a/dshr/dshr_mod.F90 b/dshr/dshr_mod.F90 index d0e4774f8..87d1c4896 100644 --- a/dshr/dshr_mod.F90 +++ b/dshr/dshr_mod.F90 @@ -107,7 +107,9 @@ end subroutine dshr_model_initphase !=============================================================================== subroutine dshr_init(gcomp, compname, sdat, mpicom, my_task, inst_index, inst_suffix, & flds_scalar_name, flds_scalar_num, flds_scalar_index_nx, flds_scalar_index_ny, logunit, rc) - +#ifdef CESMCOUPLED + use nuopc_shr_methods, only : set_component_logging +#endif ! input/output variables type(ESMF_GridComp) :: gcomp character(len=*) , intent(in) :: compname !e.g. ATM, OCN, ... @@ -126,6 +128,7 @@ subroutine dshr_init(gcomp, compname, sdat, mpicom, my_task, inst_index, inst_su ! local variables type(ESMF_VM) :: vm logical :: isPresent, isSet + integer :: slogunit character(len=CX) :: cvalue character(len=CX) :: logmsg character(len=CX) :: diro @@ -191,15 +194,18 @@ subroutine dshr_init(gcomp, compname, sdat, mpicom, my_task, inst_index, inst_su else logfile = "d"//shr_string_toLower(compname)//".log" endif - +#ifdef CESMCOUPLED + call set_component_logging(gcomp, my_task == main_task, logunit, slogunit, rc=rc) +#else if (my_task == main_task) then call ESMF_LogWrite(trim(subname)//' : output logging is written to '//trim(diro)//"/"//trim(logfile), ESMF_LOGMSG_INFO) if (ChkErr(rc,__LINE__,u_FILE_u)) return open(newunit=logunit, file=trim(diro)//"/"//trim(logfile)) + else logUnit = 6 endif - +#endif ! set component instance and suffix call NUOPC_CompAttributeGet(gcomp, name="inst_suffix", isPresent=isPresent, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return @@ -1038,6 +1044,7 @@ subroutine dshr_restart_write(rpfile, case_name, model_name, inst_suffix, ymd, t integer :: dimid(1) type(var_desc_t) :: varid type(io_desc_t) :: pio_iodesc + integer :: oldmode integer :: rcode character(*), parameter :: F00 = "('(dshr_restart_write) ',2a,2(i0,2x))" !------------------------------------------------------------------------------- @@ -1058,6 +1065,7 @@ subroutine dshr_restart_write(rpfile, case_name, model_name, inst_suffix, ymd, t ! write data model restart data rcode = pio_createfile(sdat%pio_subsystem, pioid, sdat%io_type, trim(rest_file_model), pio_clobber) + rcode = pio_set_fill(pioid, PIO_FILL, oldmode) rcode = pio_put_att(pioid, pio_global, "version", "nuopc_data_models_v0") if (present(fld) .and. present(fldname)) then rcode = pio_def_dim(pioid, 'gsize', sdat%model_gsize, dimid(1)) @@ -1298,14 +1306,14 @@ subroutine dshr_orbital_init(gcomp, logunit, maintask, rc) end subroutine dshr_orbital_init !=============================================================================== - subroutine dshr_orbital_update(clock, logunit, maintask, eccen, obliqr, lambm0, mvelpp, rc) + subroutine dshr_orbital_update(Time, logunit, maintask, eccen, obliqr, lambm0, mvelpp, rc) !---------------------------------------------------------- ! Update orbital settings !---------------------------------------------------------- ! input/output variables - type(ESMF_Clock) , intent(in) :: clock + type(ESMF_Time) , intent(in) :: Time integer , intent(in) :: logunit logical , intent(in) :: maintask real(R8) , intent(inout) :: eccen ! orbital eccentricity @@ -1315,7 +1323,6 @@ subroutine dshr_orbital_update(clock, logunit, maintask, eccen, obliqr, lambm0, integer , intent(out) :: rc ! output error ! local variables - type(ESMF_Time) :: CurrTime ! current time integer :: year ! model year at current time integer :: orb_year ! orbital year for current orbital computation character(len=CL) :: msgstr ! temporary @@ -1325,9 +1332,7 @@ subroutine dshr_orbital_update(clock, logunit, maintask, eccen, obliqr, lambm0, !------------------------------------------- if (trim(orb_mode) == trim(orb_variable_year)) then - call ESMF_ClockGet(clock, CurrTime=CurrTime, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_TimeGet(CurrTime, yy=year, rc=rc) + call ESMF_TimeGet(Time, yy=year, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return orb_year = orb_iyear + (year - orb_iyear_align) lprint = maintask diff --git a/dwav/cime_config/buildnml b/dwav/cime_config/buildnml index 4c53dc646..f1a3e4a60 100755 --- a/dwav/cime_config/buildnml +++ b/dwav/cime_config/buildnml @@ -14,7 +14,7 @@ _CDEPS_CONFIG = os.path.join(os.path.dirname(os.path.abspath(__file__)), os.pard _CIMEROOT = os.environ.get("CIMEROOT") if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "Tools") +_LIBDIR = os.path.join(_CIMEROOT, "CIME", "Tools") sys.path.append(_LIBDIR) sys.path.append(_CDEPS_CONFIG) diff --git a/streams/dshr_strdata_mod.F90 b/streams/dshr_strdata_mod.F90 index d457dc8a8..9bae5d5c6 100644 --- a/streams/dshr_strdata_mod.F90 +++ b/streams/dshr_strdata_mod.F90 @@ -17,7 +17,7 @@ module dshr_strdata_mod use ESMF , only : ESMF_REGRIDMETHOD_CONSERVE, ESMF_NORMTYPE_FRACAREA, ESMF_NORMTYPE_DSTAREA use ESMF , only : ESMF_ClockGet, operator(-), operator(==), ESMF_CALKIND_NOLEAP use ESMF , only : ESMF_FieldReGridStore, ESMF_FieldRedistStore, ESMF_UNMAPPEDACTION_IGNORE - use ESMF , only : ESMF_TERMORDER_SRCSEQ, ESMF_FieldRegrid, ESMF_FieldFill + use ESMF , only : ESMF_TERMORDER_SRCSEQ, ESMF_FieldRegrid, ESMF_FieldFill, ESMF_FieldIsCreated use ESMF , only : ESMF_REGION_TOTAL, ESMF_FieldGet, ESMF_TraceRegionExit, ESMF_TraceRegionEnter use ESMF , only : ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_RC_ARG_VALUE use shr_kind_mod , only : r8=>shr_kind_r8, r4=>shr_kind_r4, i2=>shr_kind_I2 @@ -97,11 +97,9 @@ module dshr_strdata_mod integer :: stream_lb ! index of the Lowerbound (LB) in fldlist_stream integer :: stream_ub ! index of the Upperbound (UB) in fldlist_stream type(ESMF_Field) :: field_stream ! a field on the stream data domain - type(ESMF_Field) :: stream_vector ! a vector field on the stream data domain + type(ESMF_Field) :: field_stream_vector ! a vector field on the stream data domain type(ESMF_FieldBundle), allocatable :: fldbun_data(:) ! stream field bundle interpolated to model grid spatially type(ESMF_FieldBundle) :: fldbun_model ! stream n field bundle interpolated to model grid and time - integer :: ucomp = -1 ! index of vector u in stream - integer :: vcomp = -1 ! index of vector v in stream integer :: ymdLB = -1 ! stream ymd lower bound integer :: todLB = -1 ! stream tod lower bound integer :: ymdUB = -1 ! stream ymd upper bound @@ -114,7 +112,6 @@ module dshr_strdata_mod type shr_strdata_type type(shr_strdata_perstream), allocatable :: pstrm(:) ! stream info type(shr_stream_streamType), pointer :: stream(:)=> null() ! stream datatype - integer :: nvectors ! number of vectors logical :: mainproc integer :: logunit ! stdout unit integer :: io_type ! pio info @@ -398,7 +395,7 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) integer :: nvars integer :: i, stream_nlev, index integer, allocatable :: mask(:) - character(CL) :: stream_vectors + character(CL) :: stream_vector_names character(len=*), parameter :: subname='(shr_sdat_init)' ! ---------------------------------------------- @@ -428,7 +425,7 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) end if endif ! - ! We do not yet have mask information, but we are required to set it here and change it + ! We do not yet have mask information, but we are required to set it here and change it ! later. ! if(filename /= 'none') then @@ -450,15 +447,19 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) call shr_stream_getStreamFieldList(sdat%stream(ns), sdat%pstrm(ns)%fldlist_stream) ! Create field bundles on model mesh - if(sdat%stream(ns)%readmode=='single') then + if (sdat%stream(ns)%readmode=='single') then sdat%pstrm(ns)%stream_lb = 1 sdat%pstrm(ns)%stream_ub = 2 allocate(sdat%pstrm(ns)%fldbun_data(2)) + if (mainproc) then + write(sdat%logunit,'(a,i8)') trim(subname)//" Creating field bundle array fldbun_data of size 2 for stream ",& + ns + end if else if(sdat%stream(ns)%readmode=='full_file') then ! TODO: add this in endif - ! create spatially interpolated (but not time interpolated) field bundle - fldbun_data array + ! Create spatially interpolated (but not time interpolated) field bundle - fldbun_data array do i=1,size(sdat%pstrm(ns)%fldbun_data) sdat%pstrm(ns)%fldbun_data(i) = ESMF_FieldBundleCreate(rc=rc) ! stream mesh enddo @@ -476,6 +477,12 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) end if call ESMF_FieldBundleAdd(sdat%pstrm(ns)%fldbun_data(i), (/lfield/), rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return + if (mainproc) then + if (i == 1) then + write(sdat%logunit,'(a,i8)') " adding field "//trim(sdat%pstrm(ns)%fldlist_model(nfld))//& + " to fldbun_data for stream ",ns + end if + end if enddo end do @@ -596,30 +603,34 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) do ns = 1,shr_strdata_get_stream_count(sdat) stream_mesh => sdat%pstrm(ns)%stream_mesh stream_nlev = sdat%pstrm(ns)%stream_nlev - stream_vectors = trim(sdat%stream(ns)%stream_vectors) + stream_vector_names = trim(sdat%stream(ns)%stream_vectors) ! check that vector field list is a valid colon delimited string - if (trim(stream_vectors) /= 'null') then - ! check that for now u and v are only for single leve fields + if (trim(stream_vector_names) /= 'null') then + ! check that for now u and v are only for single level fields if (stream_nlev > 1) then ! TODO: add support for u and v for multi level fields call shr_sys_abort(subname//': vector fields are not currently supported for multi-level fields') end if ! check that stream vector names are valid - if (.not. shr_string_listIsValid(stream_vectors)) then - write(sdat%logunit,*) trim(subname),' vec fldlist invalid m=',m,trim(stream_vectors) - call shr_sys_abort(subname//': vec fldlist invalid:'//trim(stream_vectors)) + if (.not. shr_string_listIsValid(stream_vector_names)) then + write(sdat%logunit,*) trim(subname),' vec fldlist invalid m=',m,trim(stream_vector_names) + call shr_sys_abort(subname//': vec fldlist invalid:'//trim(stream_vector_names)) endif ! check that only 2 fields are contained for any vector pairing - if (shr_string_listGetNum(stream_vectors) /= 2) then - write(sdat%logunit,*) trim(subname),' vec fldlist ne 2 m=',m,trim(stream_vectors) - call shr_sys_abort(subname//': vec fldlist ne 2:'//trim(stream_vectors)) + if (shr_string_listGetNum(stream_vector_names) /= 2) then + write(sdat%logunit,*) trim(subname),' vec fldlist ne 2 m=',m,trim(stream_vector_names) + call shr_sys_abort(subname//': vec fldlist ne 2:'//trim(stream_vector_names)) endif ! create stream vector field - sdat%pstrm(ns)%stream_vector = ESMF_FieldCreate(stream_mesh, & + sdat%pstrm(ns)%field_stream_vector = ESMF_FieldCreate(stream_mesh, & ESMF_TYPEKIND_r8, name='stream_vector', meshloc=ESMF_MESHLOC_ELEMENT, & ungriddedLbound=(/1/), ungriddedUbound=(/2/), gridToFieldMap=(/2/), rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return + if (mainproc) then + write(sdat%logunit,'(a,i8)') "creating ESMF stream vector field with names" //& + trim(stream_vector_names)//" for stream ",ns + end if end if enddo @@ -816,10 +827,9 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) integer ,intent(out) :: rc ! local variables - integer :: ns ! stream index integer :: nf ! field index - integer :: i,lev ! generic indices + integer :: i,lev,n ! generic indices logical , allocatable :: newData(:) integer , allocatable :: ymdmod(:) ! modified model dates to handle Feb 29 real(r8), allocatable :: coszen(:) ! cosine of zenith angle @@ -998,8 +1008,15 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) ! get coszen call ESMF_TraceRegionEnter(trim(lstr)//trim(timname)//'_coszenC') call shr_tInterp_getCosz(coszen, sdat%model_lon, sdat%model_lat, ymdmod(ns), todmod, & - sdat%eccen, sdat%mvelpp, sdat%lambm0, sdat%obliqr, sdat%stream(ns)%calendar) + sdat%eccen, sdat%mvelpp, sdat%lambm0, sdat%obliqr, sdat%stream(ns)%calendar, & + sdat%mainproc, sdat%logunit) call ESMF_TraceRegionExit(trim(lstr)//trim(timname)//'_coszenC') + if (debug > 0 .and. sdat%mainproc) then + do n = 1,size(coszen) + write(sdat%logunit,'(a,i4,2x,2(i18,2x),i8,d20.10)')' stream,ymdmod,todmod,n,coszen= ',& + ns, ymd, tod, n, coszen(n) + end do + end if ! get avg cosz factor if (newdata(ns)) then @@ -1011,8 +1028,15 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) call shr_tInterp_getAvgCosz(sdat%tavCoszen, sdat%model_lon, sdat%model_lat, & sdat%pstrm(ns)%ymdLB, sdat%pstrm(ns)%todLB, sdat%pstrm(ns)%ymdUB, sdat%pstrm(ns)%todUB, & sdat%eccen, sdat%mvelpp, sdat%lambm0, sdat%obliqr, sdat%modeldt, & - sdat%stream(ns)%calendar, rc=rc) + sdat%stream(ns)%calendar, sdat%mainproc, sdat%logunit, rc=rc) call ESMF_TraceRegionExit(trim(lstr)//trim(timname)//'_coszenN') + if (debug > 0 .and. sdat%mainproc) then + do n = 1,size(coszen) + write(sdat%logunit,'(a,i4,2x,4(i18,2x),i8,d20.10)')' stream,lbymd,lbsec,ubymd,ubsec,newdata,n,tavgCoszen= ',& + ns, sdat%pstrm(ns)%ymdLB, sdat%pstrm(ns)%todLB, sdat%pstrm(ns)%ymdUB, sdat%pstrm(ns)%todUB, & + n, sdat%tavCoszen(n) + end do + end if endif ! compute time interperpolate value - LB data normalized with this factor: cosz/tavCosz @@ -1064,7 +1088,8 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) algo=trim(sdat%stream(ns)%tinterpalgo), rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return if (debug > 0 .and. sdat%mainproc) then - write(sdat%logunit,F01) trim(subname),' interp = ',ns,flb,fub + write(sdat%logunit,'(a,i4,2(f10.5,2x))') & + trim(subname)//' non-cosz-interp stream, flb, fub= ',ns,flb,fub endif do nf = 1,size(sdat%pstrm(ns)%fldlist_model) if (sdat%pstrm(ns)%stream_nlev > 1) then @@ -1168,6 +1193,7 @@ subroutine shr_strdata_print(sdat, name) character(*),parameter :: F01 = "('(shr_strdata_print) ',a,i6,a)" character(*),parameter :: F02 = "('(shr_strdata_print) ',a,es13.6)" character(*),parameter :: F04 = "('(shr_strdata_print) ',a,i2,a,a)" + character(*),parameter :: F05 = "('(shr_strdata_print) ',a)" character(*),parameter :: F07 = "('(shr_strdata_print) ',a,i2,a,es13.6)" character(*),parameter :: F90 = "('(shr_strdata_print) ',58('-'))" !------------------------------------------------------------------------------- @@ -1181,9 +1207,8 @@ subroutine shr_strdata_print(sdat, name) write(sdat%logunit,F02) "lambm0 = ",sdat%lambm0 write(sdat%logunit,F02) "obliqr = ",sdat%obliqr write(sdat%logunit,F01) "pio_iotype = ",sdat%io_type - write(sdat%logunit,F01) "nstreams = ",shr_strdata_get_stream_count(sdat) - write(sdat%logunit,F01) "nvectors = ",sdat%nvectors + write(sdat%logunit,F05) "Per stream information " do ns = 1, shr_strdata_get_stream_count(sdat) write(sdat%logunit,F04) " taxMode (",ns,") = ",trim(sdat%stream(ns)%taxmode) write(sdat%logunit,F07) " dtlimit (",ns,") = ",sdat%stream(ns)%dtlimit @@ -1227,6 +1252,7 @@ subroutine shr_strdata_readLBUB(sdat, ns, mDate, mSec, newData, istr, rc) character(CL) :: filename_ub character(CL) :: filename_next character(CL) :: filename_prev + logical :: find_bounds character(*), parameter :: subname = '(shr_strdata_readLBUB) ' character(*), parameter :: F00 = "('(shr_strdata_readLBUB) ',8a)" character(*), parameter :: F01 = "('(shr_strdata_readLBUB) ',a,5i8)" @@ -1261,17 +1287,34 @@ subroutine shr_strdata_readLBUB(sdat, ns, mDate, mSec, newData, istr, rc) call ESMF_TraceRegionExit(trim(istr)//'_setup') ! if model current date is outside of model lower or upper bound - find the stream bounds - if (rDateM < rDateLB .or. rDateM >= rDateUB) then + find_bounds = (rDateM < rDateLB .or. rDateM >= rDateUB) + if (debug > 0 .and. sdat%mainproc) then + write(sdat%logunit,'(a,i4,2x,6(i18,2x),l7)')' stream,lbymd,lbsec,mdate,msec,ubymd,ubsec,newdata= ',ns,& + sdat%pstrm(ns)%ymdLB,sdat%pstrm(ns)%todLB, & + mdate,msec, & + sdat%pstrm(ns)%ymdUB,sdat%pstrm(ns)%todUB,find_bounds + write(sdat%logunit,'(a,i4,2x,3(f20.3,2x),l7)')' stream,rdateLB,rdateM,rdateUB,newdata= ',& + ns,rdateLB,rdateM,rdateUB,find_bounds + end if + if (find_bounds) then call ESMF_TraceRegionEnter(trim(istr)//'_fbound') call shr_stream_findBounds(stream, mDate, mSec, sdat%mainproc, & sdat%pstrm(ns)%ymdLB, dDateLB, sdat%pstrm(ns)%todLB, n_lb, filename_lb, & sdat%pstrm(ns)%ymdUB, dDateUB, sdat%pstrm(ns)%todUB, n_ub, filename_ub) call ESMF_TraceRegionExit(trim(istr)//'_fbound') + if (debug > 0 .and. sdat%mainproc) then + write(sdat%logunit,'(a,i4,2x,6(i18,2x),l7)')' stream,lbymd,lbsec,mdate,msec,ubymd,ubsec,newdata= ',ns,& + sdat%pstrm(ns)%ymdLB,sdat%pstrm(ns)%todLB,& + mdate,msec, & + sdat%pstrm(ns)%ymdUB,sdat%pstrm(ns)%todUB + write(sdat%logunit,'(a,i4,2x,3(f20.3,2x),l7)')' stream,rdateLB,rdateM,rdateUB,newdata= ',& + ns,rdateLB,rdateM,rdateUB,find_bounds + end if endif ! determine if need to read in new stream data - if (sdat%pstrm(ns)%ymdLB /= oDateLB .or. sdat%pstrm(ns)%todLB /= oSecLB) then - newdata = .true. + newdata = (sdat%pstrm(ns)%ymdLB /= oDateLB .or. sdat%pstrm(ns)%todLB /= oSecLB) + if (newdata) then if (sdat%pstrm(ns)%ymdLB == oDateUB .and. sdat%pstrm(ns)%todLB == oSecUB) then ! copy fldbun_stream_ub to fldbun_stream_lb i = sdat%pstrm(ns)%stream_ub @@ -1286,8 +1329,8 @@ subroutine shr_strdata_readLBUB(sdat, ns, mDate, mSec, newData, istr, rc) end if endif - if (sdat%pstrm(ns)%ymdUB /= oDateUB .or. sdat%pstrm(ns)%todUB /= oSecUB) then - newdata = .true. + if (newdata) then + ! read upper bound of data call shr_strdata_readstrm(sdat, sdat%pstrm(ns), stream, & sdat%pstrm(ns)%fldbun_data(sdat%pstrm(ns)%stream_ub), & filename_ub, n_ub, istr=trim(istr)//'_UB', boundstr='ub', rc=rc) @@ -1331,7 +1374,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & ! local variables integer :: stream_nlev - type(ESMF_Field) :: field_dst, vector_dst + type(ESMF_Field) :: field_dst, field_vector_dst character(CL) :: currfile logical :: fileexists logical :: fileopen @@ -1343,17 +1386,17 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & real(r8) :: fillvalue_r8 logical :: handlefill = .false. integer :: old_error_handle - real(r8), pointer :: dataptr(:) => null() - real(r8), pointer :: dataptr1d(:) => null() ! field bundle data - real(r8), pointer :: dataptr2d(:,:) => null() ! field bundle data - real(r8), pointer :: dataptr2d_src(:,:) => null() ! field bundle data - real(r8), pointer :: dataptr2d_dst(:,:) => null() ! field bundle data - real(r4), allocatable :: data_real1d(:) ! stream input data - real(r4), allocatable :: data_real2d(:,:) ! stream input data - real(r8), allocatable :: data_dbl1d(:) ! stream input data - real(r8), allocatable :: data_dbl2d(:,:) ! stream input data - integer(i2), allocatable :: data_short1d(:) ! stream input data - integer(i2), allocatable :: data_short2d(:,:) ! stream input data + real(r8), pointer :: dataptr(:) + real(r8), pointer :: dataptr1d(:) ! field bundle data + real(r8), pointer :: dataptr2d(:,:) ! field bundle data + real(r8), pointer :: dataptr2d_src(:,:) ! field bundle data + real(r8), pointer :: dataptr2d_dst(:,:) ! field bundle data + real(r4), allocatable :: data_real1d(:) ! stream input data + real(r4), allocatable :: data_real2d(:,:) ! stream input data + real(r8), allocatable :: data_dbl1d(:) ! stream input data + real(r8), allocatable :: data_dbl2d(:,:) ! stream input data + integer(i2), allocatable :: data_short1d(:) ! stream input data + integer(i2), allocatable :: data_short2d(:,:) ! stream input data integer :: lsize, n integer :: spatialDim, numOwnedElements integer :: pio_iovartype @@ -1375,6 +1418,17 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & rc = ESMF_SUCCESS + ! nullify local pointers + nullify(dataptr) + nullify(dataptr1d) + nullify(dataptr2d) + nullify(dataptr2d_src) + nullify(dataptr2d_dst) + nullify(nv_coords) + nullify(nu_coords) + nullify(data_u_dst) + nullify(data_v_dst) + ! Set up file to read from if (sdat%mainproc) then inquire(file=trim(fileName),exist=fileExists) @@ -1441,10 +1495,10 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & write(sdat%logunit,F02) 'reading file ' // trim(boundstr) //': ',trim(filename), nt endif - if(per_stream%ucomp > 0 .and. per_stream%vcomp > 0) then + if (ESMF_FieldIsCreated(per_stream%field_stream_vector)) then call shr_string_listGetName(stream%stream_vectors,1,uname) call shr_string_listGetName(stream%stream_vectors,2,vname) - call dshr_field_getfldptr(per_stream%stream_vector, fldptr2=dataptr2d_src, rc=rc) + call dshr_field_getfldptr(per_stream%field_stream_vector, fldptr2=dataptr2d_src, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return endif @@ -1744,15 +1798,19 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & dataptr2d_src(1,i) = (coslon * dataptr(i) - sinlon * dataptr2d_src(2,i)) dataptr2d_src(2,i) = (sinlon * dataptr(i) + coslon * dataptr2d_src(2,i)) enddo - vector_dst = ESMF_FieldCreate(sdat%model_mesh, ESMF_TYPEKIND_r8, name='vector_dst', & + field_vector_dst = ESMF_FieldCreate(sdat%model_mesh, ESMF_TYPEKIND_r8, name='field_vector_dst', & ungriddedLbound=(/1/), ungriddedUbound=(/2/), gridToFieldMap=(/2/), meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_FieldRegrid(per_stream%stream_vector, vector_dst, per_stream%routehandle, & + if (.not. ESMF_FieldIsCreated(per_stream%field_stream_vector)) then + call shr_sys_abort('ERROR: per_stream%field_stream_vector has not been created') + end if + + call ESMF_FieldRegrid(per_stream%field_stream_vector, field_vector_dst, per_stream%routehandle, & termorderflag=ESMF_TERMORDER_SRCSEQ, checkflag=checkflag, zeroregion=ESMF_REGION_TOTAL, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_FieldGet(vector_dst, farrayPtr=dataptr2d_dst, rc=rc) + call ESMF_FieldGet(field_vector_dst, farrayPtr=dataptr2d_dst, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return call dshr_fldbun_getFldPtr(fldbun_data, trim(uname), data_u_dst, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return @@ -1800,7 +1858,6 @@ subroutine shr_strdata_set_stream_iodesc(sdat, per_stream, fldname, pioid, rc) integer , intent(out) :: rc ! local variables - integer :: stream_nlev integer :: gsize2d integer :: pio_iovartype @@ -1812,8 +1869,8 @@ subroutine shr_strdata_set_stream_iodesc(sdat, per_stream, fldname, pioid, rc) integer, allocatable :: dimlens(:) type(ESMF_DistGrid) :: distGrid integer :: lsize - integer, pointer :: compdof(:) => null() - integer, pointer :: compdof3d(:) => null() + integer, pointer :: compdof(:) + integer, pointer :: compdof3d(:) integer :: rCode ! pio return code (only used when pio error handling is PIO_BCAST_ERROR) character(*), parameter :: subname = '(shr_strdata_set_stream_iodesc) ' character(*), parameter :: F00 = "('(shr_strdata_set_stream_iodesc) ',a,i8,2x,i8,2x,a)" @@ -1823,6 +1880,10 @@ subroutine shr_strdata_set_stream_iodesc(sdat, per_stream, fldname, pioid, rc) rc = ESMF_SUCCESS + ! nullify local pointers + nullify(compdof) + nullify(compdof3d) + ! set the number of vertical levels to a local variable stream_nlev = per_stream%stream_nlev diff --git a/streams/dshr_stream_mod.F90 b/streams/dshr_stream_mod.F90 index 4f8febc40..f29785e39 100644 --- a/streams/dshr_stream_mod.F90 +++ b/streams/dshr_stream_mod.F90 @@ -222,8 +222,8 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu p => item(getElementsByTagname(streamnode, "taxmode"), 0) if (associated(p)) then call extractDataContent(p, streamdat(i)%taxmode) - if (streamdat(i)%taxmode /= shr_stream_taxis_cycle .and. & - streamdat(i)%taxmode /= shr_stream_taxis_extend .and. & + if (streamdat(i)%taxmode /= shr_stream_taxis_cycle .and. & + streamdat(i)%taxmode /= shr_stream_taxis_extend .and. & streamdat(i)%taxmode /= shr_stream_taxis_limit) then call shr_sys_abort("tintalgo must have a value of either cycle, extend or limit") end if @@ -232,8 +232,8 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu p => item(getElementsByTagname(streamnode, "mapalgo"), 0) if (associated(p)) then call extractDataContent(p, streamdat(i)%mapalgo) - if (streamdat(i)%mapalgo /= shr_stream_mapalgo_bilinear .and. & - streamdat(i)%mapalgo /= shr_stream_mapalgo_redist .and. & + if (streamdat(i)%mapalgo /= shr_stream_mapalgo_bilinear .and. & + streamdat(i)%mapalgo /= shr_stream_mapalgo_redist .and. & streamdat(i)%mapalgo /= shr_stream_mapalgo_nn .and. & streamdat(i)%mapalgo /= shr_stream_mapalgo_consf .and. & streamdat(i)%mapalgo /= shr_stream_mapalgo_consd .and. & @@ -245,8 +245,8 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu p => item(getElementsByTagname(streamnode, "tintalgo"), 0) if (associated(p)) then call extractDataContent(p, streamdat(i)%tInterpAlgo) - if (streamdat(i)%tInterpAlgo /= shr_stream_tinterp_lower .and. & - streamdat(i)%tInterpAlgo /= shr_stream_tinterp_upper .and. & + if (streamdat(i)%tInterpAlgo /= shr_stream_tinterp_lower .and. & + streamdat(i)%tInterpAlgo /= shr_stream_tinterp_upper .and. & streamdat(i)%tInterpAlgo /= shr_stream_tinterp_nearest .and. & streamdat(i)%tInterpAlgo /= shr_stream_tinterp_linear .and. & streamdat(i)%tInterpAlgo /= shr_stream_tinterp_coszen) then @@ -783,7 +783,9 @@ subroutine shr_stream_findBounds(strm, mDateIn, secIn, isroot_task, & character(*),parameter :: F04 = "('(shr_stream_findBounds) ',2a,i4)" !------------------------------------------------------------------------------- - if (debug>0) write(strm%logunit,F02) "DEBUG: ---------- enter ------------------" + if (debug>0 .and. isroot_task) then + write(strm%logunit,F02) "DEBUG: ---------- enter ------------------" + end if if ( .not. strm%init ) then call shr_sys_abort(trim(subName)//" ERROR: trying to find bounds of uninitialized stream") @@ -828,9 +830,9 @@ subroutine shr_stream_findBounds(strm, mDateIn, secIn, isroot_task, & dDateIn = dYear*10000 + modulo(mDateIn,10000) ! mDateIn mapped to range of data years rDateIn = dDateIn + secIn/spd ! dDateIn + fraction of a day - if(debug>0) then - write(strm%logunit,*) 'fbd1 ',mYear,dYear,dDateIn,rDateIn - write(strm%logunit,*) 'fbd2 ',yrFirst,yrLast,yrAlign,nYears + if (debug>0 .and. isroot_task) then + write(strm%logunit,'(a,2(i8,2x),2(f20.4,2x))') 'mYear,dYear,dDateIn,rDateIn = ',mYear,dYear,dDateIn,rDateIn + write(strm%logunit,'(a,2(i8,2x),2(f20.4,2x))') 'yrFirst,yrLast,yrAlign,nYears= ',yrFirst,yrLast,yrAlign,nYears endif !---------------------------------------------------------------------------- @@ -865,8 +867,8 @@ subroutine shr_stream_findBounds(strm, mDateIn, secIn, isroot_task, & call shr_sys_abort(trim(subName)//" ERROR: LVD not found, all data is after yearLast") end if end if - if (debug>1 ) then - if (strm%found_lvd) write(strm%logunit,F01) "DEBUG: found LVD = ",strm%file(k)%date(n) + if (debug>1 .and. isroot_task ) then + if (strm%found_lvd) write(strm%logunit,F01) " found LVD = ",strm%file(k)%date(n) end if end if @@ -886,8 +888,8 @@ subroutine shr_stream_findBounds(strm, mDateIn, secIn, isroot_task, & else rDategvd = 99991231.0 endif - if(debug>0) then - write(strm%logunit,*) 'fbd3 ',rDateIn,rDatelvd,rDategvd + if (debug>0 .and. isroot_task) then + write(strm%logunit,'(a,3(f20.4,2x))') 'rDateIn,rDatelvd,rDategvd = ',rDateIn,rDatelvd,rDategvd endif !----------------------------------------------------------- @@ -941,8 +943,8 @@ subroutine shr_stream_findBounds(strm, mDateIn, secIn, isroot_task, & strm%n_gvd = n strm%found_gvd = .true. rDategvd = strm%file(k)%date(n) + strm%file(k)%secs(n)/spd ! GVD date + frac day - if (debug>1) then - write(strm%logunit,F01) "DEBUG: found GVD ",strm%file(k)%date(n) + if (debug>1 .and. isroot_task) then + write(strm%logunit,F01) " found GVD ",strm%file(k)%date(n) end if exit B end if @@ -1210,7 +1212,7 @@ subroutine shr_stream_readTCoord(strm, k, isroot_task, rc) ! open file if needed if (.not. pio_file_is_open(strm%file(k)%fileid)) then - if (debug > 0 .and. isroot_task) then + if (debug>1 .and. isroot_task) then write(strm%logunit, '(a)') trim(subname)//' opening stream filename = '//trim(filename) end if rcode = pio_openfile(strm%pio_subsystem, strm%file(k)%fileid, strm%pio_iotype, filename, pio_nowrite) @@ -1271,7 +1273,7 @@ subroutine shr_stream_readTCoord(strm, k, isroot_task, rc) deallocate(tvar) ! close file - if (debug > 0 .and. isroot_task) then + if (debug>1 .and. isroot_task) then write(strm%logunit, '(a)') trim(subname)//' closing stream filename = '//trim(filename) end if call pio_closefile(strm%file(k)%fileid) @@ -1334,7 +1336,9 @@ subroutine verifyTCoord(strm,k,rc) !------------------------------------------------------------------------------- rc = 0 - if (debug>1 ) write(strm%logunit,F01) "checking t-coordinate data for file k =",k + if (debug>1 .and. isroot_task) then + write(strm%logunit,F01) "checking t-coordinate data for file k =",k + end if if ( .not. strm%file(k)%haveData) then rc = 1 @@ -1356,7 +1360,7 @@ subroutine verifyTCoord(strm,k,rc) date2 = strm%file(k )%date(n) secs2 = strm%file(k )%secs(n) checkIt = .true. - if (debug>1 ) write(strm%logunit,F01) "comparing with previous file for file k =",k + if (debug>1 .and. isroot_task) write(strm%logunit,F01) "comparing with previous file for file k =",k end if end if else if (n==strm%file(k)%nt+1) then @@ -1369,7 +1373,7 @@ subroutine verifyTCoord(strm,k,rc) date2 = strm%file(k+1)%date(1) secs2 = strm%file(k+1)%secs(1) checkIt = .true. - if (debug>1 ) write(strm%logunit,F01) "comparing with next file for file k =",k + if (debug>1 .and. isroot_task) write(strm%logunit,F01) "comparing with next file for file k =",k end if end if else @@ -1405,7 +1409,8 @@ subroutine verifyTCoord(strm,k,rc) end if end do - if (debug>0) write(strm%logunit,F01) "data is OK (non-decreasing) for file k =",k + if (debug>0 .and. isroot_task) write(strm%logunit,F01) "data is OK (non-decreasing) for file k =",k + end subroutine verifyTCoord end subroutine shr_stream_readTCoord @@ -1681,13 +1686,14 @@ subroutine shr_stream_restIO(pioid, streams, mode) type(var_desc_t) :: varid, tvarid, dvarid, ntvarid, hdvarid integer :: rcode integer :: dimid_stream, dimid_files,dimid_nt, dimid_str - integer :: n, k, maxnfiles=0 + integer :: n,i, k, maxnfiles=0 integer :: maxnt = 0 integer, allocatable :: tmp(:) character(len=CL) :: fname !------------------------------------------------------------------------------- if (mode .eq. 'define') then + rcode = pio_def_dim(pioid, 'strlen', CL, dimid_str) do k=1,size(streams) if (streams(k)%nfiles > maxnfiles) then @@ -1699,21 +1705,29 @@ subroutine shr_stream_restIO(pioid, streams, mode) endif enddo enddo - rcode = pio_def_dim(pioid, 'nt', maxnt, dimid_nt) - rcode = pio_def_dim(pioid, 'nfiles', maxnfiles, dimid_files) + rcode = pio_def_dim(pioid, 'nt' , maxnt, dimid_nt) + rcode = pio_def_dim(pioid, 'nfiles' , maxnfiles, dimid_files) rcode = pio_def_dim(pioid, 'nstreams', size(streams), dimid_stream) - rcode = pio_def_var(pioid, 'nt' , PIO_INT, (/dimid_files, dimid_stream/), varid) - rcode = pio_def_var(pioid, 'nfiles', PIO_INT, (/dimid_stream/), varid) + + rcode = pio_def_var(pioid, 'ymdLB' , PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'ymdUB' , PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'todLB' , PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'todUB' , PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'nfiles', PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'offset', PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'k_lvd', PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'n_lvd', PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'k_gvd', PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'n_gvd', PIO_INT , (/dimid_stream/), varid) + rcode = pio_def_var(pioid, 'nt' , PIO_INT , (/dimid_files, dimid_stream/), varid) + rcode = pio_def_var(pioid, 'haveData', PIO_INT , (/dimid_files, dimid_stream/), varid) rcode = pio_def_var(pioid, 'filename', PIO_CHAR, (/dimid_str, dimid_files, dimid_stream/), varid) - rcode = pio_def_var(pioid, 'date', PIO_INT, (/dimid_nt, dimid_files, dimid_stream/), varid) - rcode = pio_def_var(pioid, 'timeofday',PIO_INT, (/dimid_nt, dimid_files, dimid_stream/), varid) - rcode = pio_def_var(pioid, 'offset', PIO_INT, (/dimid_stream/), varid) - rcode = pio_def_var(pioid, 'k_lvd', PIO_INT, (/dimid_stream/), varid) - rcode = pio_def_var(pioid, 'n_lvd', PIO_INT, (/dimid_stream/), varid) - rcode = pio_def_var(pioid, 'k_gvd', PIO_INT, (/dimid_stream/), varid) - rcode = pio_def_var(pioid, 'n_gvd', PIO_INT, (/dimid_stream/), varid) - rcode = pio_def_var(pioid, 'haveData', PIO_INT, (/dimid_files, dimid_stream/), varid) + rcode = pio_def_var(pioid, 'date', PIO_INT , (/dimid_nt , dimid_files, dimid_stream/), varid) + rcode = pio_def_var(pioid, 'timeofday',PIO_INT , (/dimid_nt , dimid_files, dimid_stream/), varid) + else if (mode .eq. 'write') then + + ! write out nfiles rcode = pio_inq_varid(pioid, 'nfiles', varid) allocate(tmp(size(streams))) do k=1,size(streams) @@ -1721,30 +1735,35 @@ subroutine shr_stream_restIO(pioid, streams, mode) enddo rcode = pio_put_var(pioid, varid, tmp) + ! write out offset rcode = pio_inq_varid(pioid, 'offset', varid) do k=1,size(streams) tmp(k) = streams(k)%offset enddo rcode = pio_put_var(pioid, varid, tmp) + ! write out k_lvd rcode = pio_inq_varid(pioid, 'k_lvd', varid) do k=1,size(streams) tmp(k) = streams(k)%k_lvd enddo rcode = pio_put_var(pioid, varid, tmp) + ! write out n_lvd rcode = pio_inq_varid(pioid, 'n_lvd', varid) do k=1,size(streams) tmp(k) = streams(k)%n_lvd enddo rcode = pio_put_var(pioid, varid, tmp) + ! write out k_gvd rcode = pio_inq_varid(pioid, 'k_gvd', varid) do k=1,size(streams) tmp(k) = streams(k)%k_gvd enddo rcode = pio_put_var(pioid, varid, tmp) + ! write out n_gvd rcode = pio_inq_varid(pioid, 'n_gvd', varid) do k=1,size(streams) tmp(k) = streams(k)%n_gvd @@ -1752,43 +1771,72 @@ subroutine shr_stream_restIO(pioid, streams, mode) rcode = pio_put_var(pioid, varid, tmp) deallocate(tmp) - rcode = pio_inq_varid(pioid, 'filename', varid) - rcode = pio_inq_varid(pioid, 'date', dvarid) - rcode = pio_inq_varid(pioid, 'timeofday', tvarid) - rcode = pio_inq_varid(pioid, 'nt', ntvarid) - rcode = pio_inq_varid(pioid, 'haveData', hdvarid) + ! write out nt + rcode = pio_inq_varid(pioid, 'nt', varid) + do k=1,size(streams) + do n=1,streams(k)%nfiles + rcode = pio_put_var(pioid, varid, (/n,k/), streams(k)%file(n)%nt) + enddo + enddo + + ! write out haveData + rcode = pio_inq_varid(pioid, 'haveData', dvarid) + do k=1,size(streams) + do n=1,streams(k)%nfiles + if(streams(k)%file(n)%haveData) then + rcode = pio_put_var(pioid, dvarid, (/n,k/), 1) + else + rcode = pio_put_var(pioid, dvarid, (/n,k/), 0) + endif + enddo + enddo + + ! write out date + rcode = pio_inq_varid(pioid, 'date', varid) do k=1,size(streams) do n=1,streams(k)%nfiles - rcode = pio_put_var(pioid, varid, (/1,n,k/), streams(k)%file(n)%name) - rcode = pio_put_var(pioid, ntvarid, (/n,k/), streams(k)%file(n)%nt) if (allocated(streams(k)%file(n)%date)) then - rcode = pio_put_var(pioid, dvarid, (/1,n,k/), (/streams(k)%file(n)%nt,1,1/),streams(k)%file(n)%date) + rcode = pio_put_var(pioid, varid, (/1,n,k/), (/streams(k)%file(n)%nt,1,1/), streams(k)%file(n)%date) endif + enddo + enddo + + ! write out timeofday + rcode = pio_inq_varid(pioid, 'timeofday', varid) + do k=1,size(streams) + do n=1,streams(k)%nfiles if (allocated(streams(k)%file(n)%secs)) then - rcode = pio_put_var(pioid, tvarid, (/1,n,k/), (/streams(k)%file(n)%nt,1,1/),streams(k)%file(n)%secs) - endif - if(streams(k)%file(n)%haveData) then - rcode = pio_put_var(pioid, hdvarid, (/n,k/), 1) - else - rcode = pio_put_var(pioid, hdvarid, (/n,k/), 0) + rcode = pio_put_var(pioid, varid, (/1,n,k/), (/streams(k)%file(n)%nt,1,1/), streams(k)%file(n)%secs) endif enddo enddo + + ! write out filename + rcode = pio_inq_varid(pioid, 'filename', varid) + do k=1,size(streams) + do n=1,streams(k)%nfiles + rcode = pio_put_var(pioid, varid, (/1,n,k/), streams(k)%file(n)%name) + enddo + enddo + else if (mode .eq. 'read') then + + ! Read in nfiles rcode = pio_inq_varid(pioid, 'nfiles', varid) allocate(tmp(size(streams))) rcode = pio_get_var(pioid, varid, tmp) do k=1,size(streams) if (streams(k)%nFiles /= tmp(k)) then - call shr_sys_abort('something is wrong') + call shr_sys_abort('ERROR reading in nfiles') endif enddo + ! read in offset rcode = pio_inq_varid(pioid, 'offset', varid) rcode = pio_get_var(pioid, varid, tmp) do k=1,size(streams) if (streams(k)%offset /= tmp(k)) then - call shr_sys_abort('something is wrong') + call shr_sys_abort('ERROR reading in offset') endif enddo @@ -1797,7 +1845,7 @@ subroutine shr_stream_restIO(pioid, streams, mode) do k=1,size(streams) streams(k)%k_lvd = tmp(k) if (streams(k)%k_lvd /= tmp(k)) then - call shr_sys_abort('something is wrong') + call shr_sys_abort('ERROR reading in k_lvd') endif enddo @@ -1806,7 +1854,7 @@ subroutine shr_stream_restIO(pioid, streams, mode) do k=1,size(streams) streams(k)%n_lvd = tmp(k) if (streams(k)%n_lvd /= tmp(k)) then - call shr_sys_abort('something is wrong') + call shr_sys_abort('ERROR reading in n_lvd') endif enddo @@ -1815,7 +1863,7 @@ subroutine shr_stream_restIO(pioid, streams, mode) do k=1,size(streams) streams(k)%k_gvd = tmp(k) if (streams(k)%k_gvd /= tmp(k)) then - call shr_sys_abort('something is wrong') + call shr_sys_abort('ERROR reading in k_gvd') endif enddo @@ -1824,50 +1872,66 @@ subroutine shr_stream_restIO(pioid, streams, mode) do k=1,size(streams) streams(k)%n_gvd = tmp(k) if (streams(k)%n_gvd /= tmp(k)) then - call shr_sys_abort('something is wrong') + call shr_sys_abort('ERROR reading in n_gvd') endif enddo deallocate(tmp) - rcode = pio_inq_varid(pioid, 'filename', varid) - rcode = pio_inq_varid(pioid, 'date', dvarid) + rcode = pio_inq_varid(pioid, 'filename' , varid) + rcode = pio_inq_varid(pioid, 'nt' , ntvarid) + rcode = pio_inq_varid(pioid, 'date' , dvarid) rcode = pio_inq_varid(pioid, 'timeofday', tvarid) - rcode = pio_inq_varid(pioid, 'nt', ntvarid) - rcode = pio_inq_varid(pioid, 'haveData', hdvarid) + rcode = pio_inq_varid(pioid, 'haveData' , hdvarid) do k=1,size(streams) do n=1,streams(k)%nfiles + + ! read in filename rcode = pio_get_var(pioid, varid, (/1,n,k/), fname) - if(fname .ne. streams(k)%file(n)%name) Then - call shr_sys_abort('something is wrong') + if (trim(fname) /= trim(streams(k)%file(n)%name)) then + write(6,'(a)')' fname = '//trim(fname) + write(6,'(a,i8,2x,i8,2x,a)')' k,n,streams(k)%file(n)%name = ',k,n,trim(streams(k)%file(n)%name) + call shr_sys_abort('ERROR reading in filename') endif + + ! read in nt allocate(tmp(1)) rcode = pio_get_var(pioid, ntvarid, (/n,k/), tmp(1)) streams(k)%file(n)%nt = tmp(1) if(tmp(1) /= streams(k)%file(n)%nt) then - call shr_sys_abort('something is wrong') + call shr_sys_abort('ERROR read in nt') endif deallocate(tmp) + if (streams(k)%file(n)%nt > 0) then + + ! Allocate memory allocate(tmp(streams(k)%file(n)%nt)) + + ! Read in date rcode = pio_get_var(pioid, dvarid, (/1,n,k/), (/streams(k)%file(n)%nt,1,1/),tmp) streams(k)%file(n)%date = tmp - if (.not. allocated(streams(k)%file(n)%date) .or. & - any(tmp .ne. streams(k)%file(n)%date) ) then - call shr_sys_abort('something is wrong') + if (.not. allocated(streams(k)%file(n)%date) .or. any(tmp .ne. streams(k)%file(n)%date) ) then + call shr_sys_abort('ERROR reading in date') endif + + ! Read in timeofday rcode = pio_get_var(pioid, tvarid, (/1,n,k/), (/streams(k)%file(n)%nt,1,1/),tmp) streams(k)%file(n)%secs = tmp - if (.not. allocated(streams(k)%file(n)%secs) .or. & - any(tmp .ne. streams(k)%file(n)%secs) ) then - call shr_sys_abort('something is wrong') + if (.not. allocated(streams(k)%file(n)%secs) .or. any(tmp .ne. streams(k)%file(n)%secs) ) then + call shr_sys_abort('ERROR reaing in timeofday') endif + + ! Read in havedata rcode = pio_get_var(pioid, hdvarid, (/n,k/), tmp(1)) if(tmp(1)==1) then streams(k)%file(n)%havedata = .true. else streams(k)%file(n)%havedata = .false. endif + + ! Free memory deallocate(tmp) + endif enddo enddo diff --git a/streams/dshr_tinterp_mod.F90 b/streams/dshr_tinterp_mod.F90 index 064915f31..ef634d120 100644 --- a/streams/dshr_tinterp_mod.F90 +++ b/streams/dshr_tinterp_mod.F90 @@ -20,6 +20,8 @@ module dshr_tInterp_mod public :: shr_tInterp_getAvgCosz ! get cosz, time avg of public :: shr_tInterp_getCosz ! get cosz + integer :: debug = 0 + real(R8) ,parameter :: deg2rad = SHR_CONST_PI/180.0_R8 real(r8) ,parameter :: c0 = 0.0_r8 real(r8) ,parameter :: c1 = 1.0_r8 @@ -27,8 +29,6 @@ module dshr_tInterp_mod character(*) ,parameter :: u_FILE_u = & __FILE__ - integer :: debug = 0 - !=============================================================================== contains !=============================================================================== @@ -158,7 +158,8 @@ end subroutine shr_tInterp_getFactors !=============================================================================== subroutine shr_tInterp_getAvgCosz(tavCosz, lon, lat, & - ymd1, tod1, ymd2, tod2, eccen, mvelpp, lambm0, obliqr, modeldt, calendar, rc) + ymd1, tod1, ymd2, tod2, eccen, mvelpp, lambm0, obliqr, modeldt, calendar, & + isroot, logunit, rc) !--------------------------------------------------------------- ! Returns a time-average of cos(z) over the time interval [LB,UB]. @@ -180,6 +181,8 @@ subroutine shr_tInterp_getAvgCosz(tavCosz, lon, lat, & real(r8) ,intent(in) :: obliqr ! orb param integer ,intent(in) :: modeldt ! model time step in secs character(*) ,intent(in) :: calendar ! calendar type + logical , intent(in) :: isroot + integer , intent(in) :: logunit integer ,intent(out) :: rc ! error status ! local variables @@ -236,10 +239,15 @@ subroutine shr_tInterp_getAvgCosz(tavCosz, lon, lat, & lsize = size(tavCosz) allocate(cosz(lsize)) + if (debug>0 .and. isroot) then + write(logunit,'(a,4(i8,2x))') trim(subname)//' calculating time average over interval ymd1,tod1,ymd2,tod2 = ', & + ymd1,tod1,ymd2,tod2 + end if + do while( reday < reday2) ! mid-interval t-steps thru interval [LB,UB] !--- get next cosz value for t-avg --- - call shr_tInterp_getCosz(cosz,lon,lat,ymd,tod,eccen,mvelpp,lambm0,obliqr,calendar) + call shr_tInterp_getCosz(cosz,lon,lat,ymd,tod,eccen,mvelpp,lambm0,obliqr,calendar,isroot,logunit) n = n + ldt tavCosz = tavCosz + cosz*real(ldt,r8) ! add to partial sum @@ -258,7 +266,8 @@ subroutine shr_tInterp_getAvgCosz(tavCosz, lon, lat, & end subroutine shr_tInterp_getAvgCosz !=============================================================================== - subroutine shr_tInterp_getCosz(cosz, lon, lat, ymd, tod, eccen, mvelpp, lambm0, obliqr, calendar) + subroutine shr_tInterp_getCosz(cosz, lon, lat, ymd, tod, & + eccen, mvelpp, lambm0, obliqr, calendar, isroot, logunit) !--------------------------------------------------------------- ! Calculate and return the cos(solar-zenith angle). @@ -274,6 +283,8 @@ subroutine shr_tInterp_getCosz(cosz, lon, lat, ymd, tod, eccen, mvelpp, lambm0, real(r8) , intent(in) :: lambm0 ! orb param real(r8) , intent(in) :: obliqr ! orb param character(*) , intent(in) :: calendar ! calendar type + logical , intent(in) :: isroot + integer , intent(in) :: logunit ! local variables integer :: n @@ -293,6 +304,11 @@ subroutine shr_tInterp_getCosz(cosz, lon, lat, ymd, tod, eccen, mvelpp, lambm0, call shr_cal_date2julian(ymd, tod, calday, calendar) call shr_orb_decl( calday, eccen, mvelpp, lambm0, obliqr, declin, eccf ) + if (debug > 0 .and. isroot) then + write(logunit,'(a,2(i8,2x),d20.10,2x,a)') trim(subname)//' ymd, tod, calday, calendar = ',ymd,tod,calday,calendar + write(logunit,'(a,4(d20.10,2x))') trim(subname)//' eccen, mvelpp, lambm0, obliqr = ',eccen, mvelpp, lambm0, obliqr + write(logunit,'(a,2(d20.10,2x))') trim(subname)//' declin,eccf= ',declin,eccf + end if do n = 1,lsize lonr = lon(n) * deg2rad latr = lat(n) * deg2rad From 530c2624df18b2e2b05cf1c639b073479f68f269 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Turun=C3=A7o=C4=9Flu?= Date: Thu, 27 Oct 2022 10:41:01 -0600 Subject: [PATCH 07/28] Update CDEPS (#50) Update NOAA-EMC/CDEPS to include changes from ESCOMP/CDEPS. --- datm/atm_comp_nuopc.F90 | 7 +- datm/cime_config/buildnml | 37 ++- datm/cime_config/config_component.xml | 24 +- datm/cime_config/namelist_definition_datm.xml | 13 + datm/cime_config/stream_definition_datm.xml | 280 +++++++++++++++++- datm/datm_datamode_clmncep_mod.F90 | 14 +- dlnd/cime_config/config_component.xml | 10 + dlnd/cime_config/namelist_definition_dlnd.xml | 13 + dlnd/lnd_comp_nuopc.F90 | 22 +- docn/cime_config/buildnml | 6 + docn/cime_config/config_component.xml | 13 +- docn/cime_config/namelist_definition_docn.xml | 15 +- docn/cime_config/stream_definition_docn.xml | 1 + docn/ocn_comp_nuopc.F90 | 7 +- drof/cime_config/config_component.xml | 10 + drof/cime_config/namelist_definition_drof.xml | 13 + drof/rof_comp_nuopc.F90 | 8 +- dwav/cime_config/config_component.xml | 10 + dwav/cime_config/namelist_definition_dwav.xml | 13 + dwav/wav_comp_nuopc.F90 | 8 +- share/shr_cal_mod.F90 | 17 ++ streams/dshr_strdata_mod.F90 | 199 +++++++------ streams/dshr_stream_mod.F90 | 52 +++- 23 files changed, 664 insertions(+), 128 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index fec8a327f..2796a2c10 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -130,6 +130,7 @@ module cdeps_datm_comp character(CL) :: factorFn_data = 'null' ! file containing correction factors data logical :: flds_presaero = .false. ! true => send valid prescribed aero fields to mediator logical :: flds_presndep = .false. ! true => send valid prescribed ndep fields to mediator + logical :: flds_preso3 = .false. ! true => send valid prescribed ozone fields to mediator logical :: flds_co2 = .false. ! true => send prescribed co2 to mediator logical :: flds_wiso = .false. ! true => send water isotopes to mediator character(CL) :: bias_correct = nullstr ! send bias correction fields to coupler @@ -236,7 +237,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) model_meshfile, model_maskfile, & nx_global, ny_global, restfilm, iradsw, factorFn_data, factorFn_mesh, & flds_presaero, flds_co2, flds_wiso, bias_correct, anomaly_forcing, & - skip_restart_read, flds_presndep + skip_restart_read, flds_presndep, flds_preso3 rc = ESMF_SUCCESS @@ -276,6 +277,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call shr_mpi_bcast(restfilm , mpicom, 'restfilm') call shr_mpi_bcast(flds_presaero , mpicom, 'flds_presaero') call shr_mpi_bcast(flds_presndep , mpicom, 'flds_presndep') + call shr_mpi_bcast(flds_preso3 , mpicom, 'flds_preso3') call shr_mpi_bcast(flds_co2 , mpicom, 'flds_co2') call shr_mpi_bcast(flds_wiso , mpicom, 'flds_wiso') call shr_mpi_bcast(skip_restart_read , mpicom, 'skip_restart_read') @@ -294,6 +296,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F00)' factorFn_mesh = ',trim(factorFn_mesh) write(logunit,F02)' flds_presaero = ',flds_presaero write(logunit,F02)' flds_presndep = ',flds_presndep + write(logunit,F02)' flds_preso3 = ',flds_preso3 write(logunit,F02)' flds_co2 = ',flds_co2 write(logunit,F02)' flds_wiso = ',flds_wiso write(logunit,F02)' skip_restart_read = ',skip_restart_read @@ -326,7 +329,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('CLMNCEP') call datm_datamode_clmncep_advertise(exportState, fldsExport, flds_scalar_name, & - flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + flds_co2, flds_wiso, flds_presaero, flds_presndep, flds_preso3, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('CPLHIST') call datm_datamode_cplhist_advertise(exportState, fldsExport, flds_scalar_name, & diff --git a/datm/cime_config/buildnml b/datm/cime_config/buildnml index 2ff95fdbe..575949b10 100755 --- a/datm/cime_config/buildnml +++ b/datm/cime_config/buildnml @@ -76,7 +76,7 @@ def _get_neon_data_availability(case, neonsite): oldestdate = datetime.strptime(neonatm[-10:],"%Y-%m.nc") neonatm = f'cdeps/{version}/{neonsite}/'+neonatm datavaliddate.append(neonatm) - if newestdate: + if newestdate: logger.info("Found tower data version {} for {} through {}".format(version, oldestdate, newestdate)) datavaliddate.sort() return datavaliddate @@ -105,6 +105,7 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path datm_topo = case.get_value("DATM_TOPO") datm_presaero = case.get_value("DATM_PRESAERO") datm_presndep = case.get_value("DATM_PRESNDEP") + datm_preso3 = case.get_value("DATM_PRESO3") datm_co2_tseries = case.get_value("DATM_CO2_TSERIES") atm_grid = case.get_value("ATM_GRID") model_grid = case.get_value("GRID") @@ -116,6 +117,8 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path "A DATM_MODE for CLM is incompatible with DATM_PRESAERO=none.") expect(datm_presndep != "none", "A DATM_MODE for CLM is incompatible with DATM_PRESNDEP=none.") + expect(datm_preso3 != "none", + "A DATM_MODE for CLM is incompatible with DATM_PRESO3=none.") expect(datm_topo != "none", "A DATM_MODE for CLM is incompatible with DATM_TOPO=none.") @@ -124,6 +127,7 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path logger.debug("DATM grid is {}".format(atm_grid)) logger.debug("DATM presaero mode is {}".format(datm_presaero)) logger.debug("DATM presndep mode is {}".format(datm_presndep)) + logger.debug("DATM preso3 mode is {}".format(datm_preso3)) logger.debug("DATM topo mode is {}".format(datm_topo)) # Initialize namelist defaults @@ -143,6 +147,7 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path config['datm_co2_tseries'] = datm_co2_tseries config['datm_presaero'] = datm_presaero config['datm_presndep'] = datm_presndep + config['datm_preso3'] = datm_preso3 if case.get_value('PTS_LON'): scol_lon = float(case.get_value('PTS_LON')) @@ -173,10 +178,13 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path streamlist.append("presaero.{}".format(datm_presaero)) if datm_presndep != "none": streamlist.append("presndep.{}".format(datm_presndep)) + if datm_preso3 != "none": + streamlist.append("preso3.{}".format(datm_preso3)) if datm_topo != "none": streamlist.append("topo.{}".format(datm_topo)) if datm_co2_tseries != "none": streamlist.append("co2tseries.{}".format(datm_co2_tseries)) + bias_correct = nmlgen.get_value("bias_correct") if bias_correct is not None: streamlist.append(bias_correct) @@ -189,10 +197,33 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path schema_file = os.path.join(_CDEPS_CONFIG,"stream_definition_v2.0.xsd") stream_file = os.path.join(_CDEPS_CONFIG,os.pardir, "datm","cime_config","stream_definition_datm.xml") streams = StreamCDEPS(stream_file, schema_file) - streams.create_stream_xml(streamlist, case, outfile, data_list_path, + streams.create_stream_xml(streamlist, case, outfile, data_list_path, os.path.join(caseroot,'user_nl_datm_streams'+inst_string), available_neon_data=available_neon_data) + +#################################################################################### +def _create_drv_flds_in(case, confdir): +#################################################################################### + datm_preso3 = case.get_value("DATM_PRESO3") + + # for now we are hard-coding this file name and values because we only need it for ozone + if datm_preso3 != "none": + + # Generate drv_flds_in file + outfile = os.path.join(confdir, "drv_flds_in") + ozone_nl_name = "&ozone_coupling_nl" + ozone_freq_par = "atm_ozone_frequency" + ozone_freq_val = "'multiday_average'" + nl_fin = "/" + + with open(outfile, "w") as drv_fl: + drv_fl.write("{}\n".format(ozone_nl_name)) + drv_fl.write(" {} = {}\n".format(ozone_freq_par, ozone_freq_val)) + drv_fl.write("{}\n".format(nl_fin)) + + + ############################################################################### def buildnml(case, caseroot, compname): ############################################################################### @@ -267,6 +298,8 @@ def buildnml(case, caseroot, compname): # create namelist and stream file(s) data component _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path) + _create_drv_flds_in(case, confdir) + # copy namelist files and stream text files, to rundir copy_inputs_to_rundir(caseroot, compname, confdir, rundir, inst_string) diff --git a/datm/cime_config/config_component.xml b/datm/cime_config/config_component.xml index eed8a082d..9ff459f51 100644 --- a/datm/cime_config/config_component.xml +++ b/datm/cime_config/config_component.xml @@ -92,7 +92,7 @@ char - none,clim_1850,clim_2000,clim_2010,hist,SSP1-2.6,SSP2-4.5,SSP3-7.0,SSP5-3.4,SSP5-8.5 + none,clim_1850,clim_2000,clim_2010,hist,SSP1-2.6,SSP2-4.5,SSP3-7.0,SSP5-3.4,SSP5-8.5,cplhist clim_2000 clim_1850 @@ -112,6 +112,28 @@ DATM prescribed nitrogen deposition forcing + + char + none,clim_1850,clim_2000,clim_2010,hist,SSP2-4.5,SSP3-7.0,SSP5-8.5 + clim_2000 + + clim_1850 + clim_2000 + clim_2010 + SSP2-4.5 + SSP3-7.0 + SSP5-8.5 + hist + hist + + none + none + + run_component_datm + env_run.xml + DATM prescribed ozone forcing + + char none,observed,cplhist diff --git a/datm/cime_config/namelist_definition_datm.xml b/datm/cime_config/namelist_definition_datm.xml index 3ea0bef64..c677bffe0 100644 --- a/datm/cime_config/namelist_definition_datm.xml +++ b/datm/cime_config/namelist_definition_datm.xml @@ -279,6 +279,19 @@ + + logical + datm + datm_nml + + If true, prescribed o3 is sent from datm (must be true for running with CLM). + + + .true. + .false. + + + logical datm diff --git a/datm/cime_config/stream_definition_datm.xml b/datm/cime_config/stream_definition_datm.xml index d4228d246..c29decdca 100644 --- a/datm/cime_config/stream_definition_datm.xml +++ b/datm/cime_config/stream_definition_datm.xml @@ -187,6 +187,17 @@ presndep.SSP5-8.5 presndep.cplhist + ======================== + optional stream ozone (stream specified by xml variable DATM_PRESO3) + ======================== + preso3.clim_1850 + preso3.clim_2000 + preso3.hist + preso3.SSP2-4.5 + preso3.SSP3-7.0 + preso3.SSP5-8.5 + + ======================== optional stream topo (turned on and stream specified by xml variable DATM_TOPO) ======================== @@ -3999,6 +4010,273 @@ single + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/atm/cam/chem/trop_mozart_aero/aero/aerodep_clm_SSP585_b.e21.BSSP585cmip6.f09_g17.CMIP6-SSP5-8.5.001_2014-2101_monthly_0.9x1.25_c190419.nc + + + BCDEPWET Faxa_bcphiwet + BCPHODRY Faxa_bcphodry + BCPHIDRY Faxa_bcphidry + OCDEPWET Faxa_ocphiwet + OCPHIDRY Faxa_ocphidry + OCPHODRY Faxa_ocphodry + DSTX01WD Faxa_dstwet1 + DSTX01DD Faxa_dstdry1 + DSTX02WD Faxa_dstwet2 + DSTX02DD Faxa_dstdry2 + DSTX03WD Faxa_dstwet3 + DSTX03DD Faxa_dstdry3 + DSTX04WD Faxa_dstwet4 + DSTX04DD Faxa_dstdry4 + + null + + bilinear + + null + 2015 + 2015 + 2101 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1 + 1850 + 1850 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1 + 2000 + 2000 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1 + 2010 + 2010 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-historical-WACCM.001.monthly.185001-201412.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 1850 + 1850 + 2014 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-SSP2-4.5-WACCM.001.monthly.201501-210012.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 2015 + 2015 + 2100 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-SSP3-7.0-WACCM.001.monthly.201501-210012.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 2015 + 2015 + 2100 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + + + $DIN_LOC_ROOT/cdeps/datm/ozone/O3_surface.f09_g17.CMIP6-SSP5-8.5-WACCM.001.monthly.201501-210012.nc + + + O3 Sa_o3 + + null + + bilinear + + null + 2015 + 2015 + 2100 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + @@ -4168,7 +4446,7 @@ $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc - $DIN_LOC_ROOT/lnd/clm2/ndepdata/lnd/clm2/fndepdata/fndep_clm_f09_g17.CMIP6-SSP2-4.5-WACCM_1849-2101_monthly_c191007.nc + $DIN_LOC_ROOT/lnd/clm2/ndepdata/fndep_clm_f09_g17.CMIP6-SSP2-4.5-WACCM_1849-2101_monthly_c191007.nc NDEP_NHx_month Faxa_ndep_nhx diff --git a/datm/datm_datamode_clmncep_mod.F90 b/datm/datm_datamode_clmncep_mod.F90 index 0c4619c01..6c376d902 100644 --- a/datm/datm_datamode_clmncep_mod.F90 +++ b/datm/datm_datamode_clmncep_mod.F90 @@ -36,6 +36,7 @@ module datm_datamode_clmncep_mod real(r8), pointer :: Sa_dens(:) => null() real(r8), pointer :: Sa_pbot(:) => null() real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Sa_o3(:) => null() real(r8), pointer :: Faxa_lwdn(:) => null() real(r8), pointer :: Faxa_rainc(:) => null() real(r8), pointer :: Faxa_rainl(:) => null() @@ -113,7 +114,7 @@ module datm_datamode_clmncep_mod !=============================================================================== subroutine datm_datamode_clmncep_advertise(exportState, fldsexport, flds_scalar_name, & - flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) + flds_co2, flds_wiso, flds_presaero, flds_presndep, flds_preso3, rc) ! input/output variables type(esmf_State) , intent(inout) :: exportState @@ -122,6 +123,7 @@ subroutine datm_datamode_clmncep_advertise(exportState, fldsexport, flds_scalar_ logical , intent(in) :: flds_wiso logical , intent(in) :: flds_presaero logical , intent(in) :: flds_presndep + logical , intent(in) :: flds_preso3 character(len=*) , intent(in) :: flds_scalar_name integer , intent(out) :: rc @@ -157,6 +159,9 @@ subroutine datm_datamode_clmncep_advertise(exportState, fldsexport, flds_scalar_ call dshr_fldList_add(fldsExport, 'Sa_co2prog') call dshr_fldList_add(fldsExport, 'Sa_co2diag') end if + if (flds_preso3) then + call dshr_fldList_add(fldsExport, 'Sa_o3') + end if if (flds_presaero) then call dshr_fldList_add(fldsExport, 'Faxa_bcph' , ungridded_lbound=1, ungridded_ubound=3) call dshr_fldList_add(fldsExport, 'Faxa_ocph' , ungridded_lbound=1, ungridded_ubound=3) @@ -309,6 +314,13 @@ subroutine datm_datamode_clmncep_init_pointers(importState, exportState, sdat, r if (ChkErr(rc,__LINE__,u_FILE_u)) return end if + call ESMF_StateGet(exportstate, 'Sa_o3', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + call dshr_state_getfldptr(exportState, 'Sa_o3', fldptr1=Sa_o3, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + ! error check if (.not. associated(strm_wind) .or. .not. associated(strm_tbot)) then call shr_sys_abort(trim(subname)//' ERROR: wind and tbot must be in streams for CLMNCEP') diff --git a/dlnd/cime_config/config_component.xml b/dlnd/cime_config/config_component.xml index 6fc60c254..ab40fa583 100644 --- a/dlnd/cime_config/config_component.xml +++ b/dlnd/cime_config/config_component.xml @@ -112,6 +112,16 @@ ending year to loop data over (only used when DLND_MODE is CPLHIST or GLC_CPLHIST) + + logical + TRUE,FALSE + FALSE + run_component_dlnd + env_run.xml + If set to true, than dlnd restarts will not be read on a continuation run. + + + ========================================= DLND naming conventions diff --git a/dlnd/cime_config/namelist_definition_dlnd.xml b/dlnd/cime_config/namelist_definition_dlnd.xml index 8fd3b160e..b10350b74 100644 --- a/dlnd/cime_config/namelist_definition_dlnd.xml +++ b/dlnd/cime_config/namelist_definition_dlnd.xml @@ -99,4 +99,17 @@ + + logical + dlnd + dlnd_nml + + If set to true, than dlnd restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DLND_SKIP_RESTART_READ + + + diff --git a/dlnd/lnd_comp_nuopc.F90 b/dlnd/lnd_comp_nuopc.F90 index c97e5906e..cf99994c8 100644 --- a/dlnd/lnd_comp_nuopc.F90 +++ b/dlnd/lnd_comp_nuopc.F90 @@ -79,7 +79,7 @@ module cdeps_dlnd_comp character(CL) :: restfilm = nullstr ! model restart file namelist integer :: nx_global ! global nx dimension of model mesh integer :: ny_global ! global ny dimension of model mesh - + logical :: skip_restart_read = .false. ! true => skip restart read in continuation ! linked lists type(fldList_type) , pointer :: fldsExport => null() type(dfield_type) , pointer :: dfields => null() @@ -173,7 +173,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !------------------------------------------------------------------------------- namelist / dlnd_nml / datamode, model_meshfile, model_maskfile, & - nx_global, ny_global, restfilm, force_prognostic_true + nx_global, ny_global, restfilm, skip_restart_read rc = ESMF_SUCCESS @@ -207,17 +207,17 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call shr_mpi_bcast(nx_global , mpicom, 'nx_global') call shr_mpi_bcast(ny_global , mpicom, 'ny_global') call shr_mpi_bcast(restfilm , mpicom, 'restfilm') - call shr_mpi_bcast(force_prognostic_true , mpicom, 'force_prognostic_true') + call shr_mpi_bcast(skip_restart_read , mpicom, 'skip_restart_read') ! write namelist input to standard out if (my_task == main_task) then - write(logunit,F00)' model_meshfile = ',trim(model_meshfile) - write(logunit,F00)' model_maskfile = ',trim(model_maskfile) - write(logunit ,*)' datamode = ',datamode - write(logunit ,*)' nx_global = ',nx_global - write(logunit ,*)' ny_global = ',ny_global - write(logunit ,*)' restfilm = ',trim(restfilm) - write(logunit ,*)' force_prognostic_true = ',force_prognostic_true + write(logunit,F00)' model_meshfile = ',trim(model_meshfile) + write(logunit,F00)' model_maskfile = ',trim(model_maskfile) + write(logunit,F00)' datamode = ',datamode + write(logunit,F01)' nx_global = ',nx_global + write(logunit,F01)' ny_global = ',ny_global + write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F02)' skip_restart_read = ',skip_restart_read endif ! Validate sdat datamode @@ -278,7 +278,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Read restart if necessary - if (restart_read) then + if (restart_read .and. .not. skip_restart_read) then call dshr_restart_read(restfilm, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) end if diff --git a/docn/cime_config/buildnml b/docn/cime_config/buildnml index 546e43acc..43d221223 100755 --- a/docn/cime_config/buildnml +++ b/docn/cime_config/buildnml @@ -94,6 +94,12 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path if type(streamlist) == type(str()): streamlist = [] + # Determine if skip restart is asked for and if it is a valid request + skip_restart_read = case.get_value('DOCN_SKIP_RESTART_READ') + if skip_restart_read: + if docn_mode == 'som' or docn_mode == 'som_aquap': + expect (False, f"xml variable DOCN_SKIP_RESTART_READ cannot be TRUE for docn_mode {docn_mode}") + # Generate docn.streams.xml if needed print("docn_mode is {}".format(docn_mode)) if (re.search(r'sst_aquap[0-9]+',docn_mode) is not None) or (docn_mode == 'sst_aquap_constant'): diff --git a/docn/cime_config/config_component.xml b/docn/cime_config/config_component.xml index 6c51147ac..2bcd256ba 100644 --- a/docn/cime_config/config_component.xml +++ b/docn/cime_config/config_component.xml @@ -111,7 +111,7 @@ -1 - 300 + 300. run_component_docn env_run.xml @@ -125,6 +125,7 @@ $DIN_LOC_ROOT/ocn/docn7/SOM/default.som.forcing.aquaplanet.Qflux0_h30_sstQOBS.2degFV_c20170421.nc $DIN_LOC_ROOT/ocn/docn7/SOM/default.som.forcing.aquaplanet.Qflux0_h30_sstQOBS.1degFV_c20170421.nc + $DIN_LOC_ROOT/ocn/docn7/SOM/default.som.forcing.aquaplanet.Qflux0_h30_sstQOBS.1degFV_c20170421.nc run_component_docn env_run.xml @@ -248,6 +249,16 @@ This is only used when DOCN_MODE=prescribed. + + logical + TRUE,FALSE + FALSE + run_component_docn + env_run.xml + If set to true, than docn restarts will not be read on a continuation run. + + + ========================================= DOCN naming conventions diff --git a/docn/cime_config/namelist_definition_docn.xml b/docn/cime_config/namelist_definition_docn.xml index c036ccd10..9020ac174 100644 --- a/docn/cime_config/namelist_definition_docn.xml +++ b/docn/cime_config/namelist_definition_docn.xml @@ -186,7 +186,20 @@ -1.0 - $DOCN_AQPCONST_VALUE + $DOCN_AQPCONST_VALUE + + + + + logical + docn + docn_nml + + If set to true, than docn restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DOCN_SKIP_RESTART_READ diff --git a/docn/cime_config/stream_definition_docn.xml b/docn/cime_config/stream_definition_docn.xml index b9b4b41c4..4fb67edea 100644 --- a/docn/cime_config/stream_definition_docn.xml +++ b/docn/cime_config/stream_definition_docn.xml @@ -108,6 +108,7 @@ $DIN_LOC_ROOT/share/meshes/fv1.9x2.5_141008_ESMFmesh.nc $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc + $DIN_LOC_ROOT/share/meshes/fv0.9x1.25_141008_polemod_ESMFmesh.nc $DOCN_SOMAQP_DATAFILE diff --git a/docn/ocn_comp_nuopc.F90 b/docn/ocn_comp_nuopc.F90 index 964beabeb..64fde4257 100644 --- a/docn/ocn_comp_nuopc.F90 +++ b/docn/ocn_comp_nuopc.F90 @@ -96,6 +96,7 @@ module cdeps_docn_comp character(CL) :: restfilm = nullstr ! model restart file namelist integer :: nx_global integer :: ny_global + logical :: skip_restart_read = .false. ! true => skip restart read in continuation run ! linked lists type(fldList_type) , pointer :: fldsImport => null() @@ -191,7 +192,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) namelist / docn_nml / datamode, & model_meshfile, model_maskfile, & - restfilm, nx_global, ny_global, sst_constant_value + restfilm, nx_global, ny_global, sst_constant_value, skip_restart_read rc = ESMF_SUCCESS @@ -227,6 +228,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F01)' nx_global = ',nx_global write(logunit,F01)' ny_global = ',ny_global write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F02)' skip_restart_read = ',skip_restart_read endif ! Broadcast namelist input @@ -237,6 +239,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call shr_mpi_bcast(ny_global , mpicom, 'ny_global') call shr_mpi_bcast(restfilm , mpicom, 'restfilm') call shr_mpi_bcast(sst_constant_value , mpicom, 'sst_constant_value') + call shr_mpi_bcast(skip_restart_read , mpicom, 'skip_restart_read') ! Special logic for prescribed aquaplanet if (datamode(1:9) == 'sst_aquap' .and. trim(datamode) /= 'sst_aquap_constant') then @@ -499,7 +502,7 @@ subroutine docn_comp_run(importState, exportState, clock, target_ymd, target_tod end select ! Read restart if needed - if (restart_read) then + if (restart_read .and. .not. skip_restart_read) then select case (trim(datamode)) case('sstdata', 'sst_aquap_file') call docn_datamode_copyall_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) diff --git a/drof/cime_config/config_component.xml b/drof/cime_config/config_component.xml index 7d0e8a62d..8400ada9d 100644 --- a/drof/cime_config/config_component.xml +++ b/drof/cime_config/config_component.xml @@ -125,6 +125,16 @@ ending year to loop data over (only used when DROF_MODE is CPLHIST) + + logical + TRUE,FALSE + FALSE + run_component_drof + env_run.xml + If set to true, than drof restarts will not be read on a continuation run. + + + ========================================= DROF naming conventions diff --git a/drof/cime_config/namelist_definition_drof.xml b/drof/cime_config/namelist_definition_drof.xml index ead6e9209..846139e12 100644 --- a/drof/cime_config/namelist_definition_drof.xml +++ b/drof/cime_config/namelist_definition_drof.xml @@ -104,4 +104,17 @@ + + logical + drof + drof_nml + + If set to true, than drof restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DROF_SKIP_RESTART_READ + + + diff --git a/drof/rof_comp_nuopc.F90 b/drof/rof_comp_nuopc.F90 index c40f69932..281dc8a38 100644 --- a/drof/rof_comp_nuopc.F90 +++ b/drof/rof_comp_nuopc.F90 @@ -75,7 +75,7 @@ module cdeps_drof_comp character(CL) :: restfilm = nullstr ! model restart file namelist integer :: nx_global integer :: ny_global - + logical :: skip_restart_read = .false. ! true => skip restart read logical :: diagnose_data = .true. integer , parameter :: main_task=0 ! task number of main task character(*) , parameter :: rpfile = 'rpointer.rof' @@ -171,7 +171,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !------------------------------------------------------------------------------- namelist / drof_nml / datamode, model_meshfile, model_maskfile, & - restfilm, nx_global, ny_global + restfilm, nx_global, ny_global, skip_restart_read rc = ESMF_SUCCESS @@ -206,6 +206,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F01)' nx_global = ',nx_global write(logunit,F01)' ny_global = ',ny_global write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F02)' skip_restart_read = ',skip_restart_read end if ! broadcast namelist input @@ -215,6 +216,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call shr_mpi_bcast(nx_global , mpicom, 'nx_global') call shr_mpi_bcast(ny_global , mpicom, 'ny_global') call shr_mpi_bcast(restfilm , mpicom, 'restfilm') + call shr_mpi_bcast(skip_restart_read , mpicom, 'skip_restart_read') ! Validate datamode if (trim(datamode) == 'copyall') then @@ -389,7 +391,7 @@ subroutine drof_comp_run(exportState, target_ymd, target_tod, restart_write, rc) if (chkerr(rc,__LINE__,u_FILE_u)) return ! Read restart if needed - if (restart_read) then + if (restart_read .and. .not. skip_restart_read) then call dshr_restart_read(restfilm, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) end if diff --git a/dwav/cime_config/config_component.xml b/dwav/cime_config/config_component.xml index a3c97663e..9ac5c516e 100644 --- a/dwav/cime_config/config_component.xml +++ b/dwav/cime_config/config_component.xml @@ -36,6 +36,16 @@ DWAV mode + + logical + TRUE,FALSE + FALSE + run_component_dwav + env_run.xml + If set to true, than dwav restarts will not be read on a continuation run. + + + ========================================= DWAV naming conventions diff --git a/dwav/cime_config/namelist_definition_dwav.xml b/dwav/cime_config/namelist_definition_dwav.xml index ca479efbd..16517984f 100644 --- a/dwav/cime_config/namelist_definition_dwav.xml +++ b/dwav/cime_config/namelist_definition_dwav.xml @@ -97,4 +97,17 @@ + + logical + dwav + dwav_nml + + If set to true, than dwav restarts will not be read on a continuation run. + This capability is used, for example, in CTSM spinup runs. + + + $DWAV_SKIP_RESTART_READ + + + diff --git a/dwav/wav_comp_nuopc.F90 b/dwav/wav_comp_nuopc.F90 index 5bbf17106..d16e87775 100644 --- a/dwav/wav_comp_nuopc.F90 +++ b/dwav/wav_comp_nuopc.F90 @@ -76,7 +76,7 @@ module cdeps_dwav_comp character(CL) :: restfilm = nullstr ! model restart file namelist integer :: nx_global integer :: ny_global - + logical :: skip_restart_read = .false. ! true => skip restart read ! constants logical :: diagnose_data = .true. integer , parameter :: main_task=0 ! task number of main task @@ -168,7 +168,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !------------------------------------------------------------------------------- namelist / dwav_nml / datamode, model_meshfile, model_maskfile, & - restfilm, nx_global, ny_global + restfilm, nx_global, ny_global, skip_restart_read rc = ESMF_SUCCESS @@ -203,6 +203,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F01)' nx_global = ',nx_global write(logunit,F01)' ny_global = ',ny_global write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F02)' skip_restart_read = ',skip_restart_read endif ! broadcast namelist input @@ -212,6 +213,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call shr_mpi_bcast(nx_global , mpicom, 'nx_global') call shr_mpi_bcast(ny_global , mpicom, 'ny_global') call shr_mpi_bcast(restfilm , mpicom, 'restfilm') + call shr_mpi_bcast(skip_restart_read , mpicom, 'skip_restart_read') ! Call advertise phase if (trim(datamode) == 'copyall') then @@ -266,7 +268,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Read restart if necessary - if (restart_read) then + if (restart_read .and. .not. skip_restart_read) then call dshr_restart_read(restfilm, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) end if diff --git a/share/shr_cal_mod.F90 b/share/shr_cal_mod.F90 index 086fbec53..a562306f4 100644 --- a/share/shr_cal_mod.F90 +++ b/share/shr_cal_mod.F90 @@ -89,6 +89,7 @@ module shr_cal_mod public :: shr_cal_ymdtod2string ! translate ymdtod to string for filenames public :: shr_cal_datetod2string ! translate date to string for filenames public :: shr_cal_ymds2rday_offset ! translate yr,month,day,sec offset to a fractional day offset + public :: shr_cal_leapyear ! logical function: is this a leap year? ! !PUBLIC DATA MEMBERS: @@ -1410,5 +1411,21 @@ subroutine shr_cal_ymds2rday_offset(etime, rdays_offset, & if(rc /= ESMF_SUCCESS) call ESMF_Finalize(rc=rc, endflag=ESMF_END_ABORT) end subroutine shr_cal_ymds2rday_offset + !=============================================================================== + logical function shr_cal_leapyear(yr) + integer, intent(in) :: yr + shr_cal_leapyear = .false. + if (modulo(yr, 4) == 0) then + if (modulo(yr, 100) == 0) then + if(modulo(yr, 400) == 0) then + shr_cal_leapyear = .true. + endif + else + shr_cal_leapyear = .true. + endif + endif + + end function shr_cal_leapyear + !=============================================================================== end module shr_cal_mod diff --git a/streams/dshr_strdata_mod.F90 b/streams/dshr_strdata_mod.F90 index 27b0c0cb2..19dee6043 100644 --- a/streams/dshr_strdata_mod.F90 +++ b/streams/dshr_strdata_mod.F90 @@ -19,14 +19,14 @@ module dshr_strdata_mod use ESMF , only : ESMF_FieldReGridStore, ESMF_FieldRedistStore, ESMF_UNMAPPEDACTION_IGNORE use ESMF , only : ESMF_TERMORDER_SRCSEQ, ESMF_FieldRegrid, ESMF_FieldFill, ESMF_FieldIsCreated use ESMF , only : ESMF_REGION_TOTAL, ESMF_FieldGet, ESMF_TraceRegionExit, ESMF_TraceRegionEnter - use ESMF , only : ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_RC_ARG_VALUE + use ESMF , only : ESMF_LOGMSG_INFO, ESMF_LogWrite use shr_kind_mod , only : r8=>shr_kind_r8, r4=>shr_kind_r4, i2=>shr_kind_I2 use shr_kind_mod , only : cs=>shr_kind_cs, cl=>shr_kind_cl, cxx=>shr_kind_cxx use shr_sys_mod , only : shr_sys_abort use shr_const_mod , only : shr_const_pi, shr_const_cDay, shr_const_spval use shr_cal_mod , only : shr_cal_calendarname, shr_cal_timeSet use shr_cal_mod , only : shr_cal_noleap, shr_cal_gregorian - use shr_cal_mod , only : shr_cal_date2ymd, shr_cal_ymd2date + use shr_cal_mod , only : shr_cal_date2ymd, shr_cal_ymd2date, shr_cal_leapyear use shr_orb_mod , only : shr_orb_decl, shr_orb_cosz, shr_orb_undef_real #ifdef CESMCOUPLED use shr_pio_mod , only : shr_pio_getiosys, shr_pio_getiotype, shr_pio_getioformat @@ -113,7 +113,6 @@ module dshr_strdata_mod type(shr_strdata_perstream), allocatable :: pstrm(:) ! stream info type(shr_stream_streamType), pointer :: stream(:)=> null() ! stream datatype logical :: mainproc - integer :: logunit ! stdout unit integer :: io_type ! pio info integer :: io_format ! pio info integer :: modeldt = 0 ! model dt in seconds @@ -198,9 +197,6 @@ subroutine shr_strdata_init_from_config(sdat, streamfilename, model_mesh, clock, rc = ESMF_SUCCESS call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) - ! Initialize log unit - sdat%logunit = logunit - #ifdef CESMCOUPLED ! Initialize sdat pio sdat%pio_subsystem => shr_pio_getiosys(trim(compname)) @@ -217,10 +213,10 @@ subroutine shr_strdata_init_from_config(sdat, streamfilename, model_mesh, clock, sdat%mainproc = (localPet == main_task) #ifdef DISABLE_FoX - call shr_stream_init_from_esmfconfig(streamfilename, sdat%stream, sdat%logunit, & + call shr_stream_init_from_esmfconfig(streamfilename, sdat%stream, logunit, & sdat%pio_subsystem, sdat%io_type, sdat%io_format, rc=rc) #else - call shr_stream_init_from_xml(streamfilename, sdat%stream, sdat%mainproc, sdat%logunit, & + call shr_stream_init_from_xml(streamfilename, sdat%stream, sdat%mainproc, logunit, & sdat%pio_subsystem, sdat%io_type, sdat%io_format, trim(compname), rc=rc) #endif @@ -272,9 +268,7 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & rc = ESMF_SUCCESS ! Initialize sdat%logunit and sdat%mainproc - sdat%logunit = logunit sdat%mainproc = (my_task == main_task) - if(sdat%mainproc) print *,__FILE__,__LINE__,'strm logunit is: ',logunit,trim(stream_filenames(1)) #ifdef CESMCOUPLED ! Initialize sdat pio sdat%pio_subsystem => shr_pio_getiosys(trim(compname)) @@ -420,7 +414,7 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) if (filename /= 'none' .and. mainproc) then inquire(file=trim(filename),exist=fileExists) if (.not. fileExists) then - write(sdat%logunit,'(a)') "ERROR: file does not exist: "//trim(fileName) + write(sdat%stream(1)%logunit,'(a)') "ERROR: file does not exist: "//trim(fileName) call shr_sys_abort(subName//"ERROR: file does not exist: "//trim(fileName)) end if endif @@ -452,7 +446,7 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) sdat%pstrm(ns)%stream_ub = 2 allocate(sdat%pstrm(ns)%fldbun_data(2)) if (mainproc) then - write(sdat%logunit,'(a,i8)') trim(subname)//" Creating field bundle array fldbun_data of size 2 for stream ",& + write(sdat%stream(1)%logunit,'(a,i8)') trim(subname)//" Creating field bundle array fldbun_data of size 2 for stream ",& ns end if else if(sdat%stream(ns)%readmode=='full_file') then @@ -479,7 +473,7 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) if (chkerr(rc,__LINE__,u_FILE_u)) return if (mainproc) then if (i == 1) then - write(sdat%logunit,'(a,i8)') " adding field "//trim(sdat%pstrm(ns)%fldlist_model(nfld))//& + write(sdat%stream(1)%logunit,'(a,i8)') " adding field "//trim(sdat%pstrm(ns)%fldlist_model(nfld))//& " to fldbun_data for stream ",ns end if end if @@ -614,12 +608,12 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) end if ! check that stream vector names are valid if (.not. shr_string_listIsValid(stream_vector_names)) then - write(sdat%logunit,*) trim(subname),' vec fldlist invalid m=',m,trim(stream_vector_names) + write(sdat%stream(1)%logunit,*) trim(subname),' vec fldlist invalid m=',m,trim(stream_vector_names) call shr_sys_abort(subname//': vec fldlist invalid:'//trim(stream_vector_names)) endif ! check that only 2 fields are contained for any vector pairing if (shr_string_listGetNum(stream_vector_names) /= 2) then - write(sdat%logunit,*) trim(subname),' vec fldlist ne 2 m=',m,trim(stream_vector_names) + write(sdat%stream(1)%logunit,*) trim(subname),' vec fldlist ne 2 m=',m,trim(stream_vector_names) call shr_sys_abort(subname//': vec fldlist ne 2:'//trim(stream_vector_names)) endif ! create stream vector field @@ -628,7 +622,7 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) ungriddedLbound=(/1/), ungriddedUbound=(/2/), gridToFieldMap=(/2/), rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return if (mainproc) then - write(sdat%logunit,'(a,i8)') "creating ESMF stream vector field with names" //& + write(sdat%stream(1)%logunit,'(a,i8)') "creating ESMF stream vector field with names" //& trim(stream_vector_names)//" for stream ",ns end if end if @@ -653,7 +647,7 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) else call shr_strdata_print(sdat, 'stream_data') end if - write(sdat%logunit,*) ' successfully initialized sdat' + write(sdat%stream(1)%logunit,*) ' successfully initialized sdat' endif end subroutine shr_strdata_init @@ -696,7 +690,7 @@ subroutine shr_strdata_get_stream_nlev(sdat, stream_index, rc) call pio_closefile(pioid) end if if (sdat%mainproc) then - write(sdat%logunit,*) trim(subname)//' stream_nlev = ',stream_nlev + write(sdat%stream(1)%logunit,*) trim(subname)//' stream_nlev = ',stream_nlev end if ! Set stream_nlev in the per-stream sdat info @@ -792,7 +786,14 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) ! on the time series input data. ! ! (0) The stream calendar and model calendar are identical: - ! Proceed in the standard way. + ! In this case it is still possible to have a mismatch if both are gregorian. + ! These cases are: + ! - Model is no_leap, data is Gregorian and leapyear date 2/29 is encountered in data - skip date + ! - Model is Gregorian, data is no_leap and leapyear date 2/29 is encountered in model - repeat 2/28 data + ! - Model is Gregorian, data is gregorian but leapyears do not align. + ! - if in model leap year repeat data from 2/28 + ! - if in data leap year skip date 2/29 + ! ! ! (1) The stream is a no leap calendar and the model is gregorian: ! Time interpolate on the noleap calendar. If the model date is Feb 29, @@ -852,9 +853,11 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) real(r8), pointer :: data_v_dst(:) ! pointer into field bundle type(ESMF_Time) :: timeLB, timeUB ! lb and ub times type(ESMF_TimeInterval) :: timeint ! delta time + character(CL) :: calendar integer :: dday ! delta days real(r8) :: dtime ! delta time integer :: year,month,day ! date year month day + integer :: datayear,datamonth,dataday ! data date year month day integer :: nstreams integer :: stream_index integer :: lsize @@ -892,7 +895,6 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) sdat%ymd = ymd sdat%tod = tod - if (nstreams > 0) then allocate(newData(nstreams)) allocate(ymdmod(nstreams)) @@ -905,6 +907,8 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) ! case(0) ymdmod(ns) = ymd todmod = tod + calendar = trim(sdat%stream(ns)%calendar) + call shr_cal_date2ymd (ymd,year,month,day) if (trim(sdat%model_calendar) /= trim(sdat%stream(ns)%calendar)) then if (( trim(sdat%model_calendar) == trim(shr_cal_gregorian)) .and. & (trim(sdat%stream(ns)%calendar) == trim(shr_cal_noleap))) then @@ -913,17 +917,9 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) if (month == 2 .and. day == 29) then call shr_cal_ymd2date(year,2,28,ymdmod(ns)) endif - else if ((trim(sdat%model_calendar) == trim(shr_cal_noleap)) .and. & - (trim(sdat%stream(ns)%calendar) == trim(shr_cal_gregorian))) then - ! case (2), feb 29 input data will be skipped automatically - else - ! case (3), abort - write(logunit,*) trim(subname),' ERROR: mismatch calendar ', & - trim(sdat%model_calendar),':',trim(sdat%stream(ns)%calendar) - call shr_sys_abort(trim(subname)//' ERROR: mismatch calendar ') + calendar = shr_cal_noleap endif endif - ! --------------------------------------------------------- ! Determine if new data is read in - if so then copy ! fldbun_stream_ub to fldbun_stream_lb and read in new fldbun_stream_ub data @@ -943,9 +939,9 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) end select if (debug > 0 .and. sdat%mainproc) then - write(sdat%logunit,*) trim(subname),' newData flag = ',ns,newData(ns) - write(sdat%logunit,*) trim(subname),' LB ymd,tod = ',ns,sdat%pstrm(ns)%ymdLB,sdat%pstrm(ns)%todLB - write(sdat%logunit,*) trim(subname),' UB ymd,tod = ',ns,sdat%pstrm(ns)%ymdUB,sdat%pstrm(ns)%todUB + write(sdat%stream(1)%logunit,*) trim(subname),' newData flag = ',ns,newData(ns) + write(sdat%stream(1)%logunit,*) trim(subname),' LB ymd,tod = ',ns,sdat%pstrm(ns)%ymdLB,sdat%pstrm(ns)%todLB + write(sdat%stream(1)%logunit,*) trim(subname),' UB ymd,tod = ',ns,sdat%pstrm(ns)%ymdUB,sdat%pstrm(ns)%todUB endif ! --------------------------------------------------------- @@ -953,12 +949,46 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) ! --------------------------------------------------------- if (newData(ns)) then + if (trim(sdat%model_calendar) /= trim(sdat%stream(ns)%calendar)) then + if ((trim(sdat%model_calendar) == trim(shr_cal_noleap)) .and. & + (trim(sdat%stream(ns)%calendar) == trim(shr_cal_gregorian))) then + call shr_cal_date2ymd(sdat%pstrm(ns)%ymdUB, datayear, datamonth, dataday) + if(datamonth==3 .and. dataday==1 .and. month==2 .and. day==28) then + calendar = shr_cal_noleap + endif + ! case (2), feb 29 input data will be skipped automatically + else if (.not. ( trim(sdat%model_calendar) == trim(shr_cal_gregorian)) .and. & + (trim(sdat%stream(ns)%calendar) == trim(shr_cal_noleap))) then + ! case (3), abort + write(logunit,*) trim(subname),' ERROR: mismatch calendar ', & + trim(sdat%model_calendar),':',trim(sdat%stream(ns)%calendar) + call shr_sys_abort(trim(subname)//' ERROR: mismatch calendar ') + endif + else ! calendars are the same + if(trim(sdat%model_calendar) == trim(shr_cal_gregorian)) then + ! Both are in gregorian - but it's possible that there is a mismatch + ! such that the model is in leapyear but the data is not + call shr_cal_date2ymd (ymd,year,month,day) + call shr_cal_date2ymd(sdat%pstrm(ns)%ymdUB, datayear, datamonth, dataday) + if(month == 2 .and. day >= 28) then + if(shr_cal_leapyear(year) .and. .not. shr_cal_leapyear(datayear)) then + ! model is in leap year but data is not + calendar = shr_cal_noleap + endif + else + calendar = sdat%model_calendar + endif + else + calendar = sdat%model_calendar + endif + endif + ! Reset time bounds if newdata read in - call shr_cal_date2ymd(sdat%pstrm(ns)%ymdLB,year,month,day) - call shr_cal_timeSet(timeLB,sdat%pstrm(ns)%ymdLB,0,sdat%stream(ns)%calendar,rc=rc) + call shr_cal_timeSet(timeLB,sdat%pstrm(ns)%ymdLB,0,calendar,rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call shr_cal_timeSet(timeUB,sdat%pstrm(ns)%ymdUB,0,sdat%stream(ns)%calendar,rc=rc) + call shr_cal_timeSet(timeUB,sdat%pstrm(ns)%ymdUB,0,calendar,rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + timeint = timeUB-timeLB call ESMF_TimeIntervalGet(timeint, StartTimeIn=timeLB, d=dday) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -969,13 +999,14 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) if ((sdat%pstrm(ns)%dtmax/sdat%pstrm(ns)%dtmin) > sdat%stream(ns)%dtlimit) then if (sdat%mainproc) then - write(sdat%logunit,*) trim(subname),' ERROR: for stream ',ns - write(sdat%logunit,*) trim(subName),' ERROR: dtime, dtmax, dtmin, dtlimit = ',& + write(sdat%stream(1)%logunit,*) trim(subname),' ERROR: for stream ',ns + write(sdat%stream(1)%logunit,*) trim(subname),' ERROR: dday = ',dday + write(sdat%stream(1)%logunit,*) trim(subName),' ERROR: dtime, dtmax, dtmin, dtlimit = ',& dtime, sdat%pstrm(ns)%dtmax, sdat%pstrm(ns)%dtmin, sdat%stream(ns)%dtlimit - write(sdat%logunit,*) trim(subName),' ERROR: ymdLB, todLB, ymdUB, todUB = ', & + write(sdat%stream(1)%logunit,*) trim(subName),' ERROR: ymdLB, todLB, ymdUB, todUB = ', & sdat%pstrm(ns)%ymdLB, sdat%pstrm(ns)%todLB, sdat%pstrm(ns)%ymdUB, sdat%pstrm(ns)%todUB end if - write(6,*) trim(subname),' ERROR: for stream ',ns + write(6,*) trim(subname),' ERROR: for stream ',ns, ' and calendar ',trim(calendar) write(6,*) trim(subName),' ERROR: dtime, dtmax, dtmin, dtlimit = ',& dtime, sdat%pstrm(ns)%dtmax, sdat%pstrm(ns)%dtmin, sdat%stream(ns)%dtlimit write(6,*) trim(subName),' ERROR: ymdLB, todLB, ymdUB, todUB = ', & @@ -1009,11 +1040,11 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) call ESMF_TraceRegionEnter(trim(lstr)//trim(timname)//'_coszenC') call shr_tInterp_getCosz(coszen, sdat%model_lon, sdat%model_lat, ymdmod(ns), todmod, & sdat%eccen, sdat%mvelpp, sdat%lambm0, sdat%obliqr, sdat%stream(ns)%calendar, & - sdat%mainproc, sdat%logunit) + sdat%mainproc, sdat%stream(1)%logunit) call ESMF_TraceRegionExit(trim(lstr)//trim(timname)//'_coszenC') if (debug > 0 .and. sdat%mainproc) then do n = 1,size(coszen) - write(sdat%logunit,'(a,i4,2x,2(i18,2x),i8,d20.10)')' stream,ymdmod,todmod,n,coszen= ',& + write(sdat%stream(1)%logunit,'(a,i4,2x,2(i18,2x),i8,d20.10)')' stream,ymdmod,todmod,n,coszen= ',& ns, ymd, tod, n, coszen(n) end do end if @@ -1028,11 +1059,11 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) call shr_tInterp_getAvgCosz(sdat%tavCoszen, sdat%model_lon, sdat%model_lat, & sdat%pstrm(ns)%ymdLB, sdat%pstrm(ns)%todLB, sdat%pstrm(ns)%ymdUB, sdat%pstrm(ns)%todUB, & sdat%eccen, sdat%mvelpp, sdat%lambm0, sdat%obliqr, sdat%modeldt, & - sdat%stream(ns)%calendar, sdat%mainproc, sdat%logunit, rc=rc) + sdat%stream(ns)%calendar, sdat%mainproc, sdat%stream(1)%logunit, rc=rc) call ESMF_TraceRegionExit(trim(lstr)//trim(timname)//'_coszenN') if (debug > 0 .and. sdat%mainproc) then do n = 1,size(coszen) - write(sdat%logunit,'(a,i4,2x,4(i18,2x),i8,d20.10)')' stream,lbymd,lbsec,ubymd,ubsec,newdata,n,tavgCoszen= ',& + write(sdat%stream(1)%logunit,'(a,i4,2x,4(i18,2x),i8,d20.10)')' stream,lbymd,lbsec,ubymd,ubsec,newdata,n,tavgCoszen= ',& ns, sdat%pstrm(ns)%ymdLB, sdat%pstrm(ns)%todLB, sdat%pstrm(ns)%ymdUB, sdat%pstrm(ns)%todUB, & n, sdat%tavCoszen(n) end do @@ -1084,11 +1115,11 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) call ESMF_TraceRegionEnter(trim(lstr)//trim(timname)//'_tint') call shr_tInterp_getFactors(sdat%pstrm(ns)%ymdlb, sdat%pstrm(ns)%todlb, & sdat%pstrm(ns)%ymdub, sdat%pstrm(ns)%todub, & - ymdmod(ns), todmod, flb, fub, calendar=sdat%stream(ns)%calendar, logunit=sdat%logunit, & + ymdmod(ns), todmod, flb, fub, calendar=sdat%stream(ns)%calendar, logunit=sdat%stream(1)%logunit, & algo=trim(sdat%stream(ns)%tinterpalgo), rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return if (debug > 0 .and. sdat%mainproc) then - write(sdat%logunit,'(a,i4,2(f10.5,2x))') & + write(sdat%stream(1)%logunit,'(a,i4,2(f10.5,2x))') & trim(subname)//' non-cosz-interp stream, flb, fub= ',ns,flb,fub endif do nf = 1,size(sdat%pstrm(ns)%fldlist_model) @@ -1198,27 +1229,27 @@ subroutine shr_strdata_print(sdat, name) character(*),parameter :: F90 = "('(shr_strdata_print) ',58('-'))" !------------------------------------------------------------------------------- - write(sdat%logunit,*) - write(sdat%logunit,F90) - write(sdat%logunit,F00) "name = ",trim(name) - write(sdat%logunit,F00) "calendar = ",trim(sdat%model_calendar) - write(sdat%logunit,F02) "eccen = ",sdat%eccen - write(sdat%logunit,F02) "mvelpp = ",sdat%mvelpp - write(sdat%logunit,F02) "lambm0 = ",sdat%lambm0 - write(sdat%logunit,F02) "obliqr = ",sdat%obliqr - write(sdat%logunit,F01) "pio_iotype = ",sdat%io_type - write(sdat%logunit,F01) "nstreams = ",shr_strdata_get_stream_count(sdat) - write(sdat%logunit,F05) "Per stream information " + write(sdat%stream(1)%logunit,*) + write(sdat%stream(1)%logunit,F90) + write(sdat%stream(1)%logunit,F00) "name = ",trim(name) + write(sdat%stream(1)%logunit,F00) "calendar = ",trim(sdat%model_calendar) + write(sdat%stream(1)%logunit,F02) "eccen = ",sdat%eccen + write(sdat%stream(1)%logunit,F02) "mvelpp = ",sdat%mvelpp + write(sdat%stream(1)%logunit,F02) "lambm0 = ",sdat%lambm0 + write(sdat%stream(1)%logunit,F02) "obliqr = ",sdat%obliqr + write(sdat%stream(1)%logunit,F01) "pio_iotype = ",sdat%io_type + write(sdat%stream(1)%logunit,F01) "nstreams = ",shr_strdata_get_stream_count(sdat) + write(sdat%stream(1)%logunit,F05) "Per stream information " do ns = 1, shr_strdata_get_stream_count(sdat) - write(sdat%logunit,F04) " taxMode (",ns,") = ",trim(sdat%stream(ns)%taxmode) - write(sdat%logunit,F07) " dtlimit (",ns,") = ",sdat%stream(ns)%dtlimit - write(sdat%logunit,F04) " mapalgo (",ns,") = ",trim(sdat%stream(ns)%mapalgo) - write(sdat%logunit,F04) " tintalgo(",ns,") = ",trim(sdat%stream(ns)%tinterpalgo) - write(sdat%logunit,F04) " readmode(",ns,") = ",trim(sdat%stream(ns)%readmode) - write(sdat%logunit,F04) " vectors (",ns,") = ",trim(sdat%stream(ns)%stream_vectors) - write(sdat%logunit,F01) " " + write(sdat%stream(1)%logunit,F04) " taxMode (",ns,") = ",trim(sdat%stream(ns)%taxmode) + write(sdat%stream(1)%logunit,F07) " dtlimit (",ns,") = ",sdat%stream(ns)%dtlimit + write(sdat%stream(1)%logunit,F04) " mapalgo (",ns,") = ",trim(sdat%stream(ns)%mapalgo) + write(sdat%stream(1)%logunit,F04) " tintalgo(",ns,") = ",trim(sdat%stream(ns)%tinterpalgo) + write(sdat%stream(1)%logunit,F04) " readmode(",ns,") = ",trim(sdat%stream(ns)%readmode) + write(sdat%stream(1)%logunit,F04) " vectors (",ns,") = ",trim(sdat%stream(ns)%stream_vectors) + write(sdat%stream(1)%logunit,F01) " " end do - write(sdat%logunit,F90) + write(sdat%stream(1)%logunit,F90) end subroutine shr_strdata_print @@ -1289,11 +1320,11 @@ subroutine shr_strdata_readLBUB(sdat, ns, mDate, mSec, newData, istr, rc) ! if model current date is outside of model lower or upper bound - find the stream bounds find_bounds = (rDateM < rDateLB .or. rDateM >= rDateUB) if (debug > 0 .and. sdat%mainproc) then - write(sdat%logunit,'(a,i4,2x,6(i18,2x),l7)')' stream,lbymd,lbsec,mdate,msec,ubymd,ubsec,newdata= ',ns,& + write(sdat%stream(1)%logunit,'(a,i4,2x,6(i18,2x),l7)')' stream,lbymd,lbsec,mdate,msec,ubymd,ubsec,newdata= ',ns,& sdat%pstrm(ns)%ymdLB,sdat%pstrm(ns)%todLB, & mdate,msec, & sdat%pstrm(ns)%ymdUB,sdat%pstrm(ns)%todUB,find_bounds - write(sdat%logunit,'(a,i4,2x,3(f20.3,2x),l7)')' stream,rdateLB,rdateM,rdateUB,newdata= ',& + write(sdat%stream(1)%logunit,'(a,i4,2x,3(f20.3,2x),l7)')' stream,rdateLB,rdateM,rdateUB,newdata= ',& ns,rdateLB,rdateM,rdateUB,find_bounds end if if (find_bounds) then @@ -1303,11 +1334,11 @@ subroutine shr_strdata_readLBUB(sdat, ns, mDate, mSec, newData, istr, rc) sdat%pstrm(ns)%ymdUB, dDateUB, sdat%pstrm(ns)%todUB, n_ub, filename_ub) call ESMF_TraceRegionExit(trim(istr)//'_fbound') if (debug > 0 .and. sdat%mainproc) then - write(sdat%logunit,'(a,i4,2x,6(i18,2x),l7)')' stream,lbymd,lbsec,mdate,msec,ubymd,ubsec,newdata= ',ns,& + write(sdat%stream(1)%logunit,'(a,i4,2x,6(i18,2x),l7)')' stream,lbymd,lbsec,mdate,msec,ubymd,ubsec,newdata= ',ns,& sdat%pstrm(ns)%ymdLB,sdat%pstrm(ns)%todLB,& mdate,msec, & sdat%pstrm(ns)%ymdUB,sdat%pstrm(ns)%todUB - write(sdat%logunit,'(a,i4,2x,3(f20.3,2x),l7)')' stream,rdateLB,rdateM,rdateUB,newdata= ',& + write(sdat%stream(1)%logunit,'(a,i4,2x,3(f20.3,2x),l7)')' stream,rdateLB,rdateM,rdateUB,newdata= ',& ns,rdateLB,rdateM,rdateUB,find_bounds end if endif @@ -1433,7 +1464,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & if (sdat%mainproc) then inquire(file=trim(fileName),exist=fileExists) if (.not. fileExists) then - write(sdat%logunit,F00) "ERROR: file does not exist: ", trim(fileName) + write(sdat%stream(1)%logunit,F00) "ERROR: file does not exist: ", trim(fileName) call shr_sys_abort(subName//"ERROR: file does not exist: "//trim(fileName)) end if endif @@ -1446,10 +1477,10 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & else ! otherwise close the old file if open and open new file if (fileopen) then - if (sdat%mainproc) write(sdat%logunit,F00) 'close : ',trim(currfile) + if (sdat%mainproc) write(sdat%stream(1)%logunit,F00) 'close : ',trim(currfile) call pio_closefile(pioid) endif - if (sdat%mainproc) write(sdat%logunit,F00) 'opening : ',trim(filename) + if (sdat%mainproc) write(sdat%stream(1)%logunit,F00) 'opening : ',trim(filename) rcode = pio_openfile(sdat%pio_subsystem, pioid, sdat%io_type, trim(filename), pio_nowrite) call shr_stream_setCurrFile(stream, fileopen=.true., currfile=trim(filename), currpioid=pioid) endif @@ -1462,7 +1493,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & if (ESMF_MeshIsCreated(per_stream%stream_mesh)) then if (.not. per_stream%stream_pio_iodesc_set) then - if (sdat%mainproc) write(sdat%logunit,F00) 'setting pio descriptor : ',trim(filename) + if (sdat%mainproc) write(sdat%stream(1)%logunit,F00) 'setting pio descriptor : ',trim(filename) call shr_strdata_set_stream_iodesc(sdat, per_stream, trim(per_stream%fldlist_stream(1)), & pioid, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return @@ -1492,7 +1523,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & call ESMF_TraceRegionEnter(trim(istr)//'_readpio') if (sdat%mainproc) then - write(sdat%logunit,F02) 'reading file ' // trim(boundstr) //': ',trim(filename), nt + write(sdat%stream(1)%logunit,F02) 'reading file ' // trim(boundstr) //': ',trim(filename), nt endif if (ESMF_FieldIsCreated(per_stream%field_stream_vector)) then @@ -1551,7 +1582,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & call PIO_seterrorhandling(pioid, old_error_handle) if (debug>0 .and. sdat%mainproc) then - write(sdat%logunit,F02)' reading '//& + write(sdat%stream(1)%logunit,F02)' reading '//& trim(per_stream%fldlist_stream(nf))//' into '//trim(per_stream%fldlist_model(nf)),& ' at time index: ',nt end if @@ -1575,7 +1606,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & ! Single point streams are not allowed to have missing values if (stream%mapalgo == 'none' .and. any(data_real2d == fillvalue_r4)) then write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) - if(sdat%mainproc) write(sdat%logunit,*) trim(errmsg) + if(sdat%mainproc) write(sdat%stream(1)%logunit,*) trim(errmsg) call shr_sys_abort(errmsg) endif do lev = 1,stream_nlev @@ -1607,7 +1638,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & ! Single point streams are not allowed to have missing values if (stream%mapalgo == 'none' .and. any(data_real1d == fillvalue_r4)) then write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) - if(sdat%mainproc) write(sdat%logunit,*) trim(errmsg) + if(sdat%mainproc) write(sdat%stream(1)%logunit,*) trim(errmsg) call shr_sys_abort(errmsg) endif @@ -1640,7 +1671,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & ! Single point streams are not allowed to have missing values if (stream%mapalgo == 'none' .and. any(data_dbl2d == fillvalue_r8)) then write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) - if(sdat%mainproc) write(sdat%logunit,*) trim(errmsg) + if(sdat%mainproc) write(sdat%stream(1)%logunit,*) trim(errmsg) call shr_sys_abort(errmsg) endif do lev = 1,stream_nlev @@ -1672,7 +1703,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & ! Single point streams are not allowed to have missing values if (stream%mapalgo == 'none' .and. any(data_dbl1d == fillvalue_r8)) then write(errmsg,*) ' ERROR: _Fillvalue found in stream input variable: '// trim(per_stream%fldlist_stream(nf)) - if(sdat%mainproc) write(sdat%logunit,*) trim(errmsg) + if(sdat%mainproc) write(sdat%stream(1)%logunit,*) trim(errmsg) call shr_sys_abort(errmsg) endif do n = 1,size(dataptr1d) @@ -1926,7 +1957,7 @@ subroutine shr_strdata_set_stream_iodesc(sdat, per_stream, fldname, pioid, rc) ! determine io descriptor if (ndims == 2) then if (sdat%mainproc) then - write(sdat%logunit,F00) 'setting iodesc for : '//trim(fldname)// & + write(sdat%stream(1)%logunit,F00) 'setting iodesc for : '//trim(fldname)// & ' with dimlens(1), dimlens2 = ',dimlens(1),dimlens(2),& ' variable has no time dimension ' end if @@ -1936,14 +1967,14 @@ subroutine shr_strdata_set_stream_iodesc(sdat, per_stream, fldname, pioid, rc) else if (ndims == 3) then rcode = pio_inq_dimname(pioid, dimids(ndims), dimname) if (stream_nlev > 1) then - write(sdat%logunit,F01) 'setting iodesc for : '//trim(fldname)// & + write(sdat%stream(1)%logunit,F01) 'setting iodesc for : '//trim(fldname)// & ' with dimlens(1), dimlens(2), dimlens(3) = ',dimlens(1),dimlens(2), dimlens(3), & ' variable has no time dimension '//trim(dimname) call pio_initdecomp(sdat%pio_subsystem, pio_iovartype, (/dimlens(1),dimlens(2),dimlens(3)/), compdof3d, & per_stream%stream_pio_iodesc) else if (trim(dimname) == 'time' .or. trim(dimname) == 'nt') then if (sdat%mainproc) then - write(sdat%logunit,F01) 'setting iodesc for : '//trim(fldname)// & + write(sdat%stream(1)%logunit,F01) 'setting iodesc for : '//trim(fldname)// & ' with dimlens(1), dimlens(2) = ',dimlens(1),dimlens(2),& ' variable as time dimension '//trim(dimname) end if @@ -1955,7 +1986,7 @@ subroutine shr_strdata_set_stream_iodesc(sdat, per_stream, fldname, pioid, rc) rcode = pio_inq_dimname(pioid, dimids(ndims), dimname) if (stream_nlev > 1 .and. (trim(dimname) == 'time' .or. trim(dimname) == 'nt')) then if (sdat%mainproc) then - write(sdat%logunit,F02) 'setting iodesc for : '//trim(fldname)// & + write(sdat%stream(1)%logunit,F02) 'setting iodesc for : '//trim(fldname)// & ' with dimlens(1), dimlens(2),dimlens(3) = ',dimlens(1),dimlens(2),dimlens(3),& ' variable has time dimension ' end if @@ -2009,7 +2040,7 @@ subroutine shr_strdata_get_stream_pointer_1d(sdat, strm_fld, strm_ptr, rc) fldptr1=strm_ptr, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return if (sdat%mainproc) then - write(sdat%logunit,F00)' strm_ptr is allocated for stream field strm_'//trim(strm_fld) + write(sdat%stream(1)%logunit,F00)' strm_ptr is allocated for stream field strm_'//trim(strm_fld) end if found = .true. exit @@ -2049,7 +2080,7 @@ subroutine shr_strdata_get_stream_pointer_2d(sdat, strm_fld, strm_ptr, rc) fldptr2=strm_ptr, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return if (sdat%mainproc) then - write(sdat%logunit,F00)' strm_ptr is allocated for stream field strm_'//trim(strm_fld) + write(sdat%stream(1)%logunit,F00)' strm_ptr is allocated for stream field strm_'//trim(strm_fld) end if found = .true. exit diff --git a/streams/dshr_stream_mod.F90 b/streams/dshr_stream_mod.F90 index 08f7dfd33..63d9cdb05 100644 --- a/streams/dshr_stream_mod.F90 +++ b/streams/dshr_stream_mod.F90 @@ -25,6 +25,7 @@ module dshr_stream_mod use shr_cal_mod , only : shr_cal_calendarName use shr_cal_mod , only : shr_cal_advDate use shr_cal_mod , only : shr_cal_advdateint + use shr_cal_mod , only : shr_cal_leapyear use dshr_methods_mod , only : chkerr use pio , only : pio_noerr, pio_seterrorhandling, pio_inq_att, pio_openfile, pio_closefile use pio , only : file_desc_t, pio_inq_varid, iosystem_desc_t, pio_file_is_open @@ -414,19 +415,19 @@ subroutine shr_stream_init_from_xml(streamfilename, streamdat, isroot_task, logu streamdat(i)%pio_iotype = io_type streamdat(i)%pio_ioformat = io_format #endif + ! Set logunit + streamdat(i)%logunit = logunit + call shr_stream_getCalendar(streamdat(i), 1, streamdat(i)%calendar) ! Error check if (trim(streamdat(i)%taxmode) == shr_stream_taxis_extend .and. streamdat(i)%dtlimit < 1.e10) then call shr_sys_abort(trim(subName)//" ERROR: if taxmode value is extend set dtlimit to 1.e30") end if + ! initialize flag that stream has been set + streamdat(i)%init = .true. enddo - ! Set logunit - streamdat(:)%logunit = logunit - - ! initialize flag that stream has been set - streamdat(:)%init = .true. end subroutine shr_stream_init_from_xml @@ -523,13 +524,12 @@ subroutine shr_stream_init_from_inline(streamdat, & streamdat(1)%varlist(n)%nameinmodel = trim(stream_fldlistModel(n)) end do + ! Initialize logunit + streamdat(:)%logunit = logunit ! Get stream calendar call shr_stream_getCalendar(streamdat(1), 1, calendar) streamdat(1)%calendar = trim(calendar) - ! Initialize logunit - streamdat(1)%logunit = logunit - ! Initialize flag that stream has been set streamdat(1)%init = .true. @@ -707,6 +707,9 @@ subroutine shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, streamdat(i)%pio_subsystem => pio_subsystem streamdat(i)%pio_iotype = io_type streamdat(i)%pio_ioformat = io_format + ! Set logunit + streamdat(i)%logunit = logunit + call shr_stream_getCalendar(streamdat(i), 1, streamdat(i)%calendar) ! Error check @@ -716,9 +719,6 @@ subroutine shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, enddo ! end loop nstrm - ! Set logunit - streamdat(:)%logunit = logunit - ! initialize flag that stream has been set streamdat(:)%init = .true. @@ -819,6 +819,9 @@ subroutine shr_stream_findBounds(strm, mDateIn, secIn, isroot_task, & if (cycle) then dYear = yrFirst + modulo(mYear-yrAlign+(2*nYears),nYears) ! current data year + if(debug>0 .and. isroot_task) then + write(strm%logunit, *) trim(subname), ' dyear, yrfirst, myear, yralign, nyears =', dyear, yrfirst, myear, yralign, nyears + endif else dYear = yrFirst + mYear - yrAlign endif @@ -1160,6 +1163,11 @@ subroutine shr_stream_findBounds(strm, mDateIn, secIn, isroot_task, & dDateUB = strm%file(k_ub)%date(n_ub) call shr_cal_date2ymd(dDateUB,yy,mm,dd) yy = yy + (mYear-dYear) + if(mm == 2 .and. dd==29 .and. .not. shr_cal_leapyear(yy)) then + if(isroot_task) write(strm%logunit, *) 'Found leapyear mismatch', myear, dyear, yy + mm = 3 + dd = 1 + endif call shr_cal_ymd2date(yy,mm,dd,mDateUB) secUB = strm%file(k_ub)%secs(n_ub) fileUB = strm%file(k_ub)%name @@ -1468,6 +1476,7 @@ end subroutine shr_stream_getStreamFieldList !=============================================================================== subroutine shr_stream_getCalendar(strm, k, calendar) use pio, only : PIO_set_log_level, PIO_OFFSET_KIND + use ESMF, only: ESMF_VM, ESMF_VMGet, ESMF_VMGetCurrent ! Returns calendar name ! input/output parameters: @@ -1476,6 +1485,8 @@ subroutine shr_stream_getCalendar(strm, k, calendar) character(*) ,intent(out) :: calendar ! calendar name ! local + type(ESMF_VM) :: vm + integer :: myid integer :: vid, n character(CL) :: fileName character(CL) :: lcal @@ -1483,6 +1494,7 @@ subroutine shr_stream_getCalendar(strm, k, calendar) integer :: old_handle integer :: rCode integer :: ierr + integer :: rc character(*),parameter :: subName = '(shr_stream_getCalendar) ' !------------------------------------------------------------------------------- @@ -1490,12 +1502,18 @@ subroutine shr_stream_getCalendar(strm, k, calendar) calendar = ' ' if (k > strm%nfiles) call shr_sys_abort(subname//' ERROR: k gt nfiles') + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMGet(vm, localPet=myid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + fileName = strm%file(k)%name - ! TODO strm logunit is not set + if (.not. pio_file_is_open(strm%file(k)%fileid)) then - if(strm%logunit /= 6) write(strm%logunit, '(a)') trim(subname)//' opening stream filename = '//trim(filename) + if(myid == 0) write(strm%logunit, '(a)') trim(subname)//' opening stream filename = '//trim(filename) rcode = pio_openfile(strm%pio_subsystem, strm%file(k)%fileid, strm%pio_iotype, trim(filename)) - else if(strm%logunit /= 6) then + else if(myid == 0) then write(strm%logunit, '(a)') trim(subname)//' reading stream filename = '//trim(filename) endif @@ -1523,8 +1541,8 @@ subroutine shr_stream_getCalendar(strm, k, calendar) call shr_string_leftalign_and_convert_tabs(lcal) calendar = trim(shr_cal_calendarName(trim(lcal))) - ! TODO: add isroot_task - !write(strm%logunit, '(a)') trim(subname)//' closing stream filename = '//trim(filename) + + if(myid == 0) write(strm%logunit, '(a)') trim(subname)//' closing stream filename = '//trim(filename) call pio_closefile(strm%file(k)%fileid) end subroutine shr_stream_getCalendar @@ -1709,9 +1727,11 @@ subroutine shr_stream_restIO(pioid, streams, mode) rcode = pio_def_dim(pioid, 'strlen', CL, dimid_str) do k=1,size(streams) + ! maxnfiles is the maximum number of files across all streams if (streams(k)%nfiles > maxnfiles) then maxnfiles = streams(k)%nfiles endif + ! maxnt is the maximum number of time samples across all possible stream files do n=1,streams(k)%nFiles if( streams(k)%file(n)%nt > maxnt) then maxnt = streams(k)%file(n)%nt From 0d073f8e349cfdbe5bd91f1fa296a9d3706ba412 Mon Sep 17 00:00:00 2001 From: "Bin.Li" Date: Mon, 30 Jan 2023 13:53:58 +0000 Subject: [PATCH 08/28] update datm/datm_datamode_gfs_mod.F90 --- datm/datm_datamode_gfs_mod.F90 | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/datm/datm_datamode_gfs_mod.F90 b/datm/datm_datamode_gfs_mod.F90 index 79c2c36e8..cc4b05fa4 100644 --- a/datm/datm_datamode_gfs_mod.F90 +++ b/datm/datm_datamode_gfs_mod.F90 @@ -5,7 +5,6 @@ module datm_datamode_gfs_mod use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs use shr_sys_mod , only : shr_sys_abort use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp - use shr_mpi_mod , only : shr_mpi_max use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair use dshr_methods_mod , only : dshr_state_getfldptr, chkerr use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer @@ -166,7 +165,7 @@ end subroutine datm_datamode_gfs_init_pointers !=============================================================================== subroutine datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) - + use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MAX, ESMF_VM ! input/output variables type(ESMF_State) , intent(inout) :: exportState logical , intent(in) :: mainproc @@ -181,8 +180,8 @@ subroutine datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, tar logical :: first_time = .true. integer :: n ! indices integer :: lsize ! size of attr vect - real(r8) :: rtmp - real(r8) :: tbot, pbot + real(r8) :: rtmp(2) + type(ESMF_VM) :: vm character(len=*), parameter :: subname='(datm_datamode_gfs_advance): ' !------------------------------------------------------------------------------- @@ -191,14 +190,18 @@ subroutine datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, tar lsize = size(strm_mask) if (first_time) then + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return ! determine tbotmax (see below for use) - rtmp = maxval(Sa_tbot(:)) - call shr_mpi_max(rtmp, tbotmax, mpicom, 'datm_tbot', all=.true.) + rtmp(1) = maxval(Sa_tbot(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + tbotmax = rtmp(2) if (mainproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax ! determine maskmax (see below for use) - rtmp = maxval(strm_mask(:)) - call shr_mpi_max(rtmp, maskmax, mpicom, 'datm_mask', all=.true.) + rtmp(1) = maxval(strm_mask(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + maskmax = rtmp(2) if (mainproc) write(logunit,*) trim(subname),' maskmax = ',maskmax ! reset first_time From 2aa6bfbb62ebeecd7da964b8074f6c3c41c7d1eb Mon Sep 17 00:00:00 2001 From: BinLi-NOAA Date: Thu, 25 May 2023 07:24:52 -0400 Subject: [PATCH 09/28] Update CDEPS to include the GFS_HAFS datamode (#55) --- datm/CMakeLists.txt | 1 + datm/atm_comp_nuopc.F90 | 23 +++ datm/datm_datamode_gfs_hafs_mod.F90 | 230 ++++++++++++++++++++++++++++ 3 files changed, 254 insertions(+) create mode 100644 datm/datm_datamode_gfs_hafs_mod.F90 diff --git a/datm/CMakeLists.txt b/datm/CMakeLists.txt index 023a8f35a..f25ad9f4d 100644 --- a/datm/CMakeLists.txt +++ b/datm/CMakeLists.txt @@ -7,6 +7,7 @@ set(SRCFILES atm_comp_nuopc.F90 datm_datamode_gefs_mod.F90 datm_datamode_cfsr_mod.F90 datm_datamode_gfs_mod.F90 + datm_datamode_gfs_hafs_mod.F90 datm_datamode_era5_mod.F90) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 0e2c8b59b..82703ba64 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -88,6 +88,12 @@ module cdeps_datm_comp use datm_datamode_gfs_mod , only : datm_datamode_gfs_restart_write use datm_datamode_gfs_mod , only : datm_datamode_gfs_restart_read + use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_advertise + use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_init_pointers + use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_advance + use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_write + use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_read + implicit none private ! except @@ -353,6 +359,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) trim(datamode) == 'GEFS' .or. & trim(datamode) == 'CFSR' .or. & trim(datamode) == 'GFS' .or. & + trim(datamode) == 'GFS_HAFS' .or. & trim(datamode) == 'ERA5') then else call shr_sys_abort(' ERROR illegal datm datamode = '//trim(datamode)) @@ -388,6 +395,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) case ('GFS') call datm_datamode_gfs_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('GFS_HAFS') + call datm_datamode_gfs_hafs_advertise(exportState, fldsExport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end subroutine InitializeAdvertise @@ -634,6 +644,9 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('GFS') call datm_datamode_gfs_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GFS_HAFS') + call datm_datamode_gfs_hafs_init_pointers(exportState, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Read restart if needed @@ -655,6 +668,8 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_cfsr_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) case('GFS') call datm_datamode_gfs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) + case('GFS_HAFS') + call datm_datamode_gfs_hafs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) end select end if @@ -713,6 +728,10 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & target_tod, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GFS_HAFS') + call datm_datamode_gfs_hafs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & + target_tod, sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Write restarts if needed @@ -745,6 +764,10 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_gfs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('GFS_HAFS') + call datm_datamode_gfs_hafs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & + logunit, my_task, sdat) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end if diff --git a/datm/datm_datamode_gfs_hafs_mod.F90 b/datm/datm_datamode_gfs_hafs_mod.F90 new file mode 100644 index 000000000..9e6805071 --- /dev/null +++ b/datm/datm_datamode_gfs_hafs_mod.F90 @@ -0,0 +1,230 @@ +module datm_datamode_gfs_hafs_mod + + use ESMF , only : ESMF_State, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp + use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_mod , only : dshr_restart_read, dshr_restart_write + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_gfs_hafs_advertise + public :: datm_datamode_gfs_hafs_init_pointers + public :: datm_datamode_gfs_hafs_advance + public :: datm_datamode_gfs_hafs_restart_write + public :: datm_datamode_gfs_hafs_restart_read + + ! export state data + real(r8), pointer :: Sd_pslv(:) => null() + real(r8), pointer :: Sd_u10m(:) => null() + real(r8), pointer :: Sd_v10m(:) => null() + real(r8), pointer :: Faxd_swvdr(:) => null() + real(r8), pointer :: Faxd_swvdf(:) => null() + real(r8), pointer :: Faxd_swndr(:) => null() + real(r8), pointer :: Faxd_swndf(:) => null() + real(r8), pointer :: Faxd_lwnet(:) => null() + real(r8), pointer :: Faxd_taux(:) => null() + real(r8), pointer :: Faxd_tauy(:) => null() + real(r8), pointer :: Faxd_sen(:) => null() + real(r8), pointer :: Faxd_lat(:) => null() + real(r8), pointer :: Faxd_rain(:) => null() + + ! stream data + real(r8), pointer :: strm_rain(:) => null() + + real(r8) :: rain_min ! rain value detector + + real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg + real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 + + character(*), parameter :: nullstr = 'undefined' + character(*), parameter :: rpfile = 'rpointer.atm' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_gfs_hafs_advertise(exportState, fldsexport, & + flds_scalar_name, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sd_pslv' ) + call dshr_fldList_add(fldsExport, 'Sd_u10m' ) + call dshr_fldList_add(fldsExport, 'Sd_v10m' ) + call dshr_fldList_add(fldsExport, 'Faxd_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxd_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxd_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxd_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxd_lwnet' ) + call dshr_fldList_add(fldsExport, 'Faxd_taux' ) + call dshr_fldList_add(fldsExport, 'Faxd_tauy' ) + call dshr_fldList_add(fldsExport, 'Faxd_sen' ) + call dshr_fldList_add(fldsExport, 'Faxd_lat' ) + call dshr_fldList_add(fldsExport, 'Faxd_rain' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_gfs_hafs_advertise + + !=============================================================================== + subroutine datm_datamode_gfs_hafs_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers for module level stream arrays + !call shr_strdata_get_stream_pointer( sdat, 'Sa_mask' , strm_mask , rc) + call shr_strdata_get_stream_pointer( sdat, 'Faxd_rain' , strm_rain , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sd_pslv' , fldptr1=Sd_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sd_u10m' , fldptr1=Sd_u10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sd_v10m' , fldptr1=Sd_v10m , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_swvdr' , fldptr1=Faxd_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_swvdf' , fldptr1=Faxd_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_swndr' , fldptr1=Faxd_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_swndf' , fldptr1=Faxd_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_lwnet' , fldptr1=Faxd_lwnet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_taux' , fldptr1=Faxd_taux , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_tauy' , fldptr1=Faxd_tauy , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_sen' , fldptr1=Faxd_sen , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_lat' , fldptr1=Faxd_lat , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxd_rain' , fldptr1=Faxd_rain , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine datm_datamode_gfs_hafs_init_pointers + + !=============================================================================== + subroutine datm_datamode_gfs_hafs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) + use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MIN, ESMF_VM + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: mainproc + integer , intent(in) :: logunit + integer , intent(in) :: mpicom + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + logical :: first_time = .true. + integer :: n ! indices + integer :: lsize ! size of attr vect + real(r8) :: rtmp(2) + type(ESMF_VM) :: vm + character(len=*), parameter :: subname='(datm_datamode_gfs_hafs_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(strm_rain) + + if (first_time) then + call ESMF_VMGetCurrent(vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! determine minimum Faxd_rain (see below for use) + rtmp(1) = minval(strm_rain(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MIN, rc=rc) + rain_min = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' rain_min = ',rain_min + + ! reset first_time + first_time = .false. + end if + + do n = 1, lsize + !--- Faxd_rain is positive --- + if (associated(Faxd_rain)) then + if (rain_min < 0.0_r8) Faxd_rain(n) = max(0.0_r8,Faxd_rain(n)) + end if + end do + + end subroutine datm_datamode_gfs_hafs_advance + + !=============================================================================== + subroutine datm_datamode_gfs_hafs_restart_write(case_name, inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + ! input/output variables + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + end subroutine datm_datamode_gfs_hafs_restart_write + + !=============================================================================== + subroutine datm_datamode_gfs_hafs_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) + + ! input/output arguments + character(len=*) , intent(inout) :: rest_filem + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) + + end subroutine datm_datamode_gfs_hafs_restart_read + +end module datm_datamode_gfs_hafs_mod From 89603d16f39675624fc8518da50d9515cd5f18c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Turun=C3=A7o=C4=9Flu?= Date: Fri, 26 Jan 2024 09:13:50 -0700 Subject: [PATCH 10/28] Update CDEPS (#58) --- .github/actions/buildcdeps/action.yaml | 46 + .github/workflows/extbuild.yml | 83 +- .gitignore | 4 + CMakeLists.txt | 56 +- README.md | 2 +- cime_config/buildlib | 8 +- cime_config/buildlib_comps | 22 +- cime_config/stream_cdeps.py | 377 +++--- datm/CMakeLists.txt | 19 +- datm/atm_comp_nuopc.F90 | 47 +- datm/cime_config/buildnml | 12 +- datm/cime_config/config_component.xml | 6 +- datm/cime_config/namelist_definition_datm.xml | 111 +- datm/cime_config/stream_definition_datm.xml | 85 +- datm/datm_datamode_era5_mod.F90 | 209 +++- datm/datm_datamode_simple_mod.F90 | 379 ++++++ dice/CMakeLists.txt | 15 +- dice/ice_comp_nuopc.F90 | 20 +- dlnd/CMakeLists.txt | 15 +- dlnd/lnd_comp_nuopc.F90 | 24 +- docn/CMakeLists.txt | 15 +- docn/cime_config/config_component.xml | 14 +- docn/ocn_comp_nuopc.F90 | 19 +- drof/CMakeLists.txt | 13 + drof/cime_config/config_component.xml | 2 +- drof/rof_comp_nuopc.F90 | 20 +- dshr/dshr_fldlist_mod.F90 | 11 +- dshr/dshr_mod.F90 | 2 +- dwav/CMakeLists.txt | 13 + dwav/wav_comp_nuopc.F90 | 29 +- share/CMakeLists.txt | 2 + share/shr_file_mod.F90 | 1048 +++++++++++++++++ share/shr_nl_mod.F90 | 88 ++ streams/CMakeLists.txt | 8 +- streams/dshr_stream_mod.F90 | 31 +- 35 files changed, 2467 insertions(+), 388 deletions(-) create mode 100644 .github/actions/buildcdeps/action.yaml create mode 100644 datm/datm_datamode_simple_mod.F90 create mode 100644 share/shr_file_mod.F90 create mode 100644 share/shr_nl_mod.F90 diff --git a/.github/actions/buildcdeps/action.yaml b/.github/actions/buildcdeps/action.yaml new file mode 100644 index 000000000..9d775dd12 --- /dev/null +++ b/.github/actions/buildcdeps/action.yaml @@ -0,0 +1,46 @@ +name: CDEPS build and cache +description: 'Build the CDEPS library' +inputs: + cdeps_version: + description: 'Tag in the CDEPS repository to use' + default: main + required: False + type: string + pio_path: + description: 'Path to the installed parallelio code root' + default: $HOME/pio + required: False + type: string + esmfmkfile: + description: 'Path to the installed ESMF library mkfile' + default: $HOME/ESMF/lib/libg/Linux.gfortran.64.openmpi.default/esmf.mk + required: False + type: string + src_root: + description: 'Path to cdeps source' + default: $GITHUB_WORKSPACE + required: False + type: string + cmake_flags: + description: 'Extra flags for cmake command' + default: -Wno-dev + required: False + type: string + install_prefix: + description: 'Install path of cdeps' + default: $HOME/cdeps + required: False + type: string +runs: + using: composite + steps: + - id : Build-CDEPS + shell: bash + run: | + mkdir build-cdeps + pushd build-cdeps + export ESMFMKFILE=${{ inputs.esmfmkfile }} + export PIO=${{ inputs.pio_path }} + cmake ${{ inputs.cmake_flags }} ${{ inputs.src_root }} + make VERBOSE=1 + popd diff --git a/.github/workflows/extbuild.yml b/.github/workflows/extbuild.yml index c3a54360e..52afb7b81 100644 --- a/.github/workflows/extbuild.yml +++ b/.github/workflows/extbuild.yml @@ -19,10 +19,8 @@ jobs: CPPFLAGS: "-I/usr/include -I/usr/local/include " LDFLAGS: "-L/usr/lib/x86_64-linux-gnu " # Versions of all dependencies can be updated here - these match tag names in the github repo - ESMF_VERSION: v8.4.0 - #PNETCDF_VERSION: checkpoint.1.12.3 - #NETCDF_FORTRAN_VERSION: v4.6.0 - ParallelIO_VERSION: pio2_5_10 + ESMF_VERSION: v8.5.0 + ParallelIO_VERSION: pio2_6_0 steps: - id: checkout-CDEPS uses: actions/checkout@v3 @@ -37,35 +35,11 @@ jobs: sudo apt-get install netcdf-bin libnetcdf-dev libnetcdff-dev sudo apt-get install pnetcdf-bin libpnetcdf-dev sudo apt-get install autotools-dev autoconf - # - id: cache-pnetcdf - # uses: actions/cache@v3 - # with: - # path: ~/pnetcdf - # key: ${{ runner.os }}-${{ env.PNETCDF_VERSION}}-pnetcdf1 - # - name: Build PNetCDF - # if: steps.cache-pnetcdf.outputs.cache-hit != 'true' - # uses: ./.github/actions/buildpnetcdf - # with: - # pnetcdf_version: ${{ env.PNETCDF_VERSION }} - # install_prefix: $HOME/pnetcdf - # - name: Cache netcdf-fortran - # id: cache-netcdf-fortran - # uses: actions/cache@v3 - # with: - # path: ~/netcdf-fortran - # key: ${{ runner.os }}-${{ env.NETCDF_FORTRAN_VERSION }}-netcdf-fortran1 - # - name: Build NetCDF Fortran - # if: steps.cache-netcdf-fortran.outputs.cache-hit != 'true' - # uses: ./.github/actions/buildnetcdff - # with: - # netcdf_fortran_version: ${{ env.NETCDF_FORTRAN_VERSION }} - # install_prefix: $HOME/netcdf-fortran - # netcdf_c_path: /usr - name: Cache PARALLELIO id: cache-PARALLELIO uses: actions/cache@v3 with: - path: ~/pio + path: ${GITHUB_WORKSPACE}/pio key: ${{ runner.os }}-${{ env.ParallelIO_VERSION }}-parallelio2 - name: Build ParallelIO if: steps.cache-PARALLELIO.outputs.cache-hit != 'true' @@ -73,32 +47,33 @@ jobs: with: parallelio_version: ${{ env.ParallelIO_VERSION }} enable_fortran: True - install_prefix: $HOME/pio - - name: Cache ESMF - id: cache-esmf - uses: actions/cache@v3 - with: - path: ~/ESMF - key: ${{ runner.os }}-${{ env.ESMF_VERSION }}-ESMF2 - - name: Build ESMF - if: steps.cache-esmf.outputs.cache-hit != 'true' - uses: ./.github/actions/buildesmf + install_prefix: ${GITHUB_WORKSPACE}/pio + - name: Install ESMF + uses: esmf-org/install-esmf-action@v1 + env: + ESMF_COMPILER: gfortran + ESMF_BOPT: g + ESMF_COMM: openmpi + ESMF_NETCDF: nc-config + ESMF_PNETCDF: pnetcdf-config + ESMF_INSTALL_PREFIX: ${GITHUB_WORKSPACE}/ESMF + ESMF_PIO: external + ESMF_PIO_INCLUDE: ${GITHUB_WORKSPACE}/pio/include + ESMF_PIO_LIBPATH: ${GITHUB_WORKSPACE}/pio/lib with: - esmf_version: ${{ env.ESMF_VERSION }} - esmf_bopt: g - esmf_comm: openmpi - install_prefix: $HOME/ESMF - netcdf_c_path: /usr - netcdf_fortran_path: /usr - pnetcdf_path: /usr - parallelio_path: $HOME/pio + version: ${{ env.ESMF_VERSION }} + esmpy: false + cache: true + - name: Build CDEPS + uses: ./.github/actions/buildcdeps + with: + esmfmkfile: $ESMFMKFILE + pio_path: ${GITHUB_WORKSPACE}/pio + src_root: ${GITHUB_WORKSPACE} + cmake_flags: " -Wno-dev -DCMAKE_BUILD_TYPE=DEBUG -DWERROR=ON -DCMAKE_Fortran_FLAGS=\"-DCPRGNU -g -Wall \ + -ffree-form -ffree-line-length-none -fallow-argument-mismatch \"" + - name: Test CDEPS run: | - export ESMFMKFILE=$HOME/ESMF/lib/libg/Linux.gfortran.64.openmpi.default/esmf.mk - export PIO=$HOME/pio - export SRC_ROOT= - mkdir build-cdeps - pushd build-cdeps - cmake -Wno-dev -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_Fortran_FLAGS="-DCPRGNU -g -Wall -ffree-form -ffree-line-length-none -fallow-argument-mismatch " -DWERROR=ON ../ + cd build-cdeps make VERBOSE=1 - popd diff --git a/.gitignore b/.gitignore index 34b286f3e..625692541 100644 --- a/.gitignore +++ b/.gitignore @@ -31,5 +31,9 @@ *.out *.app +# Externals +fox +share/genf90 + # ignore pycache __pycache__ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5d88135b8..28fb2a269 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,12 @@ cmake_minimum_required(VERSION 3.10) include(ExternalProject) include(FetchContent) +set(DISABLE_FoX OFF CACHE BOOL "Disable FoX library to process XML files.") +message("DISABLE_FoX = ${DISABLE_FoX}") +if(DISABLE_FoX) + add_definitions(-DDISABLE_FoX) +endif() + if (DEFINED CIMEROOT) message("Using CIME in ${CIMEROOT} with compiler ${COMPILER}") include(${CASEROOT}/Macros.cmake) @@ -23,7 +29,9 @@ else() set(BLD_STANDALONE TRUE) project(NUOPC_DATA_MODELS LANGUAGES Fortran VERSION 0.1) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) - set(FOX_ROOT ${CMAKE_SOURCE_DIR}/fox) + if(NOT DISABLE_FoX) + set(FOX_ROOT ${CMAKE_SOURCE_DIR}/fox) + endif() endif() message("CMAKE_MODULE_PATH is ${CMAKE_MODULE_PATH}, CMAKE_Fortran_COMPILER is ${CMAKE_Fortran_COMPILER}") enable_language(Fortran) @@ -62,29 +70,32 @@ endif() add_subdirectory(streams) add_subdirectory(dshr) -if(IS_DIRECTORY "${FOX_ROOT}") - message(STATUS "FoX library is already checked out!") - message(STATUS "FoX source dir: ${FOX_ROOT}") -else() - FetchContent_Declare(fox - GIT_REPOSITORY https://github.com/ESMCI/fox.git - GIT_TAG 4.1.2.1 - SOURCE_DIR ${FOX_ROOT} - BINARY_DIR ${FOX_ROOT}/.. - ) - FetchContent_GetProperties(fox) - if(NOT fox_POPULATED) - FetchContent_Populate(fox) - message(STATUS "FoX source dir: ${fox_SOURCE_DIR}") - message(STATUS "FoX binary dir: ${fox_BINARY_DIR}") +if(NOT DISABLE_FoX) + if(IS_DIRECTORY "${FOX_ROOT}") + message(STATUS "FoX library is already checked out!") + message(STATUS "FoX source dir: ${FOX_ROOT}") + else() + FetchContent_Declare(fox + GIT_REPOSITORY https://github.com/ESMCI/fox.git + GIT_TAG 4.1.2.1 + SOURCE_DIR ${FOX_ROOT} + BINARY_DIR ${FOX_ROOT}/.. + ) + FetchContent_GetProperties(fox) + if(NOT fox_POPULATED) + FetchContent_Populate(fox) + message(STATUS "FoX source dir: ${fox_SOURCE_DIR}") + message(STATUS "FoX binary dir: ${fox_BINARY_DIR}") + endif() endif() + add_subdirectory(fox) + + target_include_directories(streams PUBLIC $ + $) + target_include_directories(dshr PUBLIC $ + $) endif() -add_subdirectory(fox) -target_include_directories(streams PUBLIC $ - $) -target_include_directories(dshr PUBLIC $ - $) target_include_directories(dshr PUBLIC $ $) @@ -112,6 +123,9 @@ foreach(COMP datm dice dlnd docn drof dwav) endforeach(COMP) foreach(DEPS streams dshr cdeps_share FoX_dom FoX_wxml FoX_sax FoX_common FoX_utils FoX_fsys) + if(DISABLE_FoX AND ${DEPS} MATCHES "^FoX") + continue() + endif() if(NOT BLD_STANDALONE AND ${DEPS} STREQUAL "cdeps_share") continue() endif() diff --git a/README.md b/README.md index e46df19ae..00da8d28c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Community Data Models for Earth Prediction Systems For documentation see -https://escomp.github.io/CDEPS/html/index.html +https://escomp.github.io/CDEPS/versions/master/html/index.html ## A note on github tag action diff --git a/cime_config/buildlib b/cime_config/buildlib index 965836cff..a692a4e50 100755 --- a/cime_config/buildlib +++ b/cime_config/buildlib @@ -77,9 +77,7 @@ def buildlib(bldroot, libroot, case): logger.info("Running cmake for CDEPS") srcpath = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir)) - cmake_flags = get_standard_cmake_args( - case, os.path.join(sharedpath, "cdeps") - ) + cmake_flags = get_standard_cmake_args(case, os.path.join(sharedpath, "cdeps")) # base path of install to be completed by setting DESTDIR in make install cmake_flags += " -DCMAKE_INSTALL_PREFIX:PATH=/" cmake_flags += " -DLIBROOT={} ".format(libroot) @@ -180,8 +178,8 @@ def buildlib(bldroot, libroot, case): # Do not allow any warnings except from fox external nextline = "" for line in e.split("\n"): - if "F90" in line and not "fox" in line: - nextline.append(line) + if "f90" in line.lower() and not "fox" in line.lower(): + nextline = nextline + line if len(nextline) > 0: expect(False, nextline) diff --git a/cime_config/buildlib_comps b/cime_config/buildlib_comps index 1eba5bee6..281f0d4e9 100755 --- a/cime_config/buildlib_comps +++ b/cime_config/buildlib_comps @@ -11,7 +11,7 @@ if _CIMEROOT is None: raise SystemExit("ERROR: must set CIMEROOT environment variable") sys.path.append(os.path.join(_CIMEROOT, "CIME", "Tools")) -_LIBDIR = os.path.join(_CIMEROOT, "scripts", "lib") +_LIBDIR = os.path.join(_CIMEROOT, "CIME") sys.path.append(_LIBDIR) from standard_script_setup import * @@ -19,28 +19,36 @@ from CIME.buildlib import parse_input from CIME.case import Case from CIME.utils import run_cmd, symlink_force, expect +# pragma pylint: disable=unused-argument,undefined-variable + logger = logging.getLogger(__name__) + def buildlib(bldroot, libroot, case, compname=None): if not compname: - expect(bldroot.endswith("obj"), - "It appears that buildlib_comps is being called for the main CDEPS build\n" - "(the main CDEPS build should use buildlib, not buildlib_comps)") - compname = os.path.basename(os.path.abspath(os.path.join(bldroot,os.pardir))) + expect( + bldroot.endswith("obj"), + "It appears that buildlib_comps is being called for the main CDEPS build\n" + "(the main CDEPS build should use buildlib, not buildlib_comps)", + ) + compname = os.path.basename(os.path.abspath(os.path.join(bldroot, os.pardir))) _, o, e = run_cmd("make d{}".format(compname), from_dir=bldroot, verbose=True) libname = "lib{}.a".format(compname) dlibname = "libd{}.a".format(compname) dlibpath = os.path.join(bldroot, dlibname) if os.path.exists(dlibpath): - symlink_force(os.path.join(bldroot,dlibname), os.path.join(libroot,libname)) + symlink_force(os.path.join(bldroot, dlibname), os.path.join(libroot, libname)) else: - expect(False, "ERROR in {} build {} {}".format(compname,o,e)) + expect(False, "ERROR in {} build {} {}".format(compname, o, e)) + logger.info(f"build successful for comp={compname}") + def _main_func(args): caseroot, libroot, bldroot = parse_input(args) with Case(caseroot) as case: buildlib(bldroot, libroot, case) + if __name__ == "__main__": _main_func(sys.argv) diff --git a/cime_config/stream_cdeps.py b/cime_config/stream_cdeps.py index ead74bbf2..1f702a13c 100644 --- a/cime_config/stream_cdeps.py +++ b/cime_config/stream_cdeps.py @@ -7,12 +7,11 @@ import re import hashlib -from standard_script_setup import * from CIME.XML.standard_module_setup import * from CIME.XML.generic_xml import GenericXML -from CIME.XML.files import Files from CIME.utils import expect +# pragma pylint: disable=undefined-variable logger = logging.getLogger(__name__) _var_ref_re = re.compile(r"\$(\{)?(?P\w+)(?(1)\})") @@ -44,25 +43,40 @@ """ valid_values = {} -valid_values["mapalgo"] = ["bilinear", "nn", "redist", "mapconsd", "mapconf", "none"] +valid_values["mapalgo"] = ["bilinear", "nn", "redist", "mapconsd", "mapconf", "none"] valid_values["tintalgo"] = ["lower", "upper", "nearest", "linear", "coszen"] -valid_values["taxmode"] = ["cycle", "extend", "limit"] +valid_values["taxmode"] = ["cycle", "extend", "limit"] -xml_scalar_names = ["stream_meshfile", "stream_mapalgo", "stream_tintalgo", "stream_taxmode", "stream_dtlimit"] +xml_scalar_names = [ + "stream_meshfile", + "stream_mapalgo", + "stream_tintalgo", + "stream_taxmode", + "stream_dtlimit", +] -class StreamCDEPS(GenericXML): +class StreamCDEPS(GenericXML): def __init__(self, infile, schema): """ Initialize a CDEPS stream object """ logger.debug("Verifying using schema {}".format(schema)) GenericXML.__init__(self, infile, schema) + self.stream_nodes = None + if os.path.exists(infile): GenericXML.read(self, infile, schema) - def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file, user_mods_file, - available_neon_data=None): + def create_stream_xml( + self, + stream_names, + case, + streams_xml_file, + data_list_file, + user_mods_file, + available_neon_data=None, + ): """ Create the stream xml file and append the required stream input data to the input data list file available_neon_data is an optional list of NEON tower data available for the given case, if provided @@ -71,98 +85,134 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file # determine if there are user mods lines_input = [] - expect (os.path.isfile(user_mods_file), - "No file {} found in case directory".format(user_mods_file)) - with open(user_mods_file, "r", encoding='utf-8') as stream_mods_file: + expect( + os.path.isfile(user_mods_file), + "No file {} found in case directory".format(user_mods_file), + ) + with open(user_mods_file, "r", encoding="utf-8") as stream_mods_file: lines_input = stream_mods_file.readlines() stream_mod_dict = {} n = len(lines_input) index = 0 lines_input_new = [] - while index < len(lines_input): + while index < n: line = lines_input[index].strip() - if line.startswith('!') or (not line): + if line.startswith("!") or (not line): index = index + 1 continue - while line[-1] == '\\': + while line[-1] == "\\": index += 1 - if index < len(lines_input): - line = line[:-1].strip() + ' ' + lines_input[index].strip() + if index < n: + line = line[:-1].strip() + " " + lines_input[index].strip() else: - line = line.replace('\\', '').strip() + line = line.replace("\\", "").strip() break # endif # end while index += 1 line = case.get_resolved_value(line) lines_input_new.append(line) - #end while + # end while for line in lines_input_new: # read in a single line in user_nl_xxx_streams and parse it if it is not a comment - stream_mods = [x.strip() for x in line.strip().split(":",maxsplit=1) if x] - expect(len(stream_mods) == 2, - "input stream mod can only be of the form streamname:var=value(s)") - stream,varmod = stream_mods - expect (stream in stream_names, - "{} contains a streamname \'{}\' that is not part of valid streamnames {}". - format(user_mods_file,stream,stream_names)) - if stream not in stream_mod_dict: + stream_mods = [x.strip() for x in line.strip().split(":", maxsplit=1) if x] + expect( + len(stream_mods) == 2, + "input stream mod can only be of the form streamname:var=value(s)", + ) + stream, varmod = stream_mods + expect( + stream in stream_names, + "{} contains a streamname '{}' that is not part of valid streamnames {}".format( + user_mods_file, stream, stream_names + ), + ) + if stream not in stream_mod_dict: stream_mod_dict[stream] = {} # var=value and check the validity varmod_args = [x.strip() for x in varmod.split("=") if x] - expect(len(varmod_args) == 2, - "input stream mod can only be of the form streamname:var=value(s)") + expect( + len(varmod_args) == 2, + "input stream mod can only be of the form streamname:var=value(s)", + ) # allow multiple entries for varmod_args, most recent wins - varname,varval = varmod_args + varname, varval = varmod_args if varname in stream_mod_dict[stream]: - logger.warning("varname {} is already in stream mod dictionary".format(varname)) + logger.warning( + "varname {} is already in stream mod dictionary".format(varname) + ) if varname == "datavars" or varname == "datafiles": if varname == "datavars": - varvals = ["{}".format(x.strip()) for x in varval.split(",") if x] + varvals = [ + "{}".format(x.strip()) + for x in varval.split(",") + if x + ] if varname == "datafiles": - varvals = ["{}".format(x.strip()) for x in varval.split(",") if x] + varvals = [ + "{}".format(x.strip()) + for x in varval.split(",") + if x + ] varval = " " + "\n ".join(varvals) varval = varval.strip() stream_mod_dict[stream][varname] = varval # write header of stream file - with open(streams_xml_file, 'w', encoding='utf-8') as stream_file: + with open(streams_xml_file, "w", encoding="utf-8") as stream_file: stream_file.write('\n') stream_file.write('\n') # write contents of stream file for stream_name in stream_names: # include NEON.$NEONSITE non-precipitation data streams whether use PRISM or NEON precip - if stream_name.startswith("NEON.") and ('PRECIP' not in stream_name): - self.stream_nodes = super(StreamCDEPS,self).get_child("stream_entry", {"name" : "NEON.$NEONSITE"}, - err_msg="No stream_entry {} found".format(stream_name)) + if stream_name.startswith("NEON.") and ("PRECIP" not in stream_name): + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "NEON.$NEONSITE"}, + err_msg="No stream_entry {} found".format(stream_name), + ) elif stream_name.startswith("NEON.PRISM_PRECIP"): - self.stream_nodes = super(StreamCDEPS,self).get_child("stream_entry", {"name" : "NEON.PRISM_PRECIP.$NEONSITE"}, - err_msg="No stream_entry {} found".format(stream_name)) + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "NEON.PRISM_PRECIP.$NEONSITE"}, + err_msg="No stream_entry {} found".format(stream_name), + ) elif stream_name.startswith("NEON.NEON_PRECIP"): - self.stream_nodes = super(StreamCDEPS,self).get_child("stream_entry", {"name" : "NEON.NEON_PRECIP.$NEONSITE"}, - err_msg="No stream_entry {} found".format(stream_name)) + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "NEON.NEON_PRECIP.$NEONSITE"}, + err_msg="No stream_entry {} found".format(stream_name), + ) elif stream_name.startswith("CLM_USRDAT."): - self.stream_nodes = super(StreamCDEPS,self).get_child("stream_entry", {"name" : "CLM_USRDAT.$CLM_USRDAT_NAME"}, - err_msg="No stream_entry {} found".format(stream_name)) + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": "CLM_USRDAT.$CLM_USRDAT_NAME"}, + err_msg="No stream_entry {} found".format(stream_name), + ) elif stream_name: - self.stream_nodes = super(StreamCDEPS,self).get_child("stream_entry", {"name" : stream_name}, - err_msg="No stream_entry {} found".format(stream_name)) + self.stream_nodes = super(StreamCDEPS, self).get_child( + "stream_entry", + {"name": stream_name}, + err_msg="No stream_entry {} found".format(stream_name), + ) # determine stream_year_first and stream_year_list - data_year_first,data_year_last = self._get_stream_first_and_last_dates(self.stream_nodes, case) + data_year_first, data_year_last = self._get_stream_first_and_last_dates( + self.stream_nodes, case + ) # now write the data model streams xml file stream_vars = {} - stream_vars['streamname'] = stream_name + stream_vars["streamname"] = stream_name attributes = {} for node in self.get_children(root=self.stream_nodes): node_name = node.xml_element.tag.strip() - if node_name == 'stream_datavars': + if node_name == "stream_datavars": # Get the resolved stream data variables stream_vars[node_name] = None for child in self.get_children(root=node): @@ -171,52 +221,79 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file datavars = self._sub_glc_fields(datavars, case) datavars = self._add_xml_delimiter(datavars.split("\n"), "var") if stream_vars[node_name]: - stream_vars[node_name] = stream_vars[node_name] + "\n " + datavars.strip() + stream_vars[node_name] = ( + stream_vars[node_name] + "\n " + datavars.strip() + ) else: stream_vars[node_name] = datavars.strip() # endif - elif node_name == 'stream_datafiles': + elif node_name == "stream_datafiles": # Get the resolved stream data files stream_vars[node_name] = "" stream_datafiles = "" for child in self.get_children(root=node): - if available_neon_data and stream_name.startswith("NEON") and ('PRISM' not in stream_name): + if ( + available_neon_data + and stream_name.startswith("NEON") + and ("PRISM" not in stream_name) + ): rundir = case.get_value("RUNDIR") for neon in available_neon_data: - stream_datafiles += os.path.join(rundir,"inputdata","atm",neon) + "\n" + stream_datafiles += ( + os.path.join(rundir, "inputdata", "atm", neon) + + "\n" + ) else: stream_datafiles = child.xml_element.text - stream_datafiles = self._resolve_values(case, stream_datafiles) - #endif neon - if 'first_year' in child.xml_element.attrib and 'last_year' in child.xml_element.attrib: - value = child.xml_element.get('first_year') + stream_datafiles = self._resolve_values( + case, stream_datafiles + ) + # endif neon + if ( + "first_year" in child.xml_element.attrib + and "last_year" in child.xml_element.attrib + ): + value = child.xml_element.get("first_year") value = self._resolve_values(case, value) - stream_year_first= int(value) - value = child.xml_element.get('last_year') + stream_year_first = int(value) + value = child.xml_element.get("last_year") value = self._resolve_values(case, value) stream_year_last = int(value) year_first = max(stream_year_first, data_year_first) year_last = min(stream_year_last, data_year_last) - if 'filename_advance_days' in child.xml_element.attrib: - filename_advance_days = int(child.xml_element.get('filename_advance_days')) + if "filename_advance_days" in child.xml_element.attrib: + filename_advance_days = int( + child.xml_element.get("filename_advance_days") + ) else: filename_advance_days = 0 - stream_datafiles = self._sub_paths(stream_name, - stream_datafiles, - year_first, year_last, - filename_advance_days) + stream_datafiles = self._sub_paths( + stream_name, + stream_datafiles, + year_first, + year_last, + filename_advance_days, + ) stream_datafiles = stream_datafiles.strip() - #endif + # endif if stream_vars[node_name]: - stream_vars[node_name] += "\n " + self._add_xml_delimiter(stream_datafiles.split("\n"), "file") + stream_vars[ + node_name + ] += "\n " + self._add_xml_delimiter( + stream_datafiles.split("\n"), "file" + ) else: - stream_vars[node_name] = self._add_xml_delimiter(stream_datafiles.split("\n"), "file") - #endif - elif (node_name in xml_scalar_names): - attributes['model_grid'] = case.get_value("GRID") - attributes['compset'] = case.get_value("COMPSET") - value = self._get_value_match(node, node_name[7:], attributes=attributes) + stream_vars[node_name] = self._add_xml_delimiter( + stream_datafiles.split("\n"), "file" + ) + # endif + elif node_name in xml_scalar_names: + attributes["model_grid"] = case.get_value("GRID") + attributes["compset"] = case.get_value("COMPSET") + value = self._get_value_match( + node, node_name[7:], attributes=attributes + ) if value: value = self._resolve_values(case, value) value = value.strip() @@ -224,36 +301,50 @@ def create_stream_xml(self, stream_names, case, streams_xml_file, data_list_file elif node_name.strip(): # Get the other dependencies - stream_dict = self._add_value_to_dict(stream_vars, case, node) + self._add_value_to_dict(stream_vars, case, node) # substitute user_mods in generated stream file (i.e. stream_vars) mod_dict = {} - if stream_vars['streamname'] in stream_mod_dict: - mod_dict = stream_mod_dict[stream_vars['streamname']] + if stream_vars["streamname"] in stream_mod_dict: + mod_dict = stream_mod_dict[stream_vars["streamname"]] for var_key in mod_dict: - expect( 'stream_' + var_key in stream_vars, - "stream mod {} is not a valid name in {}".format(var_key,user_mods_file)) + expect( + "stream_" + var_key in stream_vars, + "stream mod {} is not a valid name in {}".format( + var_key, user_mods_file + ), + ) if var_key in valid_values: - expect(mod_dict[var_key] in valid_values[var_key], - "{} can only have values of {} for stream {} in file {}". - format(var_key, valid_values[var_key], stream_name, user_mods_file)) - stream_vars['stream_' + var_key] = mod_dict[var_key] - if var_key == 'datafiles': + expect( + mod_dict[var_key] in valid_values[var_key], + "{} can only have values of {} for stream {} in file {}".format( + var_key, + valid_values[var_key], + stream_name, + user_mods_file, + ), + ) + stream_vars["stream_" + var_key] = mod_dict[var_key] + if var_key == "datafiles": stream_datafiles = mod_dict[var_key] - stream_datafiles = stream_datafiles.replace('','').replace('','') + stream_datafiles = stream_datafiles.replace( + "", "" + ).replace("", "") # append to stream xml file stream_file_text = _stream_file_template.format(**stream_vars) - with open(streams_xml_file, 'a', encoding='utf-8') as stream_file: + with open(streams_xml_file, "a", encoding="utf-8") as stream_file: stream_file.write(case.get_resolved_value(stream_file_text)) # append to input_data_list - if stream_vars['stream_meshfile']: - stream_meshfile = stream_vars['stream_meshfile'].strip() - self._add_entries_to_inputdata_list(stream_meshfile, stream_datafiles.split("\n"), data_list_file) + if stream_vars["stream_meshfile"]: + stream_meshfile = stream_vars["stream_meshfile"].strip() + self._add_entries_to_inputdata_list( + stream_meshfile, stream_datafiles.split("\n"), data_list_file + ) # write close of stream xml file - with open(streams_xml_file, 'a', encoding='utf-8') as stream_file: + with open(streams_xml_file, "a", encoding="utf-8") as stream_file: stream_file.write("\n") def _get_stream_first_and_last_dates(self, stream, case): @@ -261,32 +352,34 @@ def _get_stream_first_and_last_dates(self, stream, case): Get first and last dates for data for the stream file """ for node in self.get_children(root=stream): - if node.xml_element.tag == 'stream_year_first': + if node.xml_element.tag == "stream_year_first": data_year_first = node.xml_element.text.strip() data_year_first = int(self._resolve_values(case, data_year_first)) - if node.xml_element.tag == 'stream_year_last': + if node.xml_element.tag == "stream_year_last": data_year_last = node.xml_element.text.strip() data_year_last = int(self._resolve_values(case, data_year_last)) return data_year_first, data_year_last - def _add_entries_to_inputdata_list(self, stream_meshfile, stream_datafiles, data_list_file): + def _add_entries_to_inputdata_list( + self, stream_meshfile, stream_datafiles, data_list_file + ): """ Appends input data information entries to input data list file and writes out the new file """ lines_hash = self._get_input_file_hash(data_list_file) - with open(data_list_file, 'a', encoding='utf-8') as input_data_list: + with open(data_list_file, "a", encoding="utf-8") as input_data_list: # write out the mesh file separately string = "mesh = {}\n".format(stream_meshfile) - hashValue = hashlib.md5(string.rstrip().encode('utf-8')).hexdigest() + hashValue = hashlib.md5(string.rstrip().encode("utf-8")).hexdigest() if hashValue not in lines_hash: input_data_list.write(string) # now append the stream_datafile entries for i, filename in enumerate(stream_datafiles): - if filename.strip() == '': + if filename.strip() == "": continue - string = "file{:d} = {}\n".format(i+1, filename.strip()) - hashValue = hashlib.md5(string.rstrip().encode('utf-8')).hexdigest() + string = "file{:d} = {}\n".format(i + 1, filename.strip()) + hashValue = hashlib.md5(string.rstrip().encode("utf-8")).hexdigest() if hashValue not in lines_hash: input_data_list.write(string) @@ -296,15 +389,15 @@ def _get_input_file_hash(self, data_list_file): """ lines_hash = set() if os.path.isfile(data_list_file): - with open(data_list_file, "r", encoding='utf-8') as input_data_list: + with open(data_list_file, "r", encoding="utf-8") as input_data_list: for line in input_data_list: - hashValue = hashlib.md5(line.rstrip().encode('utf-8')).hexdigest() - logger.debug( "Found line {} with hash {}".format(line,hashValue)) + hashValue = hashlib.md5(line.rstrip().encode("utf-8")).hexdigest() + logger.debug("Found line {} with hash {}".format(line, hashValue)) lines_hash.add(hashValue) return lines_hash def _get_value_match(self, node, child_name, attributes=None, exact_match=False): - ''' + """ Get the first best match for multiple tags in child_name based on the attributes input @@ -314,7 +407,7 @@ def _get_value_match(self, node, child_name, attributes=None, exact_match=False) Z - ''' + """ # Store nodes that match the attributes and their scores. matches = [] nodes = self.get_children(child_name, root=node) @@ -328,13 +421,15 @@ def _get_value_match(self, node, child_name, attributes=None, exact_match=False) # If some attribute is specified that we don't know about, # or the values don't match, it's not a match we want. if exact_match: - if attribute not in attributes or \ - attributes[attribute] != self.get(vnode, attribute): + if attribute not in attributes or attributes[ + attribute + ] != self.get(vnode, attribute): score = -1 break else: - if attribute not in attributes or not \ - re.search(self.get(vnode, attribute),attributes[attribute]): + if attribute not in attributes or not re.search( + self.get(vnode, attribute), attributes[attribute] + ): score = -1 break @@ -348,7 +443,7 @@ def _get_value_match(self, node, child_name, attributes=None, exact_match=False) # Get maximum score using either a "last" or "first" match in case of a tie max_score = -1 mnode = None - for score,node in matches: + for score, node in matches: # take the *first* best match if score > max_score: max_score = score @@ -374,10 +469,13 @@ def _resolve_values(self, case, value): """ match = _var_ref_re.search(value) while match: - env_val = case.get_value(match.group('name')) - expect(env_val is not None, - "Namelist default for variable {} refers to unknown XML variable {}.". - format(value, match.group('name'))) + env_val = case.get_value(match.group("name")) + expect( + env_val is not None, + "Namelist default for variable {} refers to unknown XML variable {}.".format( + value, match.group("name") + ), + ) value = value.replace(match.group(0), str(env_val), 1) match = _var_ref_re.search(value) return value @@ -413,10 +511,10 @@ def _sub_glc_fields(self, datavars, case): if not line: continue if "%glc" in line: - if case.get_value('GLC_NEC') == 0: + if case.get_value("GLC_NEC") == 0: glc_nec_indices = [] else: - glc_nec_indices = range(case.get_value('GLC_NEC')+1) + glc_nec_indices = range(case.get_value("GLC_NEC") + 1) for i in glc_nec_indices: new_lines.append(line.replace("%glc", "{:02d}".format(i))) else: @@ -432,7 +530,7 @@ def _days_in_month(month, year=1): """ month_start = datetime.date(year, month, 1) if month == 12: - next_year = year+1 + next_year = year + 1 next_month = 1 else: next_year = year @@ -466,7 +564,9 @@ def _add_day(cls, year, month, day): adjusted_year = adjusted_year + 1 return (adjusted_year, adjusted_month, adjusted_day) - def _sub_paths(self, stream_name, filenames, year_start, year_end, filename_advance_days): + def _sub_paths( + self, stream_name, filenames, year_start, year_end, filename_advance_days + ): """Substitute indicators with given values in a list of filenames. Replace any instance of the following substring indicators with the @@ -500,9 +600,12 @@ def _sub_paths(self, stream_name, filenames, year_start, year_end, filename_adva Returns a string (filenames separated by newlines). """ - expect(filename_advance_days == 0 or filename_advance_days == 1, - "Bad filename_advance_days attribute ({}) for {}: must be 0 or 1".format( - filename_advance_days, stream_name)) + expect( + filename_advance_days == 0 or filename_advance_days == 1, + "Bad filename_advance_days attribute ({}) for {}: must be 0 or 1".format( + filename_advance_days, stream_name + ), + ) lines = [line for line in filenames.split("\n") if line] new_lines = [] @@ -511,23 +614,33 @@ def _sub_paths(self, stream_name, filenames, year_start, year_end, filename_adva if match is None: new_lines.append(line) continue - if match.group('digits'): - year_format = "{:0"+match.group('digits')+"d}" + if match.group("digits"): + year_format = "{:0" + match.group("digits") + "d}" else: year_format = "{:04d}" - for year in range(year_start, year_end+1): - if match.group('day'): + for year in range(year_start, year_end + 1): + if match.group("day"): for month in range(1, 13): days = self._days_in_month(month) - for day in range(1, days+1): + for day in range(1, days + 1): if filename_advance_days == 1: - (adjusted_year, adjusted_month, adjusted_day) = self._add_day(year, month, day) + ( + adjusted_year, + adjusted_month, + adjusted_day, + ) = self._add_day(year, month, day) else: - (adjusted_year, adjusted_month, adjusted_day) = (year, month, day) - date_string = (year_format + "-{:02d}-{:02d}").format(adjusted_year, adjusted_month, adjusted_day) + (adjusted_year, adjusted_month, adjusted_day) = ( + year, + month, + day, + ) + date_string = (year_format + "-{:02d}-{:02d}").format( + adjusted_year, adjusted_month, adjusted_day + ) new_line = line.replace(match.group(0), date_string) new_lines.append(new_line) - elif match.group('month'): + elif match.group("month"): for month in range(1, 13): date_string = (year_format + "-{:02d}").format(year, month) new_line = line.replace(match.group(0), date_string) @@ -543,22 +656,24 @@ def _add_xml_delimiter(list_to_deliminate, delimiter): expect(delimiter and not " " in delimiter, "Missing or badly formed delimiter") pred = "<{}>".format(delimiter) postd = "".format(delimiter) - for n,item in enumerate(list_to_deliminate): + for n, item in enumerate(list_to_deliminate): if item.strip(): list_to_deliminate[n] = pred + item.strip() + postd - #endif - #endfor + # endif + # endfor return "\n ".join(list_to_deliminate) def update_input_data_list(self, data_list_file): - ''' From the stream object parse out and list required input files ''' + """From the stream object parse out and list required input files""" sinodes = self.scan_children("stream_info") for node in sinodes: meshnode = self.scan_child("stream_mesh_file", root=node) stream_meshfile = self.text(meshnode) data_file_node = self.scan_child("stream_data_files", root=node) - filenodes = self.scan_children("file",root=data_file_node) + filenodes = self.scan_children("file", root=data_file_node) stream_datafiles = [] for fnode in filenodes: stream_datafiles.append(self.text(fnode)) - self._add_entries_to_inputdata_list(stream_meshfile, stream_datafiles, data_list_file) + self._add_entries_to_inputdata_list( + stream_meshfile, stream_datafiles, data_list_file + ) diff --git a/datm/CMakeLists.txt b/datm/CMakeLists.txt index f25ad9f4d..4899e0626 100644 --- a/datm/CMakeLists.txt +++ b/datm/CMakeLists.txt @@ -8,8 +8,8 @@ set(SRCFILES atm_comp_nuopc.F90 datm_datamode_cfsr_mod.F90 datm_datamode_gfs_mod.F90 datm_datamode_gfs_hafs_mod.F90 - datm_datamode_era5_mod.F90) - + datm_datamode_era5_mod.F90 + datm_datamode_simple_mod.F90) foreach(FILE ${SRCFILES}) if(EXISTS "${CASEROOT}/SourceMods/src.datm/${FILE}") @@ -27,4 +27,17 @@ add_dependencies(datm dshr streams) target_include_directories (datm PRIVATE ${ESMF_F90COMPILEPATHS}) target_include_directories (datm PRIVATE ${CMAKE_SOURCE_DIR}) target_include_directories (datm PRIVATE ${PIO_Fortran_INCLUDE_DIR}) -target_include_directories (datm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +if(NOT DISABLE_FoX) + target_include_directories (datm PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL atm_comp_nuopc.mod) + set(MOD cdeps_datm_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 82703ba64..a00610eb9 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -94,6 +94,12 @@ module cdeps_datm_comp use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_write use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_read + use datm_datamode_simple_mod , only : datm_datamode_simple_advertise + use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers + use datm_datamode_simple_mod , only : datm_datamode_simple_advance + use datm_datamode_simple_mod , only : datm_datamode_simple_restart_write + use datm_datamode_simple_mod , only : datm_datamode_simple_restart_read + implicit none private ! except @@ -148,6 +154,7 @@ module cdeps_datm_comp integer :: nx_global ! global nx integer :: ny_global ! global ny logical :: skip_restart_read = .false. ! true => skip restart read in continuation run + logical :: export_all = .false. ! true => export all fields, do not check connected or not ! linked lists type(fldList_type) , pointer :: fldsImport => null() @@ -224,7 +231,7 @@ end subroutine SetServices !=============================================================================== subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) - + use shr_nl_mod, only: shr_nl_find_group_name ! input/output variables type(ESMF_GridComp) :: gcomp type(ESMF_State) :: importState, exportState @@ -234,7 +241,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) ! local variables integer :: nu ! unit number integer :: ierr ! error code - integer :: bcasttmp(9) + integer :: bcasttmp(10) type(ESMF_VM) :: vm character(len=*),parameter :: subname=trim(modName) // ':(InitializeAdvertise) ' character(*) ,parameter :: F00 = "('(" // trim(modName) // ") ',8a)" @@ -259,7 +266,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) anomaly_forcing, & skip_restart_read, & flds_presndep, & - flds_preso3 + flds_preso3, & + export_all rc = ESMF_SUCCESS @@ -280,6 +288,11 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (my_task == main_task) then nlfilename = "datm_in"//trim(inst_suffix) open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'datm_nml', status=ierr) + if (ierr > 0) then + write(logunit,*) 'ERROR: reading input namelist, '//trim(nlfilename)//' iostat=',ierr + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if read (nu,nml=datm_nml,iostat=ierr) close(nu) if (ierr > 0) then @@ -296,8 +309,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if(flds_co2) bcasttmp(7) = 1 if(flds_wiso) bcasttmp(8) = 1 if(skip_restart_read) bcasttmp(9) = 1 - + if(export_all) bcasttmp(10) = 1 end if + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -317,7 +331,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 9, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 10, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return nx_global = bcasttmp(1) ny_global = bcasttmp(2) @@ -328,6 +342,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) flds_co2 = (bcasttmp(7) == 1) flds_wiso = (bcasttmp(8) == 1) skip_restart_read = (bcasttmp(9) == 1) + export_all = (bcasttmp(10) == 1) ! write namelist input to standard out if (my_task == main_task) then @@ -347,6 +362,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F02)' flds_co2 = ',flds_co2 write(logunit,F02)' flds_wiso = ',flds_wiso write(logunit,F02)' skip_restart_read = ',skip_restart_read + write(logunit,F02)' export_all = ',export_all end if ! Validate sdat datamode @@ -360,7 +376,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) trim(datamode) == 'CFSR' .or. & trim(datamode) == 'GFS' .or. & trim(datamode) == 'GFS_HAFS' .or. & - trim(datamode) == 'ERA5') then + trim(datamode) == 'ERA5' .or. & + trim(datamode) == 'SIMPLE') then else call shr_sys_abort(' ERROR illegal datm datamode = '//trim(datamode)) endif @@ -397,6 +414,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('GFS_HAFS') call datm_datamode_gfs_hafs_advertise(exportState, fldsExport, flds_scalar_name, rc) + case ('SIMPLE') + call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & + nlfilename, my_task, vm, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end select @@ -453,10 +473,10 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState ! by replacing the advertised fields with the newly created fields of the same name. call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//':datmExport', rc=rc) + subname//':datmExport', export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_fldlist_realize( importState, fldsImport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//':datmImport', rc=rc) + subname//':datmImport', .false., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Get the time to interpolate the stream data to @@ -646,6 +666,8 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe if (ChkErr(rc,__LINE__,u_FILE_u)) return case('GFS_HAFS') call datm_datamode_gfs_hafs_init_pointers(exportState, sdat, rc) + case('SIMPLE') + call datm_datamode_simple_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end select @@ -670,6 +692,8 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_gfs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) case('GFS_HAFS') call datm_datamode_gfs_hafs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) + case('SIMPLE') + call datm_datamode_simple_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) end select end if @@ -731,6 +755,9 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('GFS_HAFS') call datm_datamode_gfs_hafs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & target_tod, sdat%model_calendar, rc) + case('SIMPLE') + call datm_datamode_simple_advance(target_ymd, target_tod, target_mon, & + sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end select @@ -768,6 +795,9 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_gfs_hafs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('SIMPLE') + call datm_datamode_simple_restart_write(case_name, inst_suffix, target_ymd, target_tod, & + logunit, my_task, sdat) end select end if @@ -816,6 +846,7 @@ subroutine datm_init_dfields(rc) call ESMF_StateGet(exportState, itemNameList=lfieldnames, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return do n = 1, fieldCount + call ESMF_LogWrite(trim(subname)//': field name = '//trim(lfieldnames(n)), ESMF_LOGMSG_INFO) call ESMF_StateGet(exportState, itemName=trim(lfieldnames(n)), field=lfield, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return call ESMF_FieldGet(lfield, rank=rank, rc=rc) diff --git a/datm/cime_config/buildnml b/datm/cime_config/buildnml index c3d59375a..afee50344 100755 --- a/datm/cime_config/buildnml +++ b/datm/cime_config/buildnml @@ -64,10 +64,10 @@ def _get_neon_data_availability(case, neonsite): for version in dataversions: # Once a date range for a version has been determined for any version, the loop is complete. - # Eg, if data is available for v3, the loop will not continue to v2; - # however, if data is not available for v3, it will check for v2. - # Thus, it is important for dataversions to be listed from newest to oldest. - if not newestdate: + # Eg, if data is available for v3, the loop will not continue to v2; + # however, if data is not available for v3, it will check for v2. + # Thus, it is important for dataversions to be listed from newest to oldest. + if not newestdate: with open(fullpath, "r") as fd: for line in fd.readlines(): fpath, fname = os.path.split(line) @@ -174,7 +174,7 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path # Generate datm_in namelist_file = os.path.join(confdir, "datm_in") - nmlgen.write_output_file(namelist_file, data_list_path, groups=['datm_nml']) + nmlgen.write_output_file(namelist_file, data_list_path, groups=['datm_nml','const_forcing_nml']) # Determine streams streamlist = nmlgen.get_streams() @@ -220,7 +220,7 @@ def _create_drv_flds_in(case, confdir): # for now we are hard-coding this file name and values because we only need it for ozone if datm_preso3 != "none": - # Generate drv_flds_in file + # Generate drv_flds_in file outfile = os.path.join(confdir, "drv_flds_in") ozone_nl_name = "&ozone_coupling_nl" ozone_freq_par = "atm_ozone_frequency" diff --git a/datm/cime_config/config_component.xml b/datm/cime_config/config_component.xml index de8840a01..e0a04797d 100644 --- a/datm/cime_config/config_component.xml +++ b/datm/cime_config/config_component.xml @@ -10,7 +10,7 @@ This file may have atm desc entries. --> - Data driven ATM + Data driven ATM QIAN data set QIAN with water isotopes CRUNCEP data set @@ -27,6 +27,7 @@ JRA55 Repeat Year Forcing v1.3 1990-1991 JRA55 Repeat Year Forcing v1.3 2003-2004 ERA5 interannual forcing + Namelist-configurable, constant datm forcing for simple experiments @@ -40,7 +41,7 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,CORE_IAF_JRA_1p4_2018,ERA5 + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,1PT,CLMCRUNCEP,CLMCRUNCEPv7,CLMGSWP3v1,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,CORE_IAF_JRA_1p4_2018,ERA5,SIMPLE CORE2_NYF run_component_datm env_run.xml @@ -61,6 +62,7 @@ 1PT ERA5 CPLHIST + SIMPLE diff --git a/datm/cime_config/namelist_definition_datm.xml b/datm/cime_config/namelist_definition_datm.xml index 08749a02b..491b6f6d1 100644 --- a/datm/cime_config/namelist_definition_datm.xml +++ b/datm/cime_config/namelist_definition_datm.xml @@ -70,6 +70,7 @@ ERA5_HOURLY + CPLHISTForcing.Solar,CPLHISTForcing.nonSolarFlux,CPLHISTForcing.State3hr,CPLHISTForcing.State1hr @@ -80,7 +81,7 @@ char datm datm_nml - CLMNCEP,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,ERA5,CPLHIST,1PT + CLMNCEP,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,ERA5,SIMPLE,CPLHIST,1PT general method that operates on the data. ----datamode = "CPLHIST"---- @@ -114,6 +115,8 @@ active-land-only simulations. ----datamode = "ERA5"---- Fifth generation ECMWF atmospheric reanalysis of the global climate + ----datamode = "SIMPLE"---- + Namelist-configurable, constant datm forcing for simple experiments ----datamode = "CPLHIST" ---- @@ -132,6 +135,9 @@ ERA5 + + SIMPLE + CPLHIST @@ -364,4 +370,107 @@ + + real + datm + const_forcing_nml + + density at the lowest model layer + units: kg m-3 + + + 1.204 + + + + + real + datm + const_forcing_nml + + inst_pres_height_surface + units: Pa + + + 101325.0 + + + + + real + datm + const_forcing_nml + + Constant bottom layer specific humidity + units: kg kg-1 + + + 0.0 + + + + + real + datm + const_forcing_nml + + Constant air temperature at lowest model layer + units: K + + + 273.15 + + + + + real + datm + const_forcing_nml + + Constant zonal wind speed forcing for simple models. + units: m s-1 + + + 0.0 + + + + + real + datm + const_forcing_nml + + Constant meridional wind speed forcing for simple models. + units: m s-1 + + + 0.0 + + + + + real + datm + const_forcing_nml + + Peak idealized shortwave radiation to be passed to ice/ocean surface. + units: W m-2 + + + 330.0 + + + + + real + datm + const_forcing_nml + + Peak idealized longwave radiation to be passed to ice/ocean surface. + units: W m-2 + + + 450.0 + + diff --git a/datm/cime_config/stream_definition_datm.xml b/datm/cime_config/stream_definition_datm.xml index 4da427f2d..310c5097e 100644 --- a/datm/cime_config/stream_definition_datm.xml +++ b/datm/cime_config/stream_definition_datm.xml @@ -41,6 +41,7 @@ CORE_RYF9091_JRA = JRA55 repeat year forcing, v1.3, 1990-1991 (for forcing POP and CICE) CORE_RYF0304_JRA = JRA55 repeat year forcing, v1.3, 2003-2004 (for forcing POP and CICE) ERA5 = ERA5 intra-annual year forcing + SIMPLE = Namelist-configurable, constant datm forcing for simple experiments CPLHIST = Streams for lnd or ocn/ice forcing used for spinup Currently the following optional streams are supported @@ -4619,10 +4620,10 @@ $ATM_DOMAIN_MESH - $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x3h.%ym.nc + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.3h.avrg.%ymd-10800.nc - a2x3h_Sa_topo Sa_topo + atmImp_Sa_topo Sa_topo null @@ -4649,23 +4650,23 @@ $ATM_DOMAIN_MESH - $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x1d.%ym.nc + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.24h.avrg.%ymd-00000.nc - a2x1d_Faxa_bcphiwet Faxa_bcphiwet - a2x1d_Faxa_bcphodry Faxa_bcphodry - a2x1d_Faxa_bcphidry Faxa_bcphidry - a2x1d_Faxa_ocphiwet Faxa_ocphiwet - a2x1d_Faxa_ocphidry Faxa_ocphidry - a2x1d_Faxa_ocphodry Faxa_ocphodry - a2x1d_Faxa_dstwet1 Faxa_dstwet1 - a2x1d_Faxa_dstdry1 Faxa_dstdry1 - a2x1d_Faxa_dstwet2 Faxa_dstwet2 - a2x1d_Faxa_dstdry2 Faxa_dstdry2 - a2x1d_Faxa_dstwet3 Faxa_dstwet3 - a2x1d_Faxa_dstdry3 Faxa_dstdry3 - a2x1d_Faxa_dstwet4 Faxa_dstwet4 - a2x1d_Faxa_dstdry4 Faxa_dstdry4 + atmImp_Faxa_bcph1 Faxa_bcphidry + atmImp_Faxa_bcph2 Faxa_bcphodry + atmImp_Faxa_bcph3 Faxa_bcphiwet + atmImp_Faxa_ocph1 Faxa_ocphidry + atmImp_Faxa_ocph2 Faxa_ocphodry + atmImp_Faxa_ocph3 Faxa_ocphiwet + atmImp_Faxa_dstwet1 Faxa_dstwet1 + atmImp_Faxa_dstdry1 Faxa_dstdry1 + atmImp_Faxa_dstwet2 Faxa_dstwet2 + atmImp_Faxa_dstdry2 Faxa_dstdry2 + atmImp_Faxa_dstwet3 Faxa_dstwet3 + atmImp_Faxa_dstdry3 Faxa_dstdry3 + atmImp_Faxa_dstwet4 Faxa_dstwet4 + atmImp_Faxa_dstdry4 Faxa_dstdry4 null @@ -4724,13 +4725,13 @@ $ATM_DOMAIN_MESH - $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x1hi.%ym.nc + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.1h.inst.%ymd-03600.nc - a2x1hi_Faxa_swndr Faxa_swndr - a2x1hi_Faxa_swvdr Faxa_swvdr - a2x1hi_Faxa_swndf Faxa_swndf - a2x1hi_Faxa_swvdf Faxa_swvdf + atmImp_Faxa_swndr Faxa_swndr + atmImp_Faxa_swvdr Faxa_swvdr + atmImp_Faxa_swndf Faxa_swndf + atmImp_Faxa_swvdf Faxa_swvdf null @@ -4740,7 +4741,7 @@ $DATM_YR_ALIGN $DATM_YR_START $DATM_YR_END - 2700 + -900 nearest @@ -4758,14 +4759,14 @@ $ATM_DOMAIN_MESH - $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x3h.%ym.nc + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.3h.avrg.%ymd-10800.nc - a2x3h_Faxa_rainc Faxa_rainc - a2x3h_Faxa_rainl Faxa_rainl - a2x3h_Faxa_snowc Faxa_snowc - a2x3h_Faxa_snowl Faxa_snowl - a2x3h_Faxa_lwdn Faxa_lwdn + atmImp_Faxa_rainc Faxa_rainc + atmImp_Faxa_rainl Faxa_rainl + atmImp_Faxa_snowc Faxa_snowc + atmImp_Faxa_snowl Faxa_snowl + atmImp_Faxa_lwdn Faxa_lwdn null @@ -4793,18 +4794,18 @@ $ATM_DOMAIN_MESH - $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x3h.%ym.nc + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.3h.avrg.%ymd-10800.nc - a2x3h_Sa_z Sa_z - a2x3h_Sa_tbot Sa_tbot - a2x3h_Sa_ptem Sa_ptem - a2x3h_Sa_shum Sa_shum - a2x3h_Sa_pbot Sa_pbot - a2x3h_Sa_dens Sa_dens - a2x3h_Sa_pslv Sa_pslv - a2x3h_Sa_co2diag Sa_co2diag - a2x3h_Sa_co2prog Sa_co2prog + atmImp_Sa_z Sa_z + atmImp_Sa_tbot Sa_tbot + atmImp_Sa_ptem Sa_ptem + atmImp_Sa_shum Sa_shum + atmImp_Sa_pbot Sa_pbot + atmImp_Sa_dens Sa_dens + atmImp_Sa_pslv Sa_pslv + atmImp_Sa_co2diag Sa_co2diag + atmImp_Sa_co2prog Sa_co2prog null @@ -4832,11 +4833,11 @@ $ATM_DOMAIN_MESH - $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.ha2x1h.%ym.nc + $DATM_CPLHIST_DIR/$DATM_CPLHIST_CASE.cpl.hx.atm.1h.avrg.%ymd-03600.nc - a2x1h_Sa_u Sa_u - a2x1h_Sa_v Sa_v + atmImp_Sa_u Sa_u + atmImp_Sa_v Sa_v null diff --git a/datm/datm_datamode_era5_mod.F90 b/datm/datm_datamode_era5_mod.F90 index e10fe3028..b35973248 100644 --- a/datm/datm_datamode_era5_mod.F90 +++ b/datm/datm_datamode_era5_mod.F90 @@ -26,11 +26,17 @@ module datm_datamode_era5_mod real(r8), pointer :: Sa_z(:) => null() real(r8), pointer :: Sa_u10m(:) => null() real(r8), pointer :: Sa_v10m(:) => null() + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() real(r8), pointer :: Sa_wspd10m(:) => null() + real(r8), pointer :: Sa_wspd(:) => null() real(r8), pointer :: Sa_t2m(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() real(r8), pointer :: Sa_tskn(:) => null() real(r8), pointer :: Sa_q2m(:) => null() + real(r8), pointer :: Sa_shum(:) => null() real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() real(r8), pointer :: Faxa_rain(:) => null() real(r8), pointer :: Faxa_rainc(:) => null() real(r8), pointer :: Faxa_rainl(:) => null() @@ -52,10 +58,19 @@ module datm_datamode_era5_mod ! real(r8), pointer :: Faxa_ndep(:,:) => null() ! stream data + real(r8), pointer :: strm_z(:) => null() real(r8), pointer :: strm_tdew(:) => null() - - real(r8) :: t2max ! units detector - real(r8) :: td2max ! units detector + real(r8), pointer :: strm_wind(:) => null() + real(r8), pointer :: strm_wind10m(:) => null() + real(r8), pointer :: strm_u(:) => null() + real(r8), pointer :: strm_v(:) => null() + real(r8), pointer :: strm_u10m(:) => null() + real(r8), pointer :: strm_v10m(:) => null() + + real(r8) :: t2max ! units detector + real(r8) :: td2max ! units detector + real(r8) :: lwmax ! units detector + real(r8) :: precmax ! units detector real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg @@ -89,11 +104,17 @@ subroutine datm_datamode_era5_advertise(exportState, fldsexport, & call dshr_fldList_add(fldsExport, 'Sa_z' ) call dshr_fldList_add(fldsExport, 'Sa_u10m' ) call dshr_fldList_add(fldsExport, 'Sa_v10m' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) call dshr_fldList_add(fldsExport, 'Sa_wspd10m' ) + call dshr_fldList_add(fldsExport, 'Sa_wspd' ) call dshr_fldList_add(fldsExport, 'Sa_t2m' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) call dshr_fldList_add(fldsExport, 'Sa_tskn' ) call dshr_fldList_add(fldsExport, 'Sa_q2m' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) call dshr_fldList_add(fldsExport, 'Faxa_rain' ) call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) @@ -137,7 +158,21 @@ subroutine datm_datamode_era5_init_pointers(exportState, sdat, rc) rc = ESMF_SUCCESS ! initialize pointers for module level stream arrays - call shr_strdata_get_stream_pointer( sdat, 'Sa_tdew' , strm_tdew , rc) + call shr_strdata_get_stream_pointer(sdat, 'Sa_z' , strm_z , rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_tdew' , strm_tdew, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_wspd' , strm_wind, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_wspd10m', strm_wind10m, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_u' , strm_u, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_v' , strm_v, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_u10m' , strm_u10m, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_strdata_get_stream_pointer(sdat, 'Sa_v10m' , strm_v10m, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! get export state pointers @@ -147,16 +182,28 @@ subroutine datm_datamode_era5_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Sa_wspd10m' , fldptr1=Sa_wspd10m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_wspd' , fldptr1=Sa_wspd , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Sa_t2m' , fldptr1=Sa_t2m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Sa_tskn' , fldptr1=Sa_tskn , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Sa_q2m' , fldptr1=Sa_q2m , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , allowNullReturn=.true., rc=rc) @@ -211,9 +258,9 @@ subroutine datm_datamode_era5_advance(exportstate, mainproc, logunit, mpicom, ta ! local variables logical :: first_time = .true. integer :: n ! indices - integer :: lsize ! size of attr vect + integer :: lsize = 0 ! size of attr vect real(r8) :: rtmp(2) - real(r8) :: t2, pslv + real(r8) :: tbot, pbot real(r8) :: e, qsat type(ESMF_VM) :: vm character(len=*), parameter :: subname='(datm_datamode_era5_advance): ' @@ -221,24 +268,66 @@ subroutine datm_datamode_era5_advance(exportstate, mainproc, logunit, mpicom, ta rc = ESMF_SUCCESS - lsize = size(strm_tdew) + ! one of the following needs to be in the stream + if (associated(Sa_z)) lsize = size(Sa_z) + if (associated(strm_tdew)) lsize = size(strm_tdew) + if (mainproc .and. lsize == 0) then + write(logunit,*) trim(subname),' Sa_z or Sa_tdew need to be in the stream! Exiting ...' + end if + if (first_time) then call ESMF_VMGetCurrent(vm, rc=rc) ! determine t2max (see below for use) if (associated(Sa_t2m)) then - rtmp(1) = maxval(Sa_t2m(:)) - - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - t2max = rtmp(2) - if (mainproc) write(logunit,*) trim(subname),' t2max = ',t2max + rtmp(1) = maxval(Sa_t2m(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + t2max = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' t2max = ',t2max end if ! determine tdewmax (see below for use) - rtmp(1) = maxval(strm_tdew(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - td2max = rtmp(2) + if (associated(strm_tdew)) then + rtmp(1) = maxval(strm_tdew(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + td2max = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' td2max = ',td2max + end if - if (mainproc) write(logunit,*) trim(subname),' td2max = ',td2max + ! determine lwmax / lwmax + if (associated(Faxa_lwdn)) then + rtmp(1) = maxval(Faxa_lwdn(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + lwmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' lwmax = ',lwmax + else + ! try with other variable since Faxa_lwdn is not available + if (associated(Faxa_lwnet)) then + rtmp(1) = maxval(Faxa_lwnet(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + lwmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' lwmax = ',lwmax + else + lwmax = 0.0_r8 + end if + end if + + ! determine precmax + if (associated(Faxa_rain)) then + rtmp(1) = maxval(Faxa_rain(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + precmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' precmax = ', precmax + else + ! try with other variable since Faxa_rain is not available + if (associated(Faxa_rainl)) then + rtmp(1) = maxval(Faxa_rainl(:)) + call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) + precmax = rtmp(2) + if (mainproc) write(logunit,*) trim(subname),' precmax = ', precmax + else + precmax = 0.0_r8 + end if + end if ! reset first_time first_time = .false. @@ -246,23 +335,47 @@ subroutine datm_datamode_era5_advance(exportstate, mainproc, logunit, mpicom, ta do n = 1, lsize !--- bottom layer height --- - if (associated(Sa_z)) then - Sa_z(n) = 10.0_r8 + if (.not. associated(strm_z) .and. associated(Sa_z)) then + Sa_z(n) = 10.0_r8 + end if + + !--- calculate wind components if wind speed is provided --- + if (associated(strm_wind)) then + Sa_u(n) = strm_wind(n)/sqrt(2.0_r8) + Sa_v(n) = Sa_u(n) + end if + if (associated(strm_wind10m)) then + Sa_u10m(n) = strm_wind10m(n)/sqrt(2.0_r8) + Sa_v10m(n) = Sa_u10m(n) end if - !--- calculate wind speed --- - if (associated(Sa_wspd10m)) then - Sa_wspd10m(n) = sqrt(Sa_u10m(n)*Sa_u10m(n)+Sa_v10m(n)*Sa_v10m(n)) + !--- calculate wind speed if wind components are provided --- + if (associated(strm_u10m) .and. associated(strm_v10m) .and. associated(Sa_wspd10m)) then + Sa_wspd10m(n) = sqrt(Sa_u10m(n)*Sa_u10m(n)+Sa_v10m(n)*Sa_v10m(n)) + end if + if (associated(strm_u) .and. associated(strm_v) .and. associated(Sa_wspd)) then + Sa_wspd(n) = sqrt(Sa_u(n)*Sa_u(n)+Sa_v(n)*Sa_v(n)) end if - !--- specific humidity at 2m --- - if (associated(Sa_t2m) .and. associated(Sa_pslv) .and. associated(Sa_q2m)) then - t2 = Sa_t2m(n) - pslv = Sa_pslv(n) - if (td2max < 50.0_r8) strm_tdew(n) = strm_tdew(n) + tkFrz - e = datm_eSat(strm_tdew(n), t2) - qsat = (0.622_r8 * e)/(pslv - 0.378_r8 * e) - Sa_q2m(n) = qsat + !--- calculate specific humidity from dew point temperature --- + if (associated(strm_tdew)) then + if (associated(Sa_t2m)) then + tbot = Sa_t2m(n) + else if (associated(Sa_tbot)) then + tbot = Sa_tbot(n) + end if + + if (associated(Sa_pslv)) then + pbot = Sa_pslv(n) + else if (associated(Sa_pbot)) then + pbot = Sa_pbot(n) + end if + + if (td2max < 50.0_r8) strm_tdew(n) = strm_tdew(n) + tkFrz + e = datm_eSat(strm_tdew(n), tbot) + qsat = (0.622_r8 * e)/(pbot - 0.378_r8 * e) + if (associated(Sa_q2m)) Sa_q2m(n) = qsat + if (associated(Sa_shum)) Sa_shum(n) = qsat end if end do @@ -293,23 +406,31 @@ subroutine datm_datamode_era5_advance(exportstate, mainproc, logunit, mpicom, ta !---------------------------------------------------------- ! convert J/m^2 to W/m^2 - if (associated(Faxa_lwdn)) Faxa_lwdn(:) = Faxa_lwdn(:)/3600.0_r8 - if (associated(Faxa_lwnet)) Faxa_lwnet(:) = Faxa_lwnet(:)/3600.0_r8 - if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swvdr(:)/3600.0_r8 - if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swndr(:)/3600.0_r8 - if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swvdf(:)/3600.0_r8 - if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swndf(:)/3600.0_r8 - if (associated(Faxa_swdn)) Faxa_swdn(:) = Faxa_swdn(:)/3600.0_r8 - if (associated(Faxa_swnet)) Faxa_swnet(:) = Faxa_swnet(:)/3600.0_r8 - if (associated(Faxa_sen)) Faxa_sen(:) = Faxa_sen(:)/3600.0_r8 - if (associated(Faxa_lat)) Faxa_lat(:) = Faxa_lat(:)/3600.0_r8 + if (lwmax < 1.0e4_r8) then + if (mainproc) write(logunit,*) trim(subname),' flux related variables are already in W/m^2 unit!' + else + if (associated(Faxa_lwdn)) Faxa_lwdn(:) = Faxa_lwdn(:)/3600.0_r8 + if (associated(Faxa_lwnet)) Faxa_lwnet(:) = Faxa_lwnet(:)/3600.0_r8 + if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swvdr(:)/3600.0_r8 + if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swndr(:)/3600.0_r8 + if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swvdf(:)/3600.0_r8 + if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swndf(:)/3600.0_r8 + if (associated(Faxa_swdn)) Faxa_swdn(:) = Faxa_swdn(:)/3600.0_r8 + if (associated(Faxa_swnet)) Faxa_swnet(:) = Faxa_swnet(:)/3600.0_r8 + if (associated(Faxa_sen)) Faxa_sen(:) = Faxa_sen(:)/3600.0_r8 + if (associated(Faxa_lat)) Faxa_lat(:) = Faxa_lat(:)/3600.0_r8 + end if ! convert m to kg/m^2/s - if (associated(Faxa_rain)) Faxa_rain(:) = Faxa_rain(:)/3600.0_r8*rhofw - if (associated(Faxa_rainc)) Faxa_rainc(:) = Faxa_rainc(:)/3600.0_r8*rhofw - if (associated(Faxa_rainl)) Faxa_rainl(:) = Faxa_rainl(:)/3600.0_r8*rhofw - if (associated(Faxa_snowc)) Faxa_snowc(:) = Faxa_snowc(:)/3600.0_r8*rhofw - if (associated(Faxa_snowl)) Faxa_snowl(:) = Faxa_snowl(:)/3600.0_r8*rhofw + if (precmax < 0.01_r8) then + if (mainproc) write(logunit,*) trim(subname),' precipitation related variables are already in kg/m^2/s unit!' + else + if (associated(Faxa_rain)) Faxa_rain(:) = Faxa_rain(:)/3600.0_r8*rhofw + if (associated(Faxa_rainc)) Faxa_rainc(:) = Faxa_rainc(:)/3600.0_r8*rhofw + if (associated(Faxa_rainl)) Faxa_rainl(:) = Faxa_rainl(:)/3600.0_r8*rhofw + if (associated(Faxa_snowc)) Faxa_snowc(:) = Faxa_snowc(:)/3600.0_r8*rhofw + if (associated(Faxa_snowl)) Faxa_snowl(:) = Faxa_snowl(:)/3600.0_r8*rhofw + end if ! convert N/m^2 s to N/m^2 if (associated(Faxa_taux)) Faxa_taux(:) = Faxa_taux(:)/3600.0_r8 diff --git a/datm/datm_datamode_simple_mod.F90 b/datm/datm_datamode_simple_mod.F90 new file mode 100644 index 000000000..ca978c153 --- /dev/null +++ b/datm/datm_datamode_simple_mod.F90 @@ -0,0 +1,379 @@ +module datm_datamode_simple_mod + + use ESMF , only : ESMF_State, ESMF_StateGet, ESMF_Field, ESMF_FieldBundle + use ESMF , only : ESMF_DistGrid, ESMF_RouteHandle, ESMF_MeshCreate + use ESMF , only : ESMF_Mesh, ESMF_MeshGet, ESMF_MeshCreate + use ESMF , only : ESMF_SUCCESS, ESMF_LogWrite, ESMF_FILEFORMAT_ESMFMESH + use ESMF , only : ESMF_StateItem_Flag, ESMF_STATEITEM_NOTFOUND, operator(/=) + use ESMF , only : ESMF_FieldBundleCreate, ESMF_FieldCreate, ESMF_MESHLOC_ELEMENT + use ESMF , only : ESMF_FieldBundleAdd, ESMF_LOGMSG_INFO, ESMF_TYPEKIND_R8 + use ESMF , only : ESMF_RouteHandleDestroy, ESMF_EXTRAPMETHOD_NEAREST_STOD + use ESMF , only : ESMF_POLEMETHOD_ALLAVG, ESMF_REGRIDMETHOD_BILINEAR + use ESMF , only : ESMF_DistGridGet, ESMF_FieldRegridStore, ESMF_FieldRedistStore + use ESMF , only : ESMF_VM, ESMF_VMBroadcast + use pio , only : Var_Desc_t, file_desc_t, io_desc_t, pio_read_darray, pio_freedecomp + use pio , only : pio_openfile, PIO_NOWRITE, pio_seterrorhandling, PIO_BCAST_ERROR + use pio , only : pio_initdecomp, pio_inq_dimlen, pio_inq_varid + use pio , only : pio_inq_varndims, pio_inq_vardimid, pio_double + use pio , only : pio_closefile + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_sys_mod , only : shr_sys_abort + use shr_cal_mod , only : shr_cal_date2julian + use shr_const_mod , only : shr_const_tkfrz, shr_const_pi + use dshr_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_type + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, dshr_fldbun_regrid, chkerr + use dshr_mod , only : dshr_restart_read, dshr_restart_write + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + + implicit none + private ! except + + public :: datm_datamode_simple_advertise + public :: datm_datamode_simple_init_pointers + public :: datm_datamode_simple_advance + public :: datm_datamode_simple_restart_write + public :: datm_datamode_simple_restart_read + + ! export state pointers + real(r8), pointer :: Sa_u(:) => null() + real(r8), pointer :: Sa_v(:) => null() + real(r8), pointer :: Sa_z(:) => null() + real(r8), pointer :: Sa_tbot(:) => null() + real(r8), pointer :: Sa_ptem(:) => null() + real(r8), pointer :: Sa_shum(:) => null() + real(r8), pointer :: Sa_pbot(:) => null() + real(r8), pointer :: Sa_dens(:) => null() + real(r8), pointer :: Sa_pslv(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + real(r8), pointer :: Faxa_rainc(:) => null() + real(r8), pointer :: Faxa_rainl(:) => null() + real(r8), pointer :: Faxa_snowc(:) => null() + real(r8), pointer :: Faxa_snowl(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_ndep(:,:) => null() + + ! othe module arrays + real(R8), pointer :: yc(:) ! array of model latitudes + real(R8), pointer :: xc(:) ! array of model longitudes + + ! constant forcing values to be set via const_forcing_nml + real(R8) :: dn10 = 1.204_R8 + real(R8) :: slp = 101325.0_R8 + real(R8) :: q = 0.0_R8 + real(R8) :: t = 273.15_R8 + real(R8) :: u = 0.0_R8 + real(R8) :: v = 0.0_R8 + real(R8) :: peak_swdn = 330.0_R8 + real(R8) :: peak_lwdn = 450.0_R8 + + ! constants + real(R8) , parameter :: tKFrz = SHR_CONST_TKFRZ + real(R8) , parameter :: degtorad = SHR_CONST_PI/180.0_R8 + real(R8) , parameter :: phs_c0 = 0.298_R8 + real(R8) , parameter :: dLWarc = -5.000_R8 + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: rpfile = 'rpointer.atm' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine datm_datamode_simple_advertise(exportState, fldsexport, flds_scalar_name, & + nlfilename, my_task, vm, rc) + use shr_nl_mod, only: shr_nl_find_group_name + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + character(len=*) , intent(in) :: nlfilename + integer , intent(in) :: my_task + type(ESMF_VM) , intent(in) :: vm + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + integer , parameter :: main_task = 0 ! task number of main task + integer :: ierr ! error code + integer :: nu ! unit number + character(len=*) , parameter :: subname='(datm_datamode_simple_advertise): ' + real(R8) :: bcasttmp(8) + + !------------------------------------------------------------------------------- + + namelist / const_forcing_nml / dn10, slp, q, t, u, v, peak_swdn, peak_lwdn + + rc = ESMF_SUCCESS + + ! Read const_forcing_nml from nlfilename + if (my_task == main_task) then + open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'const_forcing_nml', status=ierr) + read (nu,nml=const_forcing_nml,iostat=ierr) + close(nu) + if (ierr > 0) then + call shr_sys_abort(subName//': namelist read error '//trim(nlfilename)) + end if + + bcasttmp = 0 + bcasttmp(1) = dn10 + bcasttmp(2) = slp + bcasttmp(3) = q + bcasttmp(4) = t + bcasttmp(5) = u + bcasttmp(6) = v + bcasttmp(7) = peak_swdn + bcasttmp(8) = peak_lwdn + end if + + call ESMF_VMBroadcast(vm, bcasttmp, 8, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + dn10 = bcasttmp(1) + slp = bcasttmp(2) + q = bcasttmp(3) + t = bcasttmp(4) + u = bcasttmp(5) + v = bcasttmp(6) + peak_swdn = bcasttmp(7) + peak_lwdn = bcasttmp(8) + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Sa_z' ) + call dshr_fldList_add(fldsExport, 'Sa_u' ) + call dshr_fldList_add(fldsExport, 'Sa_v' ) + call dshr_fldList_add(fldsExport, 'Sa_ptem' ) + call dshr_fldList_add(fldsExport, 'Sa_dens' ) + call dshr_fldList_add(fldsExport, 'Sa_pslv' ) + call dshr_fldList_add(fldsExport, 'Sa_tbot' ) + call dshr_fldList_add(fldsExport, 'Sa_pbot' ) + call dshr_fldList_add(fldsExport, 'Sa_shum' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainc' ) + call dshr_fldList_add(fldsExport, 'Faxa_rainl' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowc' ) + call dshr_fldList_add(fldsExport, 'Faxa_snowl' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) + call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) + call dshr_fldList_add(fldsExport, 'Faxa_swnet' ) + call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) + call dshr_fldList_add(fldsExport, 'Faxa_swdn' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_simple_advertise + + !=============================================================================== + subroutine datm_datamode_simple_init_pointers(exportState, sdat, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + integer :: spatialDim ! number of dimension in mesh + integer :: numOwnedElements ! size of mesh + real(r8), pointer :: ownedElemCoords(:) ! mesh lat and lons + type(ESMF_StateItem_Flag) :: itemFlag + character(len=*), parameter :: subname='(datm_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = sdat%model_lsize + + call ESMF_MeshGet(sdat%model_mesh, spatialDim=spatialDim, numOwnedElements=numOwnedElements, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + allocate(ownedElemCoords(spatialDim*numOwnedElements)) + allocate(yc(numOwnedElements)) + allocate(xc(numOwnedElements)) + call ESMF_MeshGet(sdat%model_mesh, ownedElemCoords=ownedElemCoords) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + do n = 1,numOwnedElements + yc(n) = ownedElemCoords(2*n) + xc(n) = ownedElemCoords(2*n-1) + end do + + ! get export state pointers + call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_dens' , fldptr1=Sa_dens , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_ptem' , fldptr1=Sa_ptem , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainc' , fldptr1=Faxa_rainc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_rainl' , fldptr1=Faxa_rainl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowc' , fldptr1=Faxa_snowc , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_snowl' , fldptr1=Faxa_snowl , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swnet' , fldptr1=Faxa_swnet , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_StateGet(exportstate, 'Faxa_ndep', itemFlag, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (itemflag /= ESMF_STATEITEM_NOTFOUND) then + call dshr_state_getfldptr(exportState, 'Faxa_ndep', fldptr2=Faxa_ndep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine datm_datamode_simple_init_pointers + + !=============================================================================== + subroutine datm_datamode_simple_advance(target_ymd, target_tod, target_mon, & + model_calendar, rc) + + ! input/output variables + integer , intent(in) :: target_ymd + integer , intent(in) :: target_tod + integer , intent(in) :: target_mon + character(len=*) , intent(in) :: model_calendar + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: lsize + real(R8) :: rday ! elapsed day + character(len=*), parameter :: subname='(datm_datamode_simple): ' + real(R8), parameter :: epsilon_deg = 23.45 ! axial tilt of the Earth + real(R8) :: solar_decl ! solar declination angle (rad) to be used in idealized radiation calculations + real(R8) :: hour_angle ! hour angle (rad) to be used in idealized radiation calculations + real(R8) :: zenith_angle ! solar senith angle (rad) to be used in idealized radiation calculations + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + lsize = size(Sa_z) + + call shr_cal_date2julian(target_ymd, target_tod, rday, model_calendar) + rday = mod((rday - 1.0_R8),365.0_R8) + + do n = 1,lsize + Sa_z(n) = 10.0_R8 + + !--- (i) Set forcing fields to constant values read from the namelist file --- + Sa_dens(n) = dn10 + Sa_pslv(n) = slp + Sa_pbot(n) = Sa_pslv(n) + Sa_shum(n) = q + Sa_tbot(n) = t + Sa_ptem(n) = Sa_tbot(n) + Sa_u(n) = u + Sa_v(n) = v + + !--- (ii) Set precipitation (currently all zeros) --- + + Faxa_rainc(n) = 0.0_R8 ! default zero + Faxa_snowc(n) = 0.0_R8 + if (Sa_tbot(n) < tKFrz ) then ! assign precip to rain/snow components + Faxa_rainl(n) = 0.0_R8 + Faxa_snowl(n) = 0.0_R8 ! todo + else + Faxa_rainl(n) = 0.0_R8 ! todo + Faxa_snowl(n) = 0.0_R8 + endif + + !--- (iii) RADIATION DATA --- + + ! long wave + solar_decl = (epsilon_deg * degtorad) * sin( 2.0_R8 * shr_const_pi * (int(rday) + 284.0_R8) / 365.0_R8) + zenith_angle = acos(sin(yc(n) * degtorad ) * sin(solar_decl) + cos(yc(n) * degtorad) * cos(solar_decl) ) + Faxa_lwdn(n) = max(0.0_R8, peak_lwdn * cos(zenith_angle)) + + ! short wave + hour_angle = (15.0_R8 * (target_tod/3600.0_R8 - 12.0_R8) + xc(n) ) * degtorad + zenith_angle = acos(sin(yc(n) * degtorad ) * sin(solar_decl) + cos(yc(n) * degtorad) * cos(solar_decl) * cos(hour_angle) ) + Faxa_swnet(n) = max(0.0_R8, peak_swdn * cos(zenith_angle)) + Faxa_swvdr(n) = Faxa_swnet(n)*(0.28_R8) + Faxa_swndr(n) = Faxa_swnet(n)*(0.31_R8) + Faxa_swvdf(n) = Faxa_swnet(n)*(0.24_R8) + Faxa_swndf(n) = Faxa_swnet(n)*(0.17_R8) + + enddo ! lsize + + if (associated(Faxa_ndep)) then + ! convert ndep flux to units of kgN/m2/s (input is in gN/m2/s) + Faxa_ndep(:,:) = Faxa_ndep(:,:) / 1000._r8 + end if + + end subroutine datm_datamode_simple_advance + + !=============================================================================== + subroutine datm_datamode_simple_restart_write(case_name, inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + ! input/output variables + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + end subroutine datm_datamode_simple_restart_write + + !=============================================================================== + subroutine datm_datamode_simple_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) + + ! input/output arguments + character(len=*) , intent(inout) :: rest_filem + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) + + end subroutine datm_datamode_simple_restart_read + +end module datm_datamode_simple_mod diff --git a/dice/CMakeLists.txt b/dice/CMakeLists.txt index 02b48d36c..acfc26d47 100644 --- a/dice/CMakeLists.txt +++ b/dice/CMakeLists.txt @@ -19,4 +19,17 @@ add_dependencies(dice dshr streams) target_include_directories (dice PRIVATE ${ESMF_F90COMPILEPATHS}) target_include_directories (dice PRIVATE "${CMAKE_SOURCE_DIR}") target_include_directories (dice PRIVATE "${PIO_Fortran_INCLUDE_DIR}") -target_include_directories (dice PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +if(NOT DISABLE_FoX) + target_include_directories (dice PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL ice_comp_nuopc.mod) + set(MOD cdeps_dice_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/dice/ice_comp_nuopc.F90 b/dice/ice_comp_nuopc.F90 index 266d86495..51ec80361 100644 --- a/dice/ice_comp_nuopc.F90 +++ b/dice/ice_comp_nuopc.F90 @@ -85,6 +85,7 @@ module cdeps_dice_comp character(CL) :: restfilm = nullstr ! model restart file namelist integer :: nx_global integer :: ny_global + logical :: export_all = .false. ! true => export all fields, do not check connected or not ! linked lists type(fldList_type) , pointer :: fldsImport => null() @@ -159,6 +160,7 @@ end subroutine SetServices !=============================================================================== subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + use shr_nl_mod, only: shr_nl_find_group_name ! input/output variables type(ESMF_GridComp) :: gcomp @@ -183,7 +185,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) namelist / dice_nml / datamode, & model_meshfile, model_maskfile, & - restfilm, nx_global, ny_global, flux_swpf, flux_Qmin, flux_Qacc, flux_Qacc0 + restfilm, nx_global, ny_global, & + flux_swpf, flux_Qmin, flux_Qacc, flux_Qacc0, export_all rc = ESMF_SUCCESS @@ -204,6 +207,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (my_task == main_task) then nlfilename = "dice_in"//trim(inst_suffix) open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'dice_nml', status=ierr) + read (nu,nml=dice_nml,iostat=ierr) close(nu) if (ierr > 0) then @@ -212,7 +217,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) end if ! write namelist input to standard out - write(logunit,F00)' datamode = ',trim(datamode) + write(logunit,F00)' datamode = ',trim(datamode) write(logunit,F00)' model_meshfile = ',trim(model_meshfile) write(logunit,F00)' model_maskfile = ',trim(model_maskfile) write(logunit,F01)' nx_global = ',nx_global @@ -222,13 +227,16 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F02)' flux_Qacc = ',flux_Qacc write(logunit,F03)' flux_Qacc0 = ',flux_Qacc0 write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F02)' export_all = ',export_all bcasttmp = 0 bcasttmp(1) = nx_global bcasttmp(2) = ny_global if(flux_Qacc) bcasttmp(3) = 1 + if(export_all) bcasttmp(4) = 1 rbcasttmp(1) = flux_swpf rbcasttmp(2) = flux_Qmin rbcasttmp(3) = flux_Qacc0 + if(export_all) bcasttmp(4) = 1 endif ! broadcast namelist input @@ -243,7 +251,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, rbcasttmp, 3, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -251,12 +259,12 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) nx_global = bcasttmp(1) ny_global = bcasttmp(2) flux_Qacc = (bcasttmp(3) == 1) + export_all= (bcasttmp(4) == 1) flux_swpf = rbcasttmp(1) flux_Qmin = rbcasttmp(2) flux_Qacc0 = rbcasttmp(3) - ! Validate datamode if ( trim(datamode) == 'ssmi' .or. trim(datamode) == 'ssmi_iaf') then if (my_task == main_task) write(logunit,*) ' dice datamode = ',trim(datamode) @@ -327,10 +335,10 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState ! by replacing the advertised fields with the newly created fields of the same name. call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//':diceExport', rc=rc) + subname//':diceExport', export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_fldlist_realize( importState, fldsImport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//':diceImport', rc=rc) + subname//':diceImport', .false., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! for single column, the target point might not be a point where the ice/ocn mask is > 0 diff --git a/dlnd/CMakeLists.txt b/dlnd/CMakeLists.txt index 38d6a416a..865f31e6b 100644 --- a/dlnd/CMakeLists.txt +++ b/dlnd/CMakeLists.txt @@ -17,4 +17,17 @@ add_dependencies(dlnd dshr streams) target_include_directories (dlnd PRIVATE ${ESMF_F90COMPILEPATHS}) target_include_directories (dlnd PRIVATE "${CMAKE_SOURCE_DIR}") target_include_directories (dlnd PRIVATE "${PIO_Fortran_INCLUDE_DIR}") -target_include_directories (dlnd PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +if(NOT DISABLE_FoX) + target_include_directories (dlnd PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL lnd_comp_nuopc.mod) + set(MOD cdeps_dlnd_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/dlnd/lnd_comp_nuopc.F90 b/dlnd/lnd_comp_nuopc.F90 index 320540581..5fe855ddf 100644 --- a/dlnd/lnd_comp_nuopc.F90 +++ b/dlnd/lnd_comp_nuopc.F90 @@ -25,7 +25,7 @@ module cdeps_dlnd_comp use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs use shr_sys_mod , only : shr_sys_abort use shr_cal_mod , only : shr_cal_ymd2date - use shr_log_mod , only : shr_log_setLogUnit + use shr_log_mod , only : shr_log_setLogUnit use dshr_methods_mod , only : dshr_state_getfldptr, dshr_state_diagnose, chkerr, memcheck use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_advance, shr_strdata_get_stream_domain use dshr_strdata_mod , only : shr_strdata_init_from_config @@ -81,6 +81,8 @@ module cdeps_dlnd_comp integer :: nx_global ! global nx dimension of model mesh integer :: ny_global ! global ny dimension of model mesh logical :: skip_restart_read = .false. ! true => skip restart read in continuation + logical :: export_all = .false. ! true => export all fields, do not check connected or not + ! linked lists type(fldList_type) , pointer :: fldsExport => null() type(dfield_type) , pointer :: dfields => null() @@ -155,6 +157,7 @@ end subroutine SetServices !=============================================================================== subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + use shr_nl_mod, only: shr_nl_find_group_name ! input/output variables type(ESMF_GridComp) :: gcomp @@ -166,7 +169,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) type(ESMF_VM) :: vm character(CL) :: cvalue integer :: nu ! unit number - integer :: bcasttmp(3) + integer :: bcasttmp(4) integer :: ierr ! error code character(len=*) , parameter :: subname=trim(modName)//':(InitializeAdvertise) ' character(*) , parameter :: F00 = "('(" // trim(modName) // ") ',8a)" @@ -175,7 +178,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !------------------------------------------------------------------------------- namelist / dlnd_nml / datamode, model_meshfile, model_maskfile, & - nx_global, ny_global, restfilm, skip_restart_read + nx_global, ny_global, restfilm, skip_restart_read, export_all rc = ESMF_SUCCESS @@ -196,6 +199,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (my_task == main_task) then nlfilename = "dlnd_in"//trim(inst_suffix) open (newunit=nu, file=trim(nlfilename), status="old", action="read") + call shr_nl_find_group_name(nu, 'dlnd_nml', status=ierr) + read (nu,nml=dlnd_nml,iostat=ierr) close(nu) if (ierr > 0) then @@ -206,7 +211,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) bcasttmp(1) = nx_global bcasttmp(2) = ny_global if(skip_restart_read) bcasttmp(3) = 1 + if(export_all) bcasttmp(4) = 1 end if + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -218,11 +225,12 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return nx_global = bcasttmp(1) ny_global = bcasttmp(2) skip_restart_read = (bcasttmp(3) == 1) + export_all = (bcasttmp(4) == 1) ! write namelist input to standard out if (my_task == main_task) then @@ -233,6 +241,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F01)' ny_global = ',ny_global write(logunit,F00)' restfilm = ',trim(restfilm) write(logunit,F02)' skip_restart_read = ',skip_restart_read + write(logunit,F02)' export_all = ',export_all endif ! Validate sdat datamode @@ -289,7 +298,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! Realize the actively coupled fields, now that a mesh is established and ! initialize dfields data type (to map streams to export state fields) - call dlnd_comp_realize(importState, exportState, rc=rc) + call dlnd_comp_realize(importState, exportState, export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Read restart if necessary @@ -459,11 +468,12 @@ subroutine dlnd_comp_advertise(importState, exportState, rc) end subroutine dlnd_comp_advertise !=============================================================================== - subroutine dlnd_comp_realize(importState, exportState, rc) + subroutine dlnd_comp_realize(importState, exportState, export_all, rc) ! input/output variables type(ESMF_State) , intent(inout) :: importState type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: export_all integer , intent(out) :: rc ! local variables @@ -478,7 +488,7 @@ subroutine dlnd_comp_realize(importState, exportState, rc) ! ------------------------------------- call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//':dlndExport', rc=rc) + subname//':dlndExport', export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end subroutine dlnd_comp_realize diff --git a/docn/CMakeLists.txt b/docn/CMakeLists.txt index b8a2b44ee..007d595ca 100644 --- a/docn/CMakeLists.txt +++ b/docn/CMakeLists.txt @@ -23,4 +23,17 @@ add_dependencies(docn dshr streams) target_include_directories (docn PRIVATE ${ESMF_F90COMPILEPATHS}) target_include_directories (docn PRIVATE ${CMAKE_SOURCE_DIR}) target_include_directories (docn PRIVATE ${PIO_Fortran_INCLUDE_DIR}) -target_include_directories (docn PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +if(NOT DISABLE_FoX) + target_include_directories (docn PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL ocn_comp_nuopc.mod) + set(MOD cdeps_docn_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/docn/cime_config/config_component.xml b/docn/cime_config/config_component.xml index a06201aaa..0e03abf26 100644 --- a/docn/cime_config/config_component.xml +++ b/docn/cime_config/config_component.xml @@ -155,12 +155,12 @@ $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_clim_c040926.nc $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_clim_c061106.nc $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_clim_c110526.nc - $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1x1_1850_2012_c130411.nc - $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_48x96_1850_2012_c130411.nc - $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_1850_2012_c130411.nc - $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_1850_2012_c130411.nc - $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_1850_2012_c130411.nc - $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_1850_2012_c130411.nc + $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1x1_1850_2021_c120422.nc + $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_48x96_1850_2021_c120422.nc + $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_1850_2021_c120422.nc + $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.9x1.25_1850_2021_c120422.nc + $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.47x0.63_1850_2021_c120422.nc + $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_0.23x0.31_1850_2021_c120422.nc $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1x1_clim_pi_c101029.nc $DIN_LOC_ROOT/ocn/docn7/SSTDATA/sst_ice_CMIP6_DECK_E3SM_1x1_1850_clim_c20190125.nc $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_48x96_clim_pi_c101028.nc @@ -240,7 +240,7 @@ 0 - 2012 + 2021 run_component_cam_sstice env_run.xml diff --git a/docn/ocn_comp_nuopc.F90 b/docn/ocn_comp_nuopc.F90 index d885b248b..a5e50ce50 100644 --- a/docn/ocn_comp_nuopc.F90 +++ b/docn/ocn_comp_nuopc.F90 @@ -103,6 +103,7 @@ module cdeps_docn_comp integer :: nx_global integer :: ny_global logical :: skip_restart_read = .false. ! true => skip restart read in continuation run + logical :: export_all = .false. ! true => export all fields, do not check connected or not ! linked lists type(fldList_type) , pointer :: fldsImport => null() @@ -177,7 +178,7 @@ end subroutine SetServices !=============================================================================== subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) - + use shr_nl_mod, only: shr_nl_find_group_name ! input/output variables type(ESMF_GridComp) :: gcomp type(ESMF_State) :: importState, exportState @@ -189,7 +190,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) integer :: nu ! unit number integer :: ierr ! error code character(len=CL) :: import_data_fields ! colon deliminted strings of input data fields - integer :: bcasttmp(3) + integer :: bcasttmp(4) real(r8) :: rtmp(1) type(ESMF_VM) :: vm character(len=*),parameter :: subname=trim(module_name)//':(InitializeAdvertise) ' @@ -202,7 +203,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) namelist / docn_nml / datamode, & model_meshfile, model_maskfile, & restfilm, nx_global, ny_global, sst_constant_value, skip_restart_read, & - import_data_fields + import_data_fields, export_all rc = ESMF_SUCCESS @@ -223,6 +224,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) ! Read docn_nml from nlfilename nlfilename = "docn_in"//trim(inst_suffix) open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'docn_nml', status=ierr) read (nu,nml=docn_nml,iostat=ierr) close(nu) if (ierr > 0) then @@ -241,12 +243,15 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,F02)' skip_restart_read = ',skip_restart_read write(logunit,F00)' import_data_fields = ',trim(import_data_fields) write(logunit,*) ' sst_constant_value = ',sst_constant_value + write(logunit,F02)' export_all = ', export_all bcasttmp = 0 bcasttmp(1) = nx_global bcasttmp(2) = ny_global if(skip_restart_read) bcasttmp(3) = 1 + if(export_all) bcasttmp(4) = 1 rtmp(1) = sst_constant_value + if(export_all) bcasttmp(4) = 1 endif ! Broadcast namelist input @@ -264,15 +269,15 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call ESMF_VMBroadcast(vm, import_data_fields, CL, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, rtmp, 1, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return nx_global = bcasttmp(1) ny_global = bcasttmp(2) skip_restart_read = (bcasttmp(3) == 1) + export_all = (bcasttmp(4) == 1) sst_constant_value = rtmp(1) ! Special logic for prescribed aquaplanet @@ -390,10 +395,10 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState ! by replacing the advertised fields with the newly created fields of the same name. call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//trim(modelname)//':Export', rc=rc) + subname//trim(modelname)//':Export', export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_fldlist_realize( importState, fldsImport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//trim(modelname)//':Import', rc=rc) + subname//trim(modelname)//':Import', .false., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! for single column, the target point might not be a valid ocn point diff --git a/drof/CMakeLists.txt b/drof/CMakeLists.txt index 6cfc91167..444c855e6 100644 --- a/drof/CMakeLists.txt +++ b/drof/CMakeLists.txt @@ -17,4 +17,17 @@ add_dependencies(drof dshr streams) target_include_directories (drof PRIVATE ${ESMF_F90COMPILEPATHS}) target_include_directories (drof PRIVATE "${CMAKE_SOURCE_DIR}") target_include_directories (drof PRIVATE "${PIO_Fortran_INCLUDE_DIR}") +if(NOT DISABLE_FoX) target_include_directories (drof PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL rof_comp_nuopc.mod) + set(MOD cdeps_drof_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/drof/cime_config/config_component.xml b/drof/cime_config/config_component.xml index 8400ada9d..c87e1f1c6 100644 --- a/drof/cime_config/config_component.xml +++ b/drof/cime_config/config_component.xml @@ -13,7 +13,7 @@ --> - Data runoff model + Data runoff model NULL mode COREv2 normal year forcing: COREv2 interannual year forcing: diff --git a/drof/rof_comp_nuopc.F90 b/drof/rof_comp_nuopc.F90 index 2dbe97d3c..f6e9e7cd1 100644 --- a/drof/rof_comp_nuopc.F90 +++ b/drof/rof_comp_nuopc.F90 @@ -76,6 +76,8 @@ module cdeps_drof_comp integer :: nx_global integer :: ny_global logical :: skip_restart_read = .false. ! true => skip restart read + logical :: export_all = .false. ! true => export all fields, do not check connected or not + logical :: diagnose_data = .true. integer , parameter :: main_task=0 ! task number of main task character(*) , parameter :: rpfile = 'rpointer.rof' @@ -151,7 +153,7 @@ end subroutine SetServices !=============================================================================== subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) - + use shr_nl_mod, only: shr_nl_find_group_name ! input/output variables type(ESMF_GridComp) :: gcomp type(ESMF_State) :: importState, exportState @@ -164,7 +166,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) integer :: ierr ! error code type(fldlist_type), pointer :: fldList type(ESMF_VM) :: vm - integer :: bcasttmp(3) + integer :: bcasttmp(4) character(len=*),parameter :: subname=trim(modName)//':(InitializeAdvertise) ' character(*) ,parameter :: F00 = "('(" // trim(modName) // ") ',8a)" character(*) ,parameter :: F01 = "('(" // trim(modName) // ") ',a,2x,i8)" @@ -172,7 +174,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !------------------------------------------------------------------------------- namelist / drof_nml / datamode, model_meshfile, model_maskfile, & - restfilm, nx_global, ny_global, skip_restart_read + restfilm, nx_global, ny_global, skip_restart_read, export_all rc = ESMF_SUCCESS @@ -193,6 +195,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (mainproc) then nlfilename = "drof_in"//trim(inst_suffix) open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'drof_nml', status=ierr) read (nu,nml=drof_nml,iostat=ierr) close(nu) if (ierr > 0) then @@ -201,17 +204,19 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) end if ! write namelist input to standard out - write(logunit,F00)' datamode = ',trim(datamode) + write(logunit,F00)' datamode = ',trim(datamode) write(logunit,F00)' model_meshfile = ',trim(model_meshfile) write(logunit,F00)' model_maskfile = ',trim(model_maskfile) write(logunit,F01)' nx_global = ',nx_global write(logunit,F01)' ny_global = ',ny_global write(logunit,F00)' restfilm = ',trim(restfilm) write(logunit,F02)' skip_restart_read = ',skip_restart_read + write(logunit,F02)' export_all = ', export_all bcasttmp = 0 bcasttmp(1) = nx_global bcasttmp(2) = ny_global if(skip_restart_read) bcasttmp(3) = 1 + if(export_all) bcasttmp(4) = 1 end if ! broadcast namelist input @@ -226,12 +231,13 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + nx_global = bcasttmp(1) ny_global = bcasttmp(2) skip_restart_read = (bcasttmp(3) == 1) - + export_all = (bcasttmp(4) == 1) ! Validate datamode if (trim(datamode) == 'copyall') then @@ -294,7 +300,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! NUOPC_Realize "realizes" a previously advertised field in the importState and exportState ! by replacing the advertised fields with the newly created fields of the same name. call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//':drofExport', rc=rc) + subname//':drofExport', export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Get the time to interpolate the stream data to diff --git a/dshr/dshr_fldlist_mod.F90 b/dshr/dshr_fldlist_mod.F90 index 11b0ab5e3..398e1ce61 100644 --- a/dshr/dshr_fldlist_mod.F90 +++ b/dshr/dshr_fldlist_mod.F90 @@ -53,7 +53,7 @@ end subroutine dshr_fldlist_add !=============================================================================== - subroutine dshr_fldlist_realize(state, fldLists, flds_scalar_name, flds_scalar_num, mesh, tag, rc) + subroutine dshr_fldlist_realize(state, fldLists, flds_scalar_name, flds_scalar_num, mesh, tag, export_all, rc) ! input/output variables type(ESMF_State) , intent(inout) :: state @@ -62,6 +62,7 @@ subroutine dshr_fldlist_realize(state, fldLists, flds_scalar_name, flds_scalar_n integer , intent(in) :: flds_scalar_num type(ESMF_Mesh) , intent(in) :: mesh character(len=*) , intent(in) :: tag + logical , intent(in) :: export_all integer , intent(inout) :: rc ! local variables @@ -77,7 +78,13 @@ subroutine dshr_fldlist_realize(state, fldLists, flds_scalar_name, flds_scalar_n do while (associated(fldList)) stdname = fldList%stdname - if (NUOPC_IsConnected(state, fieldName=stdname)) then + if (NUOPC_IsConnected(state, fieldName=stdname) .or. export_all) then + ! Check field name since linked list might have empty string + if (trim(stdname) == '') then + fldList => fldList%next + cycle + end if + if (stdname == trim(flds_scalar_name)) then call ESMF_LogWrite(trim(subname)//trim(tag)//" Field = "//trim(stdname)//" is connected on root pe", & ESMF_LOGMSG_INFO) diff --git a/dshr/dshr_mod.F90 b/dshr/dshr_mod.F90 index 579296a9a..f253adc05 100644 --- a/dshr/dshr_mod.F90 +++ b/dshr/dshr_mod.F90 @@ -1346,7 +1346,7 @@ subroutine dshr_orbital_update(Time, logunit, maintask, eccen, obliqr, lambm0, integer :: orb_year ! orbital year for current orbital computation character(len=CL) :: msgstr ! temporary logical :: lprint - logical :: first_time = .true. + logical, save :: first_time = .true. character(len=*) , parameter :: subname = "(dshr_orbital_update)" !------------------------------------------- diff --git a/dwav/CMakeLists.txt b/dwav/CMakeLists.txt index 676b30040..2d96bf3a6 100644 --- a/dwav/CMakeLists.txt +++ b/dwav/CMakeLists.txt @@ -17,4 +17,17 @@ add_dependencies(dwav dshr streams) target_include_directories (dwav PRIVATE ${ESMF_F90COMPILEPATHS}) target_include_directories (dwav PRIVATE "${CMAKE_SOURCE_DIR}") target_include_directories (dwav PRIVATE "${PIO_Fortran_INCLUDE_DIR}") +if(NOT DISABLE_FoX) target_include_directories (dwav PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + +if(BLD_STANDALONE) + # ESMX requires mod files + foreach (SRC ${SRCFILES}) + string(REGEX REPLACE "[.]F90$" ".mod" MOD ${SRC}) + if (NOT DEFINED CIMEROOT AND MOD STREQUAL wav_comp_nuopc.mod) + set(MOD cdeps_dwav_comp.mod) + endif() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${MOD}" DESTINATION include) + endforeach () +endif() diff --git a/dwav/wav_comp_nuopc.F90 b/dwav/wav_comp_nuopc.F90 index abf1a029f..351e7c82e 100644 --- a/dwav/wav_comp_nuopc.F90 +++ b/dwav/wav_comp_nuopc.F90 @@ -77,6 +77,8 @@ module cdeps_dwav_comp integer :: nx_global integer :: ny_global logical :: skip_restart_read = .false. ! true => skip restart read + logical :: export_all = .false. ! true => export all fields, do not check connected or not + ! constants logical :: diagnose_data = .true. integer , parameter :: main_task=0 ! task number of main task @@ -149,6 +151,7 @@ end subroutine SetServices !=============================================================================== subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) + use shr_nl_mod, only: shr_nl_find_group_name ! input/output variables type(ESMF_GridComp) :: gcomp @@ -161,7 +164,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) integer :: nu ! unit number integer :: ierr ! error code type(ESMF_VM) :: vm - integer :: bcasttmp(3) + integer :: bcasttmp(4) character(len=*),parameter :: subname=trim(modName)//':(InitializeAdvertise) ' character(*) ,parameter :: F00 = "('(" // trim(modName) // ") ',8a)" character(*) ,parameter :: F01 = "('(" // trim(modName) // ") ',a,2x,i8)" @@ -169,7 +172,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) !------------------------------------------------------------------------------- namelist / dwav_nml / datamode, model_meshfile, model_maskfile, & - restfilm, nx_global, ny_global, skip_restart_read + restfilm, nx_global, ny_global, skip_restart_read, export_all rc = ESMF_SUCCESS @@ -190,6 +193,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (my_task == main_task) then nlfilename = "dwav_in"//trim(inst_suffix) open (newunit=nu,file=trim(nlfilename),status="old",action="read") + call shr_nl_find_group_name(nu, 'dwav_nml', status=ierr) read (nu,nml=dwav_nml,iostat=ierr) close(nu) if (ierr > 0) then @@ -198,17 +202,19 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) end if ! write namelist input to standard out - write(logunit,F00)' datamode = ',trim(datamode) + write(logunit,F00)' datamode = ',trim(datamode) write(logunit,F00)' model_meshfile = ',trim(model_meshfile) write(logunit,F00)' model_maskfile = ',trim(model_maskfile) - write(logunit,F01)' nx_global = ',nx_global - write(logunit,F01)' ny_global = ',ny_global - write(logunit,F00)' restfilm = ',trim(restfilm) + write(logunit,F01)' nx_global = ',nx_global + write(logunit,F01)' ny_global = ',ny_global + write(logunit,F00)' restfilm = ',trim(restfilm) write(logunit,F02)' skip_restart_read = ',skip_restart_read + write(logunit,F02)' export_all = ', export_all bcasttmp = 0 bcasttmp(1) = nx_global bcasttmp(2) = ny_global if(skip_restart_read) bcasttmp(3) = 1 + if(export_all) bcasttmp(4) = 1 endif ! broadcast namelist input @@ -223,11 +229,13 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CL, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + nx_global = bcasttmp(1) ny_global = bcasttmp(2) skip_restart_read = (bcasttmp(3) == 1) + export_all = (bcasttmp(4) == 1) ! Call advertise phase if (trim(datamode) == 'copyall') then @@ -278,7 +286,7 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) ! Realize the actively coupled fields, now that a mesh is established and ! initialize dfields data type (to map streams to export state fields) - call dwav_comp_realize(importState, exportState, rc=rc) + call dwav_comp_realize(importState, exportState, export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Read restart if necessary @@ -427,11 +435,12 @@ subroutine dwav_comp_advertise(importState, exportState, rc) end subroutine dwav_comp_advertise !=============================================================================== - subroutine dwav_comp_realize(importState, exportState, rc) + subroutine dwav_comp_realize(importState, exportState, export_all, rc) ! input/output variables type(ESMF_State) , intent(inout) :: importState type(ESMF_State) , intent(inout) :: exportState + logical , intent(in) :: export_all integer , intent(out) :: rc ! local variables @@ -446,7 +455,7 @@ subroutine dwav_comp_realize(importState, exportState, rc) ! ------------------------------------- call dshr_fldlist_realize( exportState, fldsExport, flds_scalar_name, flds_scalar_num, model_mesh, & - subname//':dwavExport', rc=rc) + subname//':dwavExport', export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! Create stream-> export state mapping diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index 215847dae..6d1c3607d 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -5,10 +5,12 @@ set (GenF90_SRCS shr_infnan_mod.F90 shr_assert_mod.F90) add_library(cdeps_share ${GenF90_SRCS} + shr_nl_mod.F90 glc_elevclass_mod.F90 shr_timer_mod.F90 shr_cal_mod.F90 shr_kind_mod.F90 + shr_file_mod.F90 shr_sys_mod.F90 shr_abort_mod.F90 shr_const_mod.F90 diff --git a/share/shr_file_mod.F90 b/share/shr_file_mod.F90 new file mode 100644 index 000000000..c76bfca58 --- /dev/null +++ b/share/shr_file_mod.F90 @@ -0,0 +1,1048 @@ +! !MODULE: shr_file_mod.F90 --- Module to handle various file utilily functions. +! +! !DESCRIPTION: +! +! Miscilaneous methods to handle file and directory utilities as well as FORTRAN +! unit control. Also put/get local files into/from archival location +! +! File utilites used with CCSM Message passing: +! +! shr_file_stdio is the main example here, it changes the working directory, +! changes stdin and stdout to a given filename. +! +! This is needed because some implementations of MPI with MPMD so that +! each executable can run in a different working directory and redirect +! output to different files. +! +! File name archival convention, eg. +! call shr_file_put(rcode,"foo","mss:/USER/foo",rtpd=3650) +! is extensible -- the existence of the option file name prefix, eg. "mss:", +! and optional arguments, eg. rtpd-3650 can be used to access site-specific +! storage devices. Based on CCM (atmosphere) getfile & putfile routines, but +! intended to be a more extensible, shared code. +! +! !REVISION HISTORY: +! 2006-05-08 E. Kluzek, Add in shr_file_mod and getUnit, freeUnif methods. +! 2000-??-?? B. Kauffman, original version circa 2000 +! +! !INTERFACE: ------------------------------------------------------------------ + +MODULE shr_file_mod + + ! !USES: + + use shr_kind_mod ! defines kinds + use shr_sys_mod ! system calls + use shr_log_mod, only: s_loglev => shr_log_Level + use shr_log_mod, only: s_logunit => shr_log_Unit + + IMPLICIT none + + PRIVATE ! By default everything is private to this module + + ! !PUBLIC TYPES: + + ! no public types + + ! !PUBLIC MEMBER FUNCTIONS: + + public :: shr_file_put ! Put a file to an archive location + public :: shr_file_get ! Get a file from an archive location + public :: shr_file_queryPrefix ! Get prefix type for a filename + public :: shr_file_getUnit ! Get a logical unit for reading or writing + public :: shr_file_freeUnit ! Free a logical unit + public :: shr_file_stdio ! change dir and stdin and stdout + public :: shr_file_chDir ! change current working directory + public :: shr_file_dirio ! change stdin and stdout + public :: shr_file_chStdIn ! change stdin (attach to a file) + public :: shr_file_chStdOut ! change stdout (attach to a file) + public :: shr_file_setIO ! open a log file from namelist + public :: shr_file_setLogUnit ! Reset the log unit number + public :: shr_file_setLogLevel ! Reset the logging debug level + public :: shr_file_getLogUnit ! Get the log unit number + public :: shr_file_getLogLevel ! Get the logging debug level + public :: shr_file_get_real_path ! Get a fully resolved path +#if defined NEMO_IN_CCSM + public :: shr_file_maxUnit ! Max unit number to give +#endif + + ! !PUBLIC DATA MEMBERS: + + ! Integer flags for recognized prefixes on file get/put operations + integer(SHR_KIND_IN), parameter, public :: shr_file_noPrefix = 0 ! no recognized prefix + integer(SHR_KIND_IN), parameter, public :: shr_file_nullPrefix = 1 ! null: + integer(SHR_KIND_IN), parameter, public :: shr_file_cpPrefix = 2 ! cp: + integer(SHR_KIND_IN), parameter, public :: shr_file_mssPrefix = 3 ! mss: + integer(SHR_KIND_IN), parameter, public :: shr_file_hpssPrefix = 4 ! hpss: + + !EOP + !--- unit numbers, users can ask for unit numbers from 0 to min, but getUnit + !--- won't give a unit below min, users cannot ask for unit number above max + !--- for backward compatability. + !--- eventually, recommend min as hard lower limit (tcraig, 9/2007) + integer(SHR_KIND_IN),parameter :: shr_file_minUnit = 10 ! Min unit number to give + integer(SHR_KIND_IN),parameter :: shr_file_maxUnit = 99 ! Max unit number to give + logical, save :: UnitTag(0:shr_file_maxUnit) = .false. ! Logical units in use + + !=============================================================================== +CONTAINS + !=============================================================================== + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_put -- Put a file to an archival location. + ! + ! !DESCRIPTION: + ! a generic, extensible put-local-file-into-archive routine + ! USAGE: + ! call shr_file_put(rcode,"foo","/home/user/foo") + ! if ( rcode /= 0 ) call shr_sys_abort( "error copying foo" ) + ! call shr_file_put(rcode,"foo","cp:/home/user/foo",remove=.true.) + ! if ( rcode /= 0 ) call shr_sys_abort( "error copying foo" ) + ! call shr_file_put(rcode,"foo","mss:/USER/foo",rtpd=3650) + ! if ( rcode /= 0 ) call shr_sys_abort( "error archiving foo to MSS" ) + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_put(rcode,loc_fn,rem_fn,passwd,rtpd,async,remove) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(out) :: rcode ! return code (non-zero -- error) + character(*), intent(in) :: loc_fn ! local filename + character(*), intent(in) :: rem_fn ! remote filename + character(*), intent(in),optional :: passwd ! password + integer(SHR_KIND_IN),intent(in),optional :: rtpd ! MSS retention period + logical, intent(in),optional :: async ! true <=> asynchronous put + logical, intent(in),optional :: remove ! true <=> rm after put + + !EOP + + !----- local ----- + integer(SHR_KIND_IN) :: rtpd2 ! MSS retention period + logical :: remove2 ! true <=> rm after put + logical :: async2 ! true <=> asynchronous put + character(SHR_KIND_CL) :: passwd2 ! password + character(SHR_KIND_CL) :: rfn ! rem_fn without the destination prefix + character(SHR_KIND_CL) :: cmd ! command sent to system call + integer(SHR_KIND_IN) :: prefix ! remote file prefix type + + !----- formats ----- + character(*),parameter :: subName = '(shr_file_put) ' + character(*),parameter :: F00 = "('(shr_file_put) ',4a)" + character(*),parameter :: F01 = "('(shr_file_put) ',a,i3,2a)" + character(*),parameter :: F02 = "(a,i4)" + + !------------------------------------------------------------------------------- + ! Notes: + ! - On some machines the system call will not return a valid error code + ! - when things are sent asynchronously, there probably won't be a error code + ! returned. + !------------------------------------------------------------------------------- + + remove2 =.false. ; if ( PRESENT(remove )) remove2 = remove + async2 =.true. ; if ( PRESENT(async )) async2 = async + passwd2 = " " ; if ( PRESENT(passwd )) passwd2 = passwd + rtpd2 = 365 ; if ( PRESENT(rtpd )) rtpd2 = rtpd + rcode = 0 + prefix = shr_file_queryPrefix( rem_fn ) + + if ( trim(rem_fn) == trim(loc_fn) ) then + !------------------------------------------------------ + ! (remote file name) == (local file name) => do nothing + !------------------------------------------------------ + cmd = 'do nothing: remote file = local file = '//trim(loc_fn) + rcode = 0 + else if ( prefix == shr_file_cpPrefix .or. prefix == shr_file_noPrefix )then + !------------------------------------------------------ + ! put via unix cp + !------------------------------------------------------ + rfn = rem_fn + if ( rem_fn(1:3) == "cp:") rfn = rem_fn(4:len_trim(rem_fn)) + cmd = '/bin/cp -f '//trim(loc_fn)//' '//trim(rfn) + if (remove2) cmd = trim(cmd)//' && /bin/rm -f '//trim(loc_fn) + if (async2 ) cmd = trim(cmd)//' & ' + call shr_sys_system(trim(cmd),rcode) + else if ( prefix == shr_file_mssPrefix )then + !------------------------------------------------------ + ! put onto NCAR's MSS + !------------------------------------------------------ + if (rtpd2 > 9999) rtpd2 = 9999 + write(cmd,F02) '/usr/local/bin/msrcp -period ',rtpd2 + if (async2 .and. (.not. remove2) ) cmd = trim(cmd)//' -async ' + if (len_trim(passwd2) > 0 ) cmd = trim(cmd)//' -wpwd '//trim(passwd) + cmd = trim(cmd)//' '//trim(loc_fn)//' '//trim(rem_fn) + if (remove2) cmd = trim(cmd)//' && /bin/rm -f '//trim(loc_fn) + if (async2 .and. remove2 ) cmd = trim(cmd)//' & ' + call shr_sys_system(trim(cmd),rcode) + else if ( prefix == shr_file_hpssPrefix )then + !------------------------------------------------------ + ! put onto LANL's hpss + !------------------------------------------------------ + rcode = -1 + cmd = 'rem_fn='//trim(rem_fn)//' loc_fn='//trim(loc_fn) + write(s_logunit,F00) 'ERROR: hpss option not yet implemented' + call shr_sys_abort( subName//'ERROR: hpss option not yet implemented' ) + else if ( prefix == shr_file_nullPrefix )then + ! do nothing + cmd = "null prefix => no file archival, do nothing" + rcode = 0 + end if + + if (s_loglev > 0) write(s_logunit,F01) 'rcode =',rcode,' cmd = ', trim(cmd) + + END SUBROUTINE shr_file_put + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_get -- Get a file from archival location. + ! + ! !DESCRIPTION: + ! a generic, extensible get-local-file-from-archive routine + ! + ! USAGE: + ! call shr_file_get(rcode,"foo","/home/user/foo") + ! if ( rcode /= 0 ) call shr_sys_abort( "error getting file foo" ) + ! call shr_file_get(rcode,"foo","cp:/home/user/foo",remove=.true.) + ! if ( rcode /= 0 ) call shr_sys_abort( "error getting file foo" ) + ! call shr_file_get(rcode,"foo","mss:/USER/foo",clobber=.true.) + ! if ( rcode /= 0 ) call shr_sys_abort( "error getting file foo from MSS" ) + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_get(rcode,loc_fn,rem_fn,passwd,async,clobber) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(out) :: rcode ! return code (non-zero means error) + character(*) ,intent(in) :: loc_fn ! local filename + character(*) ,intent(in) :: rem_fn ! remote filename + character(*) ,intent(in),optional :: passwd ! password + logical ,intent(in),optional :: async ! true <=> asynchronous get + logical ,intent(in),optional :: clobber ! true <=> clobber existing file + + !EOP + + !----- local ----- + logical :: async2 ! true <=> asynchronous get + logical :: clobber2 ! true <=> clobber existing file + logical :: exists ! true <=> local file a ready exists + character(SHR_KIND_CL) :: passwd2 ! password + character(SHR_KIND_CL) :: rfn ! rem_fn without the destination prefix + character(SHR_KIND_CL) :: cmd ! command sent to system call + integer(SHR_KIND_IN) :: prefix ! remote file prefix type + + !----- formats ----- + character(*),parameter :: subName = '(shr_file_get) ' + character(*),parameter :: F00 = "('(shr_file_get) ',4a)" + character(*),parameter :: F01 = "('(shr_file_get) ',a,i3,2a)" + + !------------------------------------------------------------------------------- + ! Notes: + ! - On some machines the system call will not return a valid error code + ! - When things are sent asynchronously, there probably won't be a error code + ! returned. + !------------------------------------------------------------------------------- + + passwd2 = " " ; if (PRESENT(passwd )) passwd2 = passwd + async2 = .false. ; if (PRESENT(async )) async2 = async + clobber2 = .false. ; if (PRESENT(clobber)) clobber2 = clobber + rcode = 0 + + inquire(file=trim(loc_fn),exist=exists) + prefix = shr_file_queryPrefix( rem_fn ) + + if ( exists .and. .not. clobber2 ) then + !------------------------------------------------------ + ! (file exists) and (don't clobber) => do nothing + !------------------------------------------------------ + cmd = 'do nothing: file exists & no-clobber for '//trim(loc_fn) + rcode = 0 + else if ( trim(rem_fn) == trim(loc_fn) ) then + !------------------------------------------------------ + ! (remote file name) == (local file name) => do nothing + !------------------------------------------------------ + cmd = 'do nothing: remote file = local file for '//trim(loc_fn) + rcode = 0 + else if ( prefix == shr_file_cpPrefix .or. prefix == shr_file_noPrefix )then + !------------------------------------------------------ + ! get via unix cp + !------------------------------------------------------ + rfn = rem_fn ! remove prefix from this temp file name + if (rem_fn(1:3) == "cp:") rfn = rem_fn(4:len_trim(rem_fn)) + cmd = '/bin/cp -f '//trim(rfn)//' '//trim(loc_fn) + if (async2) cmd = trim(cmd)//' & ' + call shr_sys_system(trim(cmd),rcode) + else if ( prefix == shr_file_mssPrefix )then + !------------------------------------------------------ + ! get from NCAR's MSS + !------------------------------------------------------ + cmd = '/usr/local/bin/msrcp ' + if (async2) cmd = trim(cmd)//' -async ' + cmd = trim(cmd)//' '//trim(rem_fn)//' '//trim(loc_fn) + call shr_sys_system(trim(cmd),rcode) + else if ( prefix == shr_file_hpssPrefix )then + !------------------------------------------------------ + ! get from LANL's hpss + !------------------------------------------------------ + rcode = -1 + cmd = 'rem_fn='//trim(rem_fn)//' loc_fn='//trim(loc_fn) + write(s_logunit,F00) 'ERROR: hpss option not yet implemented' + call shr_sys_abort( subName//'ERROR: hpss option not yet implemented' ) + else if ( prefix == shr_file_nullPrefix )then + ! do nothing + cmd = "null prefix => no file retrieval, do nothing" + rcode = 0 + end if + + if (s_loglev > 0) write(s_logunit,F01) 'rcode =',rcode,' cmd = ', trim(cmd) + + END SUBROUTINE shr_file_get + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_queryPrefix -- Get the prefix type from a filepath. + ! + ! !DESCRIPTION: + ! + ! !INTERFACE: ------------------------------------------------------------------ + + integer(SHR_KIND_IN) FUNCTION shr_file_queryPrefix( filepath, prefix ) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + character(*), intent(in) :: filepath ! Input filepath + character(*), intent(out), optional :: prefix ! Output prefix description + + !EOP + + !----- local ----- + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + if ( filepath(1:5) == "null:" )then + shr_file_queryPrefix = shr_file_nullPrefix + if ( present(prefix) ) prefix = "null:" + else if( filepath(1:3) == "cp:" )then + shr_file_queryPrefix = shr_file_cpPrefix + if ( present(prefix) ) prefix = "cp:" + else if( filepath(1:4) == "mss:" )then + shr_file_queryPrefix = shr_file_mssPrefix + if ( present(prefix) ) prefix = "mss:" + else if( filepath(1:5) == "hpss:" )then + shr_file_queryPrefix = shr_file_hpssPrefix + if ( present(prefix) ) prefix = "hpss:" + else + shr_file_queryPrefix = shr_file_noPrefix + if ( present(prefix) ) prefix = "" + end if + + END FUNCTION shr_file_queryPrefix + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_getUnit -- Get a free FORTRAN unit number + ! + ! !DESCRIPTION: Get the next free FORTRAN unit number. + ! + ! !REVISION HISTORY: + ! 2005-Dec-14 - E. Kluzek - creation + ! + ! !INTERFACE: ------------------------------------------------------------------ + + INTEGER FUNCTION shr_file_getUnit ( unit ) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(in),optional :: unit ! desired unit number + + !EOP + + !----- local ----- + integer(SHR_KIND_IN) :: n ! loop index + logical :: opened ! If unit opened or not + + !----- formats ----- + character(*),parameter :: subName = '(shr_file_getUnit) ' + character(*),parameter :: F00 = "('(shr_file_getUnit) ',A,I4,A)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + shr_file_getUnit = -1 + if (present (unit)) then + inquire( unit, opened=opened ) + if (unit < 0 .or. unit > shr_file_maxUnit) then + write(s_logunit,F00) 'invalid unit number request:', unit + call shr_sys_abort( 'ERROR: bad input unit number' ) + else if (opened .or. UnitTag(unit) .or. unit == 0 .or. unit == 5 & + .or. unit == 6) then + write(s_logunit,F00) 'unit number ', unit, ' is already in use' + call shr_sys_abort( 'ERROR: Input unit number already in use' ) + else + shr_file_getUnit = unit + UnitTag (unit) = .true. + return + end if + + else + ! --- Choose first available unit other than 0, 5, or 6 ------ + do n=shr_file_maxUnit, shr_file_minUnit, -1 + inquire( n, opened=opened ) + if (n == 5 .or. n == 6 .or. opened) then + cycle + end if + if ( .not. UnitTag(n) ) then + shr_file_getUnit = n + UnitTag(n) = .true. + return + end if + end do + end if + + call shr_sys_abort( subName//': Error: no available units found' ) + + END FUNCTION shr_file_getUnit + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_freeUnit -- Free up a FORTRAN unit number + ! + ! !DESCRIPTION: Free up the given unit number + ! + ! !REVISION HISTORY: + ! 2005-Dec-14 - E. Kluzek - creation + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_freeUnit ( unit) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(in) :: unit ! unit number to be freed + + !EOP + + !----- local ----- + + !----- formats ----- + character(*), parameter :: subName = '(shr_file_freeUnit) ' + character(*), parameter :: F00 = "('(shr_file_freeUnit) ',A,I4,A)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + if (unit < 0 .or. unit > shr_file_maxUnit) then + if (s_loglev > 0) write(s_logunit,F00) 'invalid unit number request:', unit + else if (unit == 0 .or. unit == 5 .or. unit == 6) then + call shr_sys_abort( subName//': Error: units 0, 5, and 6 must not be freed' ) + else if (UnitTag(unit)) then + UnitTag (unit) = .false. + else + if (s_loglev > 0) write(s_logunit,F00) 'unit ', unit, ' was not in use' + end if + + return + + END SUBROUTINE shr_file_freeUnit + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_stdio -- Change working directory, and redirect stdin/stdout + ! + ! !DESCRIPTION: + ! 1) change the cwd (current working directory) and + ! 2) redirect stdin & stdout (units 5 & 6) to named files, + ! where the desired cwd & files are specified by namelist file. + ! + ! Normally this is done to work around limitations in the execution syntax + ! of common MPI implementations. For example, SGI's mpirun syntax is not + ! flexible enough to allow MPMD models to select different execution + ! directories or to redirect stdin & stdout on the command line. + ! Such functionality is highly desireable for CCSM purposes. + ! ie. mpirun can't handle this: + ! unix> cd /usr/tmp/jdoe/csm/case01/atm ; atm < atm.parm > atm.log & + ! unix> cd /usr/tmp/jdoe/csm/case01/cpl ; cpl < cpl.parm > cpl.log & + ! etc. + ! + ! ASSUMPTIONS: + ! o if the cwd, stdin, or stdout are to be changed, there must be a namelist + ! file in the cwd named _stdio.nml where is provided via + ! subroutine dummy argument. + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_stdio(model) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + character(*),intent(in) :: model ! used to construct env varible name + + !EOP + + !--- formats --- + character(*),parameter :: subName = '(shr_file_stdio) ' + character(*),parameter :: F00 = "('(shr_file_stdio) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + call shr_file_chdir (model) ! changes cwd + call shr_file_chStdOut(model) ! open units 5 & 6 to named files + call shr_file_chStdIn (model) ! open units 5 & 6 to named files + + END SUBROUTINE shr_file_stdio + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_chdir -- Change working directory. + ! + ! !DESCRIPTION: + ! change the cwd (current working directory), see shr_file_stdio for notes + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_chdir(model, rcodeOut) + + ! !USES: + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + character(*) ,intent(in) :: model ! used to construct env varible name + integer(SHR_KIND_IN),intent(out),optional :: rcodeOut ! Return error code + + !EOP + + !--- local --- + character(SHR_KIND_CL) :: dir ! directory to cd to + integer (SHR_KIND_IN) :: rcode ! Return error code + character(SHR_KIND_CL) :: filename ! namelist file to read + + !--- formats --- + character(*),parameter :: subName = '(shr_file_chdir) ' + character(*),parameter :: F00 = "('(shr_file_chdir) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + call shr_file_stdioReadNL( model, filename, dirOut=dir, rcodeOut=rcode ) + if (dir /= "nochange") then + call shr_sys_chdir(dir ,rcode) + if (s_loglev > 0) write(s_logunit,F00) "read ",trim(filename),", changed cwd to ",trim(dir) + else + if (s_loglev > 0) write(s_logunit,F00) "read ",trim(filename),", cwd has *not* been changed" + rcode = 1 + endif + if ( present(rcodeOut) ) rcodeOut = rcode + + END SUBROUTINE shr_file_chdir + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_dirio --- Change stdin and stdout. + ! + ! !DESCRIPTION: + ! change the stdin & stdout (units 5 & 6), see shr_file_stdio for notes + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_dirio(model) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + character(*),intent(in) :: model ! used to construct env varible name + + !EOP + + !--- local --- + + !--- formats --- + character(*),parameter :: subName = '(shr_file_dirio) ' + + !------------------------------------------------------------------------------- + ! Notes: + ! + !------------------------------------------------------------------------------- + + call shr_file_chStdIn (model) + call shr_file_chStdOut(model) + + END SUBROUTINE shr_file_dirio + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_chStdIn -- Change stdin + ! + ! !DESCRIPTION: + ! change the stdin (unit 5), see shr_file_stdio for notes + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_chStdIn( model, NLFilename, rcodeOut ) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + character(*) ,intent(in) :: model ! used to construct env var name + character(SHR_KIND_CL),intent(out),optional :: NLFilename ! open unit 5 to this + integer (SHR_KIND_IN),intent(out),optional :: rcodeOut ! return code + + !EOP + + !--- local --- + character(SHR_KIND_CL) :: stdin ! open unit 5 to this file + character(SHR_KIND_CL) :: nlfile ! Namelist filename for model to read from + character(SHR_KIND_CL) :: filename ! namelist file to read + integer (SHR_KIND_IN) :: rcode ! return code + + !--- formats --- + character(*),parameter :: subName = '(shr_file_chStdIn) ' + character(*),parameter :: F00 = "('(shr_file_chStdIn) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + call shr_file_stdioReadNL( model, filename, stdinOut=stdin, & + nlfileOut=nlfile, rcodeOut=rcode ) + if (stdin /= "nochange") then + open(unit=5,file=stdin ,status='UNKNOWN',iostat=rcode) + if ( rcode /= 0 )then + if (s_loglev > 0) & + write(s_logunit,F00) "read ",trim(filename),': error opening file as unit 5:', & + trim(nlfile) + else + if (s_loglev > 0) & + write(s_logunit,F00) "read ",trim(filename),': unit 5 connected to ', & + trim(stdin) + end if + else + if (s_loglev > 0) write(s_logunit,F00) "read ",trim(filename), & + ': unit 5 has *not* been redirected' + endif + if ( len_trim(nlfile) > 0) then + if (s_loglev > 0) write(s_logunit,F00) "read ",trim(filename), & + ': read namelist from file:',trim(nlfile) + if ( .not. present(NLFilename) )then + if (s_loglev > 0) write(s_logunit,F00) "error: namelist filename NOT present" + rcode = 7 + end if + else + if (s_loglev > 0) write(s_logunit,F00) "read ",trim(filename),", " + if ( present(NLFilename) )then + if (s_loglev > 0) write(s_logunit,F00) "error: namelist filename present, but null" + rcode = 8 + end if + endif + if ( present(NLFilename) ) NLFilename = nlfile + if ( present(rcodeOut) ) rcodeOut = rcode + + END SUBROUTINE shr_file_chStdIn + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_stdout -- Change stdout + ! + ! !DESCRIPTION: + ! change the stdout (unit 6), see shr_file_stdio for notes + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_chStdOut(model,rcodeOut) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + !--- arguments --- + character(*) ,intent(in) :: model ! used to construct env varible name + integer(SHR_KIND_IN),intent(out),optional :: rcodeOut ! Return error code + !EOP + + !--- local --- + character(SHR_KIND_CL) :: filename ! namelist file to read + character(SHR_KIND_CL) :: stdout ! open unit 6 to this file + integer (SHR_KIND_IN) :: rcode ! return code + + !--- formats --- + character(*),parameter :: subName = '(shr_file_chStdOut) ' + character(*),parameter :: F00 = "('(shr_file_chStdOut) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + call shr_file_stdioReadNL( model, filename, stdoutOut=stdout, & + rcodeOut=rcode ) + if (stdout /= "nochange") then + close(6) + open(unit=6,file=stdout,position='APPEND') + if (s_loglev > 0) write(s_logunit,F00) "read ",trim(filename), & + ': unit 6 connected to ',trim(stdout) + call shr_sys_flush(s_logunit) + else + if (s_loglev > 0) write(s_logunit,F00) "read ",trim(filename), & + ': unit 6 has *not* been redirected' + rcode = 1 + endif + + if ( present(rcodeOut) ) rcodeOut = rcode + + END SUBROUTINE shr_file_chStdOut + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_stdioReadNL -- read in stdio namelist + ! + ! !DESCRIPTION: + ! Read in the stdio namelist for any given model type. Return any of the + ! needed input namelist variables as optional arguments. Return "nochange" in + ! dir, stdin, or stdout if shouldn't change. + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_stdioReadNL( model, filename, dirOut, stdinOut, stdoutOut, & + NLFileOut, rcodeOut ) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + character(*) ,intent(in) :: model ! used to construct env varible name + character(SHR_KIND_CL),intent(out) :: filename ! nml file to read from unit 5 + character(SHR_KIND_CL),intent(out),optional :: NLFileOut ! open unit 6 to this file + character(SHR_KIND_CL),intent(out),optional :: dirOut ! directory to cd to + character(SHR_KIND_CL),intent(out),optional :: stdinOut ! open unit 5 to this file + character(SHR_KIND_CL),intent(out),optional :: stdoutOut ! open unit 6 to this file + integer (SHR_KIND_IN),intent(out),optional :: rcodeOut ! return code + + !EOP + + !--- local --- + logical :: exists ! true iff file exists + character(SHR_KIND_CL) :: dir ! directory to cd to + character(SHR_KIND_CL) :: stdin ! open unit 5 to this file + character(SHR_KIND_CL) :: stdout ! open unit 6 to this file + character(SHR_KIND_CL) :: NLFile ! namelist file to read seperately + integer (SHR_KIND_IN) :: rcode ! return code + integer (SHR_KIND_IN) :: unit ! Unit to read from + + namelist / stdio / dir,stdin,stdout,NLFile + + !--- formats --- + character(*),parameter :: subName = '(shr_file_stdioReadNL) ' + character(*),parameter :: F00 = "('(shr_file_stdioReadNL) ',4a)" + character(*),parameter :: F01 = "('(shr_file_stdioReadNL) ',3a,i6)" + + !------------------------------------------------------------------------------- + ! Notes: + ! + !------------------------------------------------------------------------------- + + rcode = 0 + dir = "nochange" + stdin = "nochange" + stdout = "nochange" + NLFile = " " + + filename = trim(model)//"_stdio.nml" ! eg. file="cpl_stdio.nml" + inquire(file=filename,exist=exists) + + if (.not. exists) then + if (s_loglev > 0) write(s_logunit,F00) "file ",trim(filename),& + & " doesn't exist, can not read stdio namelist from it" + rcode = 9 + else + unit = shr_file_getUnit() + open (unit,file=filename,action="READ") + read (unit,nml=stdio,iostat=rcode) + close(unit) + call shr_file_freeUnit( unit ) + if (rcode /= 0) then + write(s_logunit,F01) 'ERROR: reading ',trim(filename),': iostat=',rcode + call shr_sys_abort(subName//" ERROR reading "//trim(filename) ) + end if + endif + if ( len_trim(NLFile) > 0 .and. trim(stdin) /= "nochange" )then + write(s_logunit,F00) "Error: input namelist:" + write(s_logunit,nml=stdio) + call shr_sys_abort(subName//" ERROR trying to both redirect AND "// & + "open namelist filename" ) + end if + if ( present(NLFileOut) ) NLFileOut = NLFile + if ( present(dirOut) ) dirOut = dir + if ( present(stdinOut) ) stdinOut = stdin + if ( present(stdoutOut) ) stdoutOut = stdout + if ( present(rcodeOut) ) rcodeOut = rcode + + END SUBROUTINE shr_file_stdioReadNL + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_setIO -- read in stdio namelist + ! + ! !DESCRIPTION: + ! This opens a namelist file specified as an argument and then opens + ! a log file associated with the unit argument. This may be extended + ! in the future. + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_setIO( nmlfile, funit) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + character(len=*) ,intent(in) :: nmlfile ! namelist filename + integer(SHR_KIND_IN),intent(in) :: funit ! unit number for log file + + !EOP + + !--- local --- + logical :: exists ! true if file exists + character(SHR_KIND_CL) :: diri ! directory to cd to + character(SHR_KIND_CL) :: diro ! directory to cd to + character(SHR_KIND_CL) :: logfile ! open unit 6 to this file + integer(SHR_KIND_IN) :: unit ! unit number + integer(SHR_KIND_IN) :: rcode ! error code + + namelist / modelio / diri,diro,logfile + + !--- formats --- + character(*),parameter :: subName = '(shr_file_setIO) ' + character(*),parameter :: F00 = "('(shr_file_setIO) ',4a)" + character(*),parameter :: F01 = "('(shr_file_setIO) ',3a,i6)" + + !------------------------------------------------------------------------------- + ! Notes: + ! + !------------------------------------------------------------------------------- + + diri = "." + diro = "." + logfile = "" + + inquire(file=nmlfile,exist=exists) + + if (.not. exists) then + if (s_loglev > 0) write(s_logunit,F00) "file ",trim(nmlfile)," nonexistent" + return + else + unit = shr_file_getUnit() + open (unit,file=nmlfile,action="READ") + read (unit,nml=modelio,iostat=rcode) + close(unit) + call shr_file_freeUnit( unit ) + if (rcode /= 0) then + write(s_logunit,F01) 'ERROR: reading ',trim(nmlfile),': iostat=',rcode + call shr_sys_abort(subName//" ERROR reading "//trim(nmlfile) ) + end if + endif + + if (len_trim(logfile) > 0) then + open(funit,file=trim(diro)//"/"//trim(logfile)) + else + if (s_loglev > 0) write(s_logunit,F00) "logfile not opened" + endif + + END SUBROUTINE shr_file_setIO + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_setLogUnit -- Set the Log I/O Unit number + ! Depricated - use shr_log_setLogUnit + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_setLogUnit(unit) + use shr_log_mod, only: shr_log_setLogUnit + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(in) :: unit ! new unit number + + !EOP + + !--- formats --- + character(*),parameter :: subName = '(shr_file_setLogUnit) ' + character(*),parameter :: F00 = "('(shr_file_setLogUnit) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: Caller must be sure it's a valid unit number + !------------------------------------------------------------------------------- +#if DEBUG + if (s_loglev > 2 .and. s_logunit-unit /= 0) then + write(s_logunit,*) subName,': reset log unit number from/to ',s_logunit, unit + write( unit,*) subName,': reset log unit number from/to ',s_logunit, unit + endif + if(unit /= 6) print *,__FILE__,__LINE__,'This routine is depricated - use shr_log_setLogUnit instead', unit +#endif + call shr_log_setLogUnit(unit) + + END SUBROUTINE shr_file_setLogUnit + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_setLogLevel -- Set the Log I/O Unit number + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_setLogLevel(newlevel) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(in) :: newlevel ! new log level + + !EOP + + !--- formats --- + character(*),parameter :: subName = '(shr_file_setLogLevel) ' + character(*),parameter :: F00 = "('(shr_file_setLogLevel) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + if (s_loglev+newlevel > 2 .and. s_loglev-newlevel /= 0) & + write(s_logunit,*) subName,': reset log level from/to ',s_loglev, newlevel + + s_loglev = newlevel + + END SUBROUTINE shr_file_setLogLevel + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_getLogUnit -- Set the Log I/O Unit number + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_getLogUnit(unit) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(out) :: unit ! new unit number + + !EOP + + !--- formats --- + character(*),parameter :: subName = '(shr_file_getLogUnit) ' + character(*),parameter :: F00 = "('(shr_file_getLogUnit) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + unit = s_logunit + + END SUBROUTINE shr_file_getLogUnit + + !=============================================================================== + !BOP =========================================================================== + ! + ! !IROUTINE: shr_file_getLogLevel -- Set the Log I/O Unit number + ! + ! !INTERFACE: ------------------------------------------------------------------ + + SUBROUTINE shr_file_getLogLevel(curlevel) + + implicit none + + ! !INPUT/OUTPUT PARAMETERS: + + integer(SHR_KIND_IN),intent(out) :: curlevel ! new log level + + !EOP + + !--- formats --- + character(*),parameter :: subName = '(shr_file_getLogLevel) ' + character(*),parameter :: F00 = "('(shr_file_getLogLevel) ',4a)" + + !------------------------------------------------------------------------------- + ! Notes: + !------------------------------------------------------------------------------- + + curlevel = s_loglev + + END SUBROUTINE shr_file_getLogLevel + + !=============================================================================== + subroutine shr_file_get_real_path(path, resolved_path) + use, intrinsic :: iso_c_binding + character(len=*), intent(in) :: path + character(len=*), intent(out) :: resolved_path + + ! Define + integer :: n + character(len=1) :: a(SHR_KIND_CL) + type(c_ptr) :: ptr + + ! Fortran interface to C function, realpath() + interface + function realpath(path,resolved_path) bind(c,name="realpath") + use, intrinsic :: iso_c_binding + type(c_ptr) :: realpath + character(len=1,kind=c_char), intent(in) :: path(*) + character(len=1,kind=c_char), intent(out) :: resolved_path(*) + end function realpath + end interface + + ! Initialize + a="" + + ptr=realpath(trim(path)//C_NULL_CHAR,a) + + ! Transfer character array to character string + resolved_path = transfer(a,resolved_path) + + ! Determine the first null char + do n=1,SHR_KIND_CL + if(iachar(resolved_path(n:n)).eq.0) exit + end do + resolved_path=resolved_path(:n-1) + end subroutine shr_file_get_real_path + + + !=============================================================================== + +END MODULE shr_file_mod diff --git a/share/shr_nl_mod.F90 b/share/shr_nl_mod.F90 new file mode 100644 index 000000000..f06f2185c --- /dev/null +++ b/share/shr_nl_mod.F90 @@ -0,0 +1,88 @@ +module shr_nl_mod + +! Utilities for namelist reading +! Adapted Fall 2012 from CAM's namelist_utils. + +implicit none +private + +save + +public :: & + shr_nl_find_group_name ! seek through a file to find a specified namelist + +contains + +! This routine probably discards more error code information than it needs to. + +subroutine shr_nl_find_group_name(unit, group, status) + + use shr_string_mod, only: shr_string_toLower + +!--------------------------------------------------------------------------------------- +! Purpose: +! Search a file that contains namelist input for the specified namelist group name. +! Leave the file positioned so that the current record is the first record of the +! input for the specified group. +! +! Method: +! Read the file line by line. Each line is searched for an '&' which may only +! be preceded by blanks, immediately followed by the group name which is case +! insensitive. If found then backspace the file so the current record is the +! one containing the group name and return success. Otherwise return -1. +! +! Author: B. Eaton, August 2007 +!--------------------------------------------------------------------------------------- + + integer, intent(in) :: unit ! fortran unit attached to file + character(len=*), intent(in) :: group ! namelist group name + integer, intent(out) :: status ! 0 for success, -1 if group name not found + + ! Local variables + + integer :: len_grp + integer :: ios ! io status + character(len=80) :: inrec ! first 80 characters of input record + character(len=80) :: inrec2 ! left adjusted input record + character(len=len(group)) :: lc_group + + !--------------------------------------------------------------------------- + + len_grp = len_trim(group) + lc_group = shr_string_toLower(group) + + ios = 0 + do while (ios <= 0) + + read(unit, '(a)', iostat=ios, end=100) inrec + + if (ios <= 0) then ! ios < 0 indicates an end of record condition + + ! look for group name in this record + + ! remove leading blanks + inrec2 = adjustl(inrec) + + ! check for leading '&' + if (inrec2(1:1) == '&') then + + ! check for case insensitive group name + if (trim(lc_group) == shr_string_toLower(inrec2(2:len_grp+1))) then + + ! found group name. backspace to leave file position at this record + backspace(unit) + status = 0 + return + + end if + end if + end if + + end do + + 100 continue ! end of file processing + status = -1 + +end subroutine shr_nl_find_group_name + +end module shr_nl_mod diff --git a/streams/CMakeLists.txt b/streams/CMakeLists.txt index 99066e802..ab4b534ba 100644 --- a/streams/CMakeLists.txt +++ b/streams/CMakeLists.txt @@ -18,14 +18,16 @@ message("Stream srcfiles are ${SRCFILES}") add_library(streams ${SRCFILES}) -add_dependencies(streams FoX_dom) +if(NOT DISABLE_FoX) + add_dependencies(streams FoX_dom) + target_include_directories (streams PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) +endif() + if(BLD_STANDALONE) add_dependencies(streams cdeps_share) target_include_directories (streams PRIVATE ${CMAKE_BINARY_DIR}/share) endif() - -target_include_directories (streams PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/../fox/include) target_include_directories (streams PRIVATE ${ESMF_F90COMPILEPATHS}) target_include_directories (streams PRIVATE ${PIO_Fortran_INCLUDE_DIR}) diff --git a/streams/dshr_stream_mod.F90 b/streams/dshr_stream_mod.F90 index da206732a..298caaded 100644 --- a/streams/dshr_stream_mod.F90 +++ b/streams/dshr_stream_mod.F90 @@ -670,8 +670,6 @@ subroutine shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, if( ESMF_ConfigGetLen(config=CF, label="stream_vectors"//mystrm//':', rc=rc) > 0 ) then call ESMF_ConfigGetAttribute(CF,value=streamdat(i)%stream_vectors,label="stream_vectors"//mystrm//':', rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - else - call shr_sys_abort("stream_vectors must be provided") endif if( ESMF_ConfigGetLen(config=CF, label="stream_lev_dimname"//mystrm//':', rc=rc) > 0 ) then @@ -1711,7 +1709,7 @@ end subroutine shr_stream_getNFiles !=============================================================================== subroutine shr_stream_restIO(pioid, streams, mode) - + use shr_file_mod, only : shr_file_get_real_path use pio, only : pio_def_dim, pio_def_var, pio_put_var, pio_get_var, file_desc_t, var_desc_t use pio, only : pio_int, pio_char @@ -1727,7 +1725,9 @@ subroutine shr_stream_restIO(pioid, streams, mode) integer :: n, k, maxnfiles=0 integer :: maxnt = 0 integer, allocatable :: tmp(:) - character(len=CL) :: fname + integer :: logunit + character(len=CL) :: fname, rfname, rsfname + !------------------------------------------------------------------------------- if (mode .eq. 'define') then @@ -1735,6 +1735,7 @@ subroutine shr_stream_restIO(pioid, streams, mode) rcode = pio_def_dim(pioid, 'strlen', CL, dimid_str) do k=1,size(streams) ! maxnfiles is the maximum number of files across all streams + logunit = streams(k)%logunit if (streams(k)%nfiles > maxnfiles) then maxnfiles = streams(k)%nfiles endif @@ -1923,16 +1924,28 @@ subroutine shr_stream_restIO(pioid, streams, mode) rcode = pio_inq_varid(pioid, 'timeofday', tvarid) rcode = pio_inq_varid(pioid, 'haveData' , hdvarid) do k=1,size(streams) + logunit = streams(k)%logunit do n=1,streams(k)%nfiles ! read in filename rcode = pio_get_var(pioid, varid, (/1,n,k/), fname) - if (trim(fname) /= trim(streams(k)%file(n)%name)) then - write(6,'(a)')' fname = '//trim(fname) - write(6,'(a,i8,2x,i8,2x,a)')' k,n,streams(k)%file(n)%name = ',k,n,trim(streams(k)%file(n)%name) - call shr_sys_abort('ERROR reading in filename') + + if(trim(fname) /= trim(streams(k)%file(n)%name)) then + write(logunit,*) 'Filename does not match restart record, checking realpath' + call shr_file_get_real_path(fname, rfname) + call shr_file_get_real_path(trim(streams(k)%file(n)%name), rsfname) + if (trim(rfname) /= trim(rsfname)) then + write(logunit,*) 'Filename path does not match restartfile, checking filename' + rfname = fname(index(fname,'/',.true.):) + rsfname = streams(k)%file(n)%name(index(streams(k)%file(n)%name, '/',.true.):) + if (trim(rfname) /= trim(rsfname)) then + write(logunit,*) trim(rfname), '<>', trim(rsfname) + write(logunit,'(a)')' fname = '//trim(fname) + write(logunit,'(a,i8,2x,i8,2x,a)')' k,n,streams(k)%file(n)%name = ',k,n,trim(streams(k)%file(n)%name) + call shr_sys_abort('ERROR reading in filename') + endif + endif endif - ! read in nt allocate(tmp(1)) rcode = pio_get_var(pioid, ntvarid, (/n,k/), tmp(1)) From 3d7067a523b8557058755289e4275f5f5c985daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ufuk=20Turun=C3=A7o=C4=9Flu?= Date: Mon, 5 Feb 2024 07:01:41 -0700 Subject: [PATCH 11/28] sync CDEPS with ESCOMP (#60) --- datm/atm_comp_nuopc.F90 | 9 ++++- docn/cime_config/config_component.xml | 2 +- streams/dshr_strdata_mod.F90 | 56 +++++++++++++++++---------- streams/dshr_stream_mod.F90 | 21 +++++++++- 4 files changed, 62 insertions(+), 26 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index a00610eb9..7262e0fc0 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -93,6 +93,12 @@ module cdeps_datm_comp use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_advance use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_write use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_read + + use datm_datamode_simple_mod , only : datm_datamode_simple_advertise + use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers + use datm_datamode_simple_mod , only : datm_datamode_simple_advance + use datm_datamode_simple_mod , only : datm_datamode_simple_restart_write + use datm_datamode_simple_mod , only : datm_datamode_simple_restart_read use datm_datamode_simple_mod , only : datm_datamode_simple_advertise use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers @@ -744,6 +750,7 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('GEFS') call datm_datamode_gefs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & target_tod, sdat%model_calendar, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return case('CFSR') call datm_datamode_cfsr_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & target_tod, sdat%model_calendar, rc) @@ -786,11 +793,9 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('CFSR') call datm_datamode_cfsr_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) - if (ChkErr(rc,__LINE__,u_FILE_u)) return case('GFS') call datm_datamode_gfs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) - if (ChkErr(rc,__LINE__,u_FILE_u)) return case('GFS_HAFS') call datm_datamode_gfs_hafs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) diff --git a/docn/cime_config/config_component.xml b/docn/cime_config/config_component.xml index 0e03abf26..3a98b7878 100644 --- a/docn/cime_config/config_component.xml +++ b/docn/cime_config/config_component.xml @@ -148,7 +148,7 @@ char - $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1x1_clim_c101029.nc + $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1x1_2000climo_c180511.nc $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_48x96_clim_c050526.nc $DIN_LOC_ROOT/atm/cam/sst/sst_HadOIBl_bc_1.9x2.5_clim_c061031.nc diff --git a/streams/dshr_strdata_mod.F90 b/streams/dshr_strdata_mod.F90 index ce39cc7c4..c056639d3 100644 --- a/streams/dshr_strdata_mod.F90 +++ b/streams/dshr_strdata_mod.F90 @@ -240,7 +240,8 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & stream_meshfile, stream_lev_dimname, stream_mapalgo, & stream_filenames, stream_fldlistFile, stream_fldListModel, & stream_yearFirst, stream_yearLast, stream_yearAlign, & - stream_offset, stream_taxmode, stream_dtlimit, stream_tintalgo, stream_name, rc) + stream_offset, stream_taxmode, stream_dtlimit, stream_tintalgo, & + stream_src_mask, stream_dst_mask, stream_name, rc) ! input/output variables type(shr_strdata_type) , intent(inout) :: sdat ! stream data type @@ -262,8 +263,14 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & character(*) , intent(in) :: stream_taxMode ! time axis mode real(r8) , intent(in) :: stream_dtlimit ! ratio of max/min stream delta times character(*) , intent(in) :: stream_tintalgo ! time interpolation algorithm + integer, optional , intent(in) :: stream_src_mask ! source mask value + integer, optional , intent(in) :: stream_dst_mask ! destination mask value character(*), optional , intent(in) :: stream_name ! name of stream - integer , intent(out) :: rc ! error code + integer, optional , intent(out) :: rc ! error code + + ! local variables + integer :: src_mask = 0 + integer :: dst_mask = 0 ! ---------------------------------------------- rc = ESMF_SUCCESS @@ -277,6 +284,10 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & sdat%io_format = shr_pio_getioformat(trim(compname)) #endif + ! Check source and destination mask, defaults are 0 + if (present(stream_src_mask)) src_mask = stream_src_mask + if (present(stream_dst_mask)) dst_mask = stream_dst_mask + ! Initialize sdat%pstrm - ASSUME only 1 stream allocate(sdat%pstrm(1)) @@ -292,7 +303,7 @@ subroutine shr_strdata_init_from_inline(sdat, my_task, logunit, compname, & stream_yearFirst, stream_yearLast, stream_yearAlign, & stream_offset, stream_taxmode, stream_tintalgo, stream_dtlimit, & stream_fldlistFile, stream_fldListModel, stream_fileNames, & - logunit, trim(compname)) + logunit, trim(compname), src_mask, dst_mask) ! Now finish initializing sdat call shr_strdata_init(sdat, model_clock, stream_name, rc) @@ -549,8 +560,8 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) regridmethod=ESMF_REGRIDMETHOD_BILINEAR, & polemethod=ESMF_POLEMETHOD_ALLAVG, & extrapMethod=ESMF_EXTRAPMETHOD_NEAREST_STOD, & - dstMaskValues = (/0/), & ! ignore destination points where the mask is 0 - srcMaskValues = (/0/), & ! ignore source points where the mask is 0 + dstMaskValues=(/sdat%stream(ns)%dst_mask_val/), & + srcMaskValues=(/sdat%stream(ns)%src_mask_val/), & srcTermProcessing=srcTermProcessing_Value, ignoreDegenerate=.true., rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return else if (trim(sdat%stream(ns)%mapalgo) == 'redist') then @@ -562,8 +573,8 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) call ESMF_FieldReGridStore(sdat%pstrm(ns)%field_stream, lfield_dst, & routehandle=sdat%pstrm(ns)%routehandle, & regridmethod=ESMF_REGRIDMETHOD_NEAREST_STOD, & - dstMaskValues = (/0/), & ! ignore destination points where the mask is 0 - srcMaskValues = (/0/), & ! ignore source points where the mask is 0 + dstMaskValues=(/sdat%stream(ns)%dst_mask_val/), & + srcMaskValues=(/sdat%stream(ns)%src_mask_val/), & srcTermProcessing=srcTermProcessing_Value, ignoreDegenerate=.true., & unmappedaction=ESMF_UNMAPPEDACTION_IGNORE, rc=rc) else if (trim(sdat%stream(ns)%mapalgo) == 'consf') then @@ -571,8 +582,8 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) routehandle=sdat%pstrm(ns)%routehandle, & regridmethod=ESMF_REGRIDMETHOD_CONSERVE, & normType=ESMF_NORMTYPE_FRACAREA, & - dstMaskValues = (/0/), & ! ignore destination points where the mask is 0 - srcMaskValues = (/0/), & ! ignore source points where the mask is 0 + dstMaskValues=(/sdat%stream(ns)%dst_mask_val/), & + srcMaskValues=(/sdat%stream(ns)%src_mask_val/), & srcTermProcessing=srcTermProcessing_Value, ignoreDegenerate=.true., & unmappedaction=ESMF_UNMAPPEDACTION_IGNORE, rc=rc) else if (trim(sdat%stream(ns)%mapalgo) == 'consd') then @@ -580,8 +591,8 @@ subroutine shr_strdata_init(sdat, model_clock, stream_name, rc) routehandle=sdat%pstrm(ns)%routehandle, & regridmethod=ESMF_REGRIDMETHOD_CONSERVE, & normType=ESMF_NORMTYPE_DSTAREA, & - dstMaskValues = (/0/), & ! ignore destination points where the mask is 0 - srcMaskValues = (/0/), & ! ignore source points where the mask is 0 + dstMaskValues=(/sdat%stream(ns)%dst_mask_val/), & + srcMaskValues=(/sdat%stream(ns)%src_mask_val/), & srcTermProcessing=srcTermProcessing_Value, ignoreDegenerate=.true., & unmappedaction=ESMF_UNMAPPEDACTION_IGNORE, rc=rc) else if (trim(sdat%stream(ns)%mapalgo) == 'none') then @@ -1235,9 +1246,10 @@ subroutine shr_strdata_print(sdat, name) character(*),parameter :: F00 = "('(shr_strdata_print) ',8a)" character(*),parameter :: F01 = "('(shr_strdata_print) ',a,i6,a)" character(*),parameter :: F02 = "('(shr_strdata_print) ',a,es13.6)" - character(*),parameter :: F04 = "('(shr_strdata_print) ',a,i2,a,a)" - character(*),parameter :: F05 = "('(shr_strdata_print) ',a)" - character(*),parameter :: F07 = "('(shr_strdata_print) ',a,i2,a,es13.6)" + character(*),parameter :: F03 = "('(shr_strdata_print) ',a,i2,a,a)" + character(*),parameter :: F04 = "('(shr_strdata_print) ',a)" + character(*),parameter :: F05 = "('(shr_strdata_print) ',a,i2,a,es13.6)" + character(*),parameter :: F06 = "('(shr_strdata_print) ',a,i2,a,i1)" character(*),parameter :: F90 = "('(shr_strdata_print) ',58('-'))" !------------------------------------------------------------------------------- @@ -1251,14 +1263,16 @@ subroutine shr_strdata_print(sdat, name) write(sdat%stream(1)%logunit,F02) "obliqr = ",sdat%obliqr write(sdat%stream(1)%logunit,F01) "pio_iotype = ",sdat%io_type write(sdat%stream(1)%logunit,F01) "nstreams = ",shr_strdata_get_stream_count(sdat) - write(sdat%stream(1)%logunit,F05) "Per stream information " + write(sdat%stream(1)%logunit,F04) "Per stream information " do ns = 1, shr_strdata_get_stream_count(sdat) - write(sdat%stream(1)%logunit,F04) " taxMode (",ns,") = ",trim(sdat%stream(ns)%taxmode) - write(sdat%stream(1)%logunit,F07) " dtlimit (",ns,") = ",sdat%stream(ns)%dtlimit - write(sdat%stream(1)%logunit,F04) " mapalgo (",ns,") = ",trim(sdat%stream(ns)%mapalgo) - write(sdat%stream(1)%logunit,F04) " tintalgo(",ns,") = ",trim(sdat%stream(ns)%tinterpalgo) - write(sdat%stream(1)%logunit,F04) " readmode(",ns,") = ",trim(sdat%stream(ns)%readmode) - write(sdat%stream(1)%logunit,F04) " vectors (",ns,") = ",trim(sdat%stream(ns)%stream_vectors) + write(sdat%stream(1)%logunit,F03) " taxMode (",ns,") = ",trim(sdat%stream(ns)%taxmode) + write(sdat%stream(1)%logunit,F05) " dtlimit (",ns,") = ",sdat%stream(ns)%dtlimit + write(sdat%stream(1)%logunit,F03) " mapalgo (",ns,") = ",trim(sdat%stream(ns)%mapalgo) + write(sdat%stream(1)%logunit,F03) " tintalgo(",ns,") = ",trim(sdat%stream(ns)%tinterpalgo) + write(sdat%stream(1)%logunit,F03) " readmode(",ns,") = ",trim(sdat%stream(ns)%readmode) + write(sdat%stream(1)%logunit,F03) " vectors (",ns,") = ",trim(sdat%stream(ns)%stream_vectors) + write(sdat%stream(1)%logunit,F06) " src_mask(",ns,") = ",sdat%stream(ns)%src_mask_val + write(sdat%stream(1)%logunit,F06) " dst_mask(",ns,") = ",sdat%stream(ns)%dst_mask_val write(sdat%stream(1)%logunit,F01) " " end do write(sdat%stream(1)%logunit,F90) diff --git a/streams/dshr_stream_mod.F90 b/streams/dshr_stream_mod.F90 index 298caaded..352bf6650 100644 --- a/streams/dshr_stream_mod.F90 +++ b/streams/dshr_stream_mod.F90 @@ -131,6 +131,8 @@ module dshr_stream_mod type(file_desc_t) :: currpioid ! current pio file desc type(shr_stream_file_type) , allocatable :: file(:) ! filenames of stream data files (full pathname) type(shr_stream_data_variable), allocatable :: varlist(:) ! stream variable names (on file and in model) + integer :: src_mask_val = 0 ! mask value for src mesh + integer :: dst_mask_val = 0 ! mask value for dst mesh end type shr_stream_streamType !----- parameters ----- @@ -445,7 +447,7 @@ subroutine shr_stream_init_from_inline(streamdat, & stream_yearFirst, stream_yearLast, stream_yearAlign, & stream_offset, stream_taxmode, stream_tintalgo, stream_dtlimit, & stream_fldlistFile, stream_fldListModel, stream_fileNames, & - logunit, compname) + logunit, compname, stream_src_mask_val, stream_dst_mask_val) ! -------------------------------------------------------- ! set values of stream datatype independent of a reading in a stream text file @@ -472,6 +474,8 @@ subroutine shr_stream_init_from_inline(streamdat, & character(*) ,intent(in) :: stream_filenames(:) ! stream data filenames (full pathnamesa) integer ,intent(in) :: logunit ! stdout unit character(len=*) ,intent(in) :: compname ! component name (e.g. ATM, OCN...) + integer ,optional, intent(in) :: stream_src_mask_val ! source mask value + integer ,optional, intent(in) :: stream_dst_mask_val ! destination mask value ! local variables integer :: n @@ -534,10 +538,15 @@ subroutine shr_stream_init_from_inline(streamdat, & ! Initialize logunit streamdat(:)%logunit = logunit + ! Get stream calendar call shr_stream_getCalendar(streamdat(1), 1, calendar) streamdat(1)%calendar = trim(calendar) + ! Set source and destination mask + if (present(stream_src_mask_val)) streamdat(1)%src_mask_val = stream_src_mask_val + if (present(stream_dst_mask_val)) streamdat(1)%dst_mask_val = stream_dst_mask_val + ! Initialize flag that stream has been set streamdat(1)%init = .true. @@ -571,6 +580,8 @@ subroutine shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, !! stream_data_files: !! stream_data_variables: !! stream_offset: + !! stream_src_mask: + !! stream_dst_mask: !!--------------------------------------------------------------------- ! input/output variables @@ -606,7 +617,6 @@ subroutine shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, call ESMF_ConfigLoadFile(config=CF ,filename=trim(streamfilename), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - ! get number of streams nstrms = ESMF_ConfigGetLen(config=CF, label='stream_info:', rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -718,6 +728,13 @@ subroutine shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, call shr_stream_getCalendar(streamdat(i), 1, streamdat(i)%calendar) + ! Get source and destination mask, 0 by default + call ESMF_ConfigGetAttribute(CF,value=streamdat(i)%src_mask_val,label="stream_src_mask"//mystrm//':', default=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ConfigGetAttribute(CF,value=streamdat(i)%dst_mask_val,label="stream_dst_mask"//mystrm//':', default=0, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! Error check if (trim(streamdat(i)%taxmode) == shr_stream_taxis_extend .and. streamdat(i)%dtlimit < 1.e10) then call shr_sys_abort(trim(subName)//" ERROR: if taxmode value is extend set dtlimit to 1.e30") From fbdf6843d6bde852d97f1547591d90136103f669 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Tue, 11 Jun 2024 12:01:37 -0400 Subject: [PATCH 12/28] Create cplhist mode for dice (#62) * Adapt docn_datamode_cplhist for dice_datamode_cplhist * Fix .or. and local variables have different names in docn and dice * Add Si_imask. Decide whether to have flds_i2o_per_cat for cplhist method. * Copy sea ice stream fields to export state fields via dshr_dfield_add * Switches So_t from C to K. Decide on which/add switch * Overwrite missing value of 0 K in Si_t * Handle So_t in C and K in docn_datamode_cplhist_mod.F90 Need model SST to be in K if (minval(So_t) .LT. 100.0_r8), convert C-->K * Only fill docn_datamode_cplhist export variables if associated. Handle units of So_t based on namelist input * Default convert SST C to K (as currently). Then switch based on optional sst_constant_value * Allow null return for taux too in dice/dice_datamode_cplhist_mod.F90 * Add doc for dice cplhist mode to dice.rst --- dice/CMakeLists.txt | 1 + dice/dice_datamode_cplhist_mod.F90 | 195 +++++++++++++++++++++++++++++ dice/ice_comp_nuopc.F90 | 89 +++++++++++-- doc/source/dice.rst | 3 + docn/docn_datamode_cplhist_mod.F90 | 27 +++- docn/ocn_comp_nuopc.F90 | 2 +- 6 files changed, 301 insertions(+), 16 deletions(-) create mode 100644 dice/dice_datamode_cplhist_mod.F90 diff --git a/dice/CMakeLists.txt b/dice/CMakeLists.txt index acfc26d47..aabb44312 100644 --- a/dice/CMakeLists.txt +++ b/dice/CMakeLists.txt @@ -1,6 +1,7 @@ project(dice Fortran) set(SRCFILES ice_comp_nuopc.F90 dice_datamode_ssmi_mod.F90 + dice_datamode_cplhist_mod.F90 dice_flux_atmice_mod.F90) foreach(FILE ${SRCFILES}) diff --git a/dice/dice_datamode_cplhist_mod.F90 b/dice/dice_datamode_cplhist_mod.F90 new file mode 100644 index 000000000..1d1eb28a0 --- /dev/null +++ b/dice/dice_datamode_cplhist_mod.F90 @@ -0,0 +1,195 @@ +module dice_datamode_cplhist_mod + + use ESMF , only : ESMF_State, ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_SUCCESS + use NUOPC , only : NUOPC_Advertise + use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs + use shr_const_mod , only : shr_const_TkFrzsw + use shr_sys_mod , only : shr_sys_abort + use dshr_methods_mod , only : dshr_state_getfldptr, dshr_fldbun_getfldptr, chkerr + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + use dshr_mod , only : dshr_restart_read, dshr_restart_write + use dshr_strdata_mod , only : shr_strdata_type + + implicit none + private ! except + + public :: dice_datamode_cplhist_advertise + public :: dice_datamode_cplhist_init_pointers + public :: dice_datamode_cplhist_advance + public :: dice_datamode_cplhist_restart_read + public :: dice_datamode_cplhist_restart_write + + ! export fields + ! ice to atm in CMEPS/mediator/esmFldsExchange_ufs_mod.F90 + real(r8), pointer :: Si_ifrac(:) => null() + real(r8), pointer :: Si_imask(:) => null() + real(r8), pointer :: Faii_taux(:) => null() + real(r8), pointer :: Faii_tauy(:) => null() + real(r8), pointer :: Faii_lat(:) => null() + real(r8), pointer :: Faii_sen(:) => null() + real(r8), pointer :: Faii_lwup(:) => null() + real(r8), pointer :: Faii_evap(:) => null() + real(r8), pointer :: Si_vice(:) => null() + real(r8), pointer :: Si_vsno(:) => null() + real(r8), pointer :: Si_t(:) => null() + real(r8), pointer :: Si_avsdr(:) => null() + real(r8), pointer :: Si_avsdf(:) => null() + real(r8), pointer :: Si_anidr(:) => null() + real(r8), pointer :: Si_anidf(:) => null() + + character(*) , parameter :: nullstr = 'null' + character(*) , parameter :: rpfile = 'rpointer.ice' + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine dice_datamode_cplhist_advertise(exportState, fldsexport, flds_scalar_name, rc) + + ! input/output variables + type(esmf_State) , intent(inout) :: exportState + type(fldlist_type) , pointer :: fldsexport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Advertise export fields + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldList_add(fldsExport, 'Si_ifrac' ) + call dshr_fldList_add(fldsExport, 'Si_imask' ) + call dshr_fldList_add(fldsExport, 'Faii_taux' ) + call dshr_fldList_add(fldsExport, 'Faii_tauy' ) + call dshr_fldList_add(fldsExport, 'Faii_lat' ) + call dshr_fldList_add(fldsExport, 'Faii_sen' ) + call dshr_fldList_add(fldsExport, 'Faii_lwup' ) + call dshr_fldList_add(fldsExport, 'Faii_evap' ) + call dshr_fldList_add(fldsExport, 'Si_vice' ) + call dshr_fldList_add(fldsExport, 'Si_vsno' ) + call dshr_fldList_add(fldsExport, 'Si_t' ) + call dshr_fldList_add(fldsExport, 'Si_avsdr' ) + call dshr_fldList_add(fldsExport, 'Si_avsdf' ) + call dshr_fldList_add(fldsExport, 'Si_anidr' ) + call dshr_fldList_add(fldsExport, 'Si_anidf' ) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(dice_comp_advertise): Fr_ice'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine dice_datamode_cplhist_advertise + + !=============================================================================== + subroutine dice_datamode_cplhist_init_pointers(importState, exportState,sdat,rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + integer , intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(dice_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! initialize pointers to export fields + call dshr_state_getfldptr(exportState, 'Si_ifrac' , fldptr1=Si_ifrac , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_imask' , fldptr1=Si_imask , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_taux' , fldptr1=Faii_taux , allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_tauy' , fldptr1=Faii_tauy , allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_lat' , fldptr1=Faii_lat , allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_sen', fldptr1=Faii_sen, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_lwup', fldptr1=Faii_lwup, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faii_evap', fldptr1=Faii_evap, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_vice', fldptr1=Si_vice, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_vsno', fldptr1=Si_vsno, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_t', fldptr1=Si_t, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_avsdr', fldptr1=Si_avsdr, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_avsdf', fldptr1=Si_avsdf, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_anidr', fldptr1=Si_anidr, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Si_anidf', fldptr1=Si_anidf, allowNullReturn=.true., rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + !Initialize (e.g., =0)? + + end subroutine dice_datamode_cplhist_init_pointers + + !=============================================================================== + subroutine dice_datamode_cplhist_advance(rc) + + ! input/output variables + integer, intent(out) :: rc + + ! local variables + character(len=*), parameter :: subname='(dice_datamode_cplhist_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + !Unit conversions, calculations,.... + !Where aice=0, Si_t=0K (as missing value). Interpolation in time between ice that comes or goes then has issues + where(Si_t .LT. 10) Si_t = shr_const_TkFrzsw + + end subroutine dice_datamode_cplhist_advance + + !=============================================================================== + subroutine dice_datamode_cplhist_restart_write(case_name, inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + ! input/output variables + character(len=*) , intent(in) :: case_name + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: ymd ! model date + integer , intent(in) :: tod ! model sec into model date + integer , intent(in) :: logunit + integer , intent(in) :: my_task + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_write(rpfile, case_name, 'dice', inst_suffix, ymd, tod, & + logunit, my_task, sdat) + + end subroutine dice_datamode_cplhist_restart_write + + !=============================================================================== + subroutine dice_datamode_cplhist_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) + + ! input/output arguments + character(len=*) , intent(inout) :: rest_filem + character(len=*) , intent(in) :: inst_suffix + integer , intent(in) :: logunit + integer , intent(in) :: my_task + integer , intent(in) :: mpicom + type(shr_strdata_type) , intent(inout) :: sdat + !------------------------------------------------------------------------------- + + call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) + + end subroutine dice_datamode_cplhist_restart_read + +end module dice_datamode_cplhist_mod diff --git a/dice/ice_comp_nuopc.F90 b/dice/ice_comp_nuopc.F90 index 51ec80361..567a1943c 100644 --- a/dice/ice_comp_nuopc.F90 +++ b/dice/ice_comp_nuopc.F90 @@ -16,7 +16,7 @@ module cdeps_dice_comp use ESMF , only : ESMF_AlarmIsRinging, ESMF_METHOD_INITIALIZE use ESMF , only : ESMF_ClockGet, ESMF_TimeGet, ESMF_MethodRemove, ESMF_MethodAdd use ESMF , only : ESMF_GridCompSetEntryPoint, operator(+), ESMF_AlarmRingerOff - use ESMF , only : ESMF_ClockGetAlarm, ESMF_StateGet, ESMF_Field, ESMF_FieldGet + use ESMF , only : ESMF_ClockGetAlarm, ESMF_StateGet, ESMF_Field, ESMF_FieldGet, ESMF_MAXSTR use NUOPC , only : NUOPC_CompDerive, NUOPC_CompSetEntryPoint, NUOPC_CompSpecialize use NUOPC , only : NUOPC_CompAttributeGet, NUOPC_Advertise use NUOPC_Model , only : model_routine_SS => SetServices @@ -41,6 +41,12 @@ module cdeps_dice_comp use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_advance use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_restart_read use dice_datamode_ssmi_mod , only : dice_datamode_ssmi_restart_write + ! + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_advertise + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_init_pointers + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_advance + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_restart_read + use dice_datamode_cplhist_mod , only : dice_datamode_cplhist_restart_write implicit none private ! except @@ -176,6 +182,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) integer :: bcasttmp(4) real(r8) :: rbcasttmp(3) type(ESMF_VM) :: vm + logical :: isPresent, isSet character(len=*),parameter :: subname=trim(modName)//':(InitializeAdvertise) ' character(*) ,parameter :: F00 = "('(" // trim(modName) // ") ',8a)" character(*) ,parameter :: F01 = "('(" // trim(modName) // ") ',a,2x,i8)" @@ -266,22 +273,28 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) flux_Qacc0 = rbcasttmp(3) ! Validate datamode - if ( trim(datamode) == 'ssmi' .or. trim(datamode) == 'ssmi_iaf') then + if ( trim(datamode) == 'ssmi' .or. trim(datamode) == 'ssmi_iaf' .or. trim(datamode) == 'cplhist') then if (my_task == main_task) write(logunit,*) ' dice datamode = ',trim(datamode) else call shr_sys_abort(' ERROR illegal dice datamode = '//trim(datamode)) endif ! Advertise import and export fields - call NUOPC_CompAttributeGet(gcomp, name='flds_i2o_per_cat', value=cvalue, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) flds_i2o_per_cat ! module variable + if ( trim(datamode) == 'ssmi' .or. trim(datamode) == 'ssmi_iaf') then + call NUOPC_CompAttributeGet(gcomp, name='flds_i2o_per_cat', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) read(cvalue,*) flds_i2o_per_cat ! module variable + endif + !datamode already validated select case (trim(datamode)) - case('ssmi', 'ssmi_iaf') + case('ssmi','ssmi_iaf') call dice_datamode_ssmi_advertise(importState, exportState, fldsimport, fldsexport, & flds_scalar_name, flds_i2o_per_cat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('cplhist') + call dice_datamode_cplhist_advertise(exportState, fldsexport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end subroutine InitializeAdvertise @@ -489,16 +502,25 @@ subroutine dice_comp_run(importstate, exportstate, target_ymd, target_tod, cosar if (first_time) then - ! Initialize dfields with export state data that has corresponding stream field - call dshr_dfield_add(dfields, sdat, state_fld='Si_ifrac', strm_fld='Si_ifrac', & + ! Initialize dfields with export state data that has corresponding stream fieldi + select case (trim(datamode)) + case('ssmi','ssmi_iaf') + call dshr_dfield_add(dfields, sdat, state_fld='Si_ifrac', strm_fld='Si_ifrac', & state=exportState, logunit=logunit, mainproc=mainproc, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return + if (chkerr(rc,__LINE__,u_FILE_u)) return + case('cplhist') + call dice_init_dfields(importState, exportState, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end select ! Initialize datamode module ponters select case (trim(datamode)) case('ssmi', 'ssmi_iaf') call dice_datamode_ssmi_init_pointers(importState, exportState, sdat, flds_i2o_per_cat, rc) if (chkerr(rc,__LINE__,u_FILE_u)) return + case('cplhist') + call dice_datamode_cplhist_init_pointers(importState,exportState,sdat,rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return end select ! read restart if needed @@ -506,6 +528,8 @@ subroutine dice_comp_run(importstate, exportstate, target_ymd, target_tod, cosar select case (trim(datamode)) case('ssmi', 'ssmi_iaf') call dice_datamode_ssmi_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) + case('cplhist') + call dice_datamode_cplhist_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) end select end if @@ -546,15 +570,22 @@ subroutine dice_comp_run(importstate, exportstate, target_ymd, target_tod, cosar call dice_datamode_ssmi_advance(exportState, importState, cosarg, flds_i2o_per_cat, & flux_swpf, flux_Qmin, flux_Qacc, flux_Qacc0, dt, logunit, restart_read, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('cplhist') + call dice_datamode_cplhist_advance(rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Write restarts if needed + ! TODO - no rc returned if (restart_write) then select case (trim(datamode)) case('ssmi', 'ssmi_iaf') call dice_datamode_ssmi_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('cplhist') + call dice_datamode_cplhist_restart_write(case_name, inst_suffix, target_ymd, target_tod, logunit, my_task, sdat) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end if @@ -567,6 +598,46 @@ subroutine dice_comp_run(importstate, exportstate, target_ymd, target_tod, cosar call ESMF_TraceRegionExit('dice_datamode') call ESMF_TraceRegionExit('DICE_RUN') + contains + subroutine dice_init_dfields(importState, exportState, rc) + ! ----------------------------- + ! Initialize dfields arrays + ! ----------------------------- + + ! input/output variables + type(ESMF_State) , intent(inout) :: importState + type(ESMF_State) , intent(inout) :: exportState + integer , intent(out) :: rc + + ! local variables + integer :: n + integer :: fieldcount + type(ESMF_Field) :: lfield + character(ESMF_MAXSTR) ,pointer :: lfieldnamelist(:) + character(*), parameter :: subName = "(dice_init_dfields) " + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Initialize dfields data type (to map streams to export state fields) + ! Create dfields linked list - used for copying stream fields to export + ! state fields + call ESMF_StateGet(exportState, itemCount=fieldCount, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(lfieldnamelist(fieldCount)) + call ESMF_StateGet(exportState, itemNameList=lfieldnamelist, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1, fieldCount + call ESMF_StateGet(exportState, itemName=trim(lfieldNameList(n)), field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (trim(lfieldnamelist(n)) /= flds_scalar_name) then + call dshr_dfield_add( dfields, sdat, trim(lfieldnamelist(n)), trim(lfieldnamelist(n)), exportState, & + logunit, mainproc, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if + end do + end subroutine dice_init_dfields + end subroutine dice_comp_run !=============================================================================== diff --git a/doc/source/dice.rst b/doc/source/dice.rst index ebd5084b2..5abd2b5bb 100644 --- a/doc/source/dice.rst +++ b/doc/source/dice.rst @@ -27,6 +27,9 @@ ssmi (``dice_datamode_ssmi_mod.F90``) ssmi_iaf (``dice_datamode_ssmi_mod.F90``) - `ssmi_iaf` is the interannually varying version of `ssmi`. +cplhist (``dice_datamode_cplhist_mod.F90``) + - It provides mediator history variables from ice component of previous simulation. + .. _dice-cime-vars: --------------------------------------- diff --git a/docn/docn_datamode_cplhist_mod.F90 b/docn/docn_datamode_cplhist_mod.F90 index 3ff9e65c5..730879364 100644 --- a/docn/docn_datamode_cplhist_mod.F90 +++ b/docn/docn_datamode_cplhist_mod.F90 @@ -96,10 +96,11 @@ subroutine docn_datamode_cplhist_init_pointers(exportState, ocn_fraction, rc) call dshr_state_getfldptr(exportState, 'So_bldepth', fldptr1=So_bldepth, allowNullReturn=.true., rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - So_u(:) = 0.0_r8 - So_v(:) = 0.0_r8 - So_t(:) = TkFrz - So_bldepth(:) = 0.0_r8 + !Allocation depends on exchanged fields, so check before filling arrays with values here + if (associated(So_u)) So_u(:) = 0.0_r8 + if (associated(So_v)) So_v(:) = 0.0_r8 + if (associated(So_t)) So_t(:) = TkFrz + if (associated(So_bldepth)) So_bldepth(:) = 0.0_r8 ! Set export state ocean fraction (So_omask) So_omask(:) = ocn_fraction(:) @@ -107,18 +108,32 @@ subroutine docn_datamode_cplhist_init_pointers(exportState, ocn_fraction, rc) end subroutine docn_datamode_cplhist_init_pointers !=============================================================================== - subroutine docn_datamode_cplhist_advance(rc) + subroutine docn_datamode_cplhist_advance(sst_constant_value, rc) ! input/output variables + real(r8), optional, intent(in) :: sst_constant_value integer, intent(out) :: rc ! local variables + logical :: units_CToK = .true. ! true => convert SST in C to K character(len=*), parameter :: subname='(docn_datamode_cplhist_advance): ' !------------------------------------------------------------------------------- rc = ESMF_SUCCESS - So_t(:) = So_t(:) + TkFrz + !If need unit conversion for So_t (C-->K), + !use existing nml variable sst_constant_value to signal units of input + !i.e., 0-->Celsius, 273.15-->K + + if (present(sst_constant_value)) then + if(sst_constant_value .GT. 230.0_r8) then !interpret input SST in K + units_CToK = .false. !in K already, don't convert + endif + endif + + if (units_CToK) then + So_t(:) = So_t(:) + TkFrz + endif end subroutine docn_datamode_cplhist_advance diff --git a/docn/ocn_comp_nuopc.F90 b/docn/ocn_comp_nuopc.F90 index a5e50ce50..8df6f9566 100644 --- a/docn/ocn_comp_nuopc.F90 +++ b/docn/ocn_comp_nuopc.F90 @@ -605,7 +605,7 @@ subroutine docn_comp_run(importState, exportState, clock, target_ymd, target_tod call docn_datamode_aquaplanet_advance(exportState, model_mesh, sst_constant_value=sst_constant_value, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case('cplhist') - call docn_datamode_cplhist_advance(rc=rc) + call docn_datamode_cplhist_advance(sst_constant_value=sst_constant_value, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end select From 1f9eaaa142c8b07ed6b788c9f44ea02cc86d0bae Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Tue, 27 Aug 2024 10:31:09 -0400 Subject: [PATCH 13/28] Unify gfs, cfsr, and gefs datm datamodes (#63) * For gfs and cfsr datm datamodes, use gefs * Delete datm/datm_datamode_gfs_hafs_mod.F90 * Remove gfs_hafs datamode from atm_comp_nuopc.F90 * Remove gfs_hafs from CMakeLists.txt --- datm/CMakeLists.txt | 3 - datm/atm_comp_nuopc.F90 | 64 ------- datm/datm_datamode_cfsr_mod.F90 | 256 ---------------------------- datm/datm_datamode_gfs_hafs_mod.F90 | 230 ------------------------- datm/datm_datamode_gfs_mod.F90 | 255 --------------------------- 5 files changed, 808 deletions(-) delete mode 100644 datm/datm_datamode_cfsr_mod.F90 delete mode 100644 datm/datm_datamode_gfs_hafs_mod.F90 delete mode 100644 datm/datm_datamode_gfs_mod.F90 diff --git a/datm/CMakeLists.txt b/datm/CMakeLists.txt index 4899e0626..b22ee6be9 100644 --- a/datm/CMakeLists.txt +++ b/datm/CMakeLists.txt @@ -5,9 +5,6 @@ set(SRCFILES atm_comp_nuopc.F90 datm_datamode_core2_mod.F90 datm_datamode_jra_mod.F90 datm_datamode_gefs_mod.F90 - datm_datamode_cfsr_mod.F90 - datm_datamode_gfs_mod.F90 - datm_datamode_gfs_hafs_mod.F90 datm_datamode_era5_mod.F90 datm_datamode_simple_mod.F90) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 7262e0fc0..4fae638c2 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -75,24 +75,6 @@ module cdeps_datm_comp use datm_datamode_gefs_mod , only : datm_datamode_gefs_advance use datm_datamode_gefs_mod , only : datm_datamode_gefs_restart_write use datm_datamode_gefs_mod , only : datm_datamode_gefs_restart_read - - use datm_datamode_cfsr_mod , only : datm_datamode_cfsr_advertise - use datm_datamode_cfsr_mod , only : datm_datamode_cfsr_init_pointers - use datm_datamode_cfsr_mod , only : datm_datamode_cfsr_advance - use datm_datamode_cfsr_mod , only : datm_datamode_cfsr_restart_write - use datm_datamode_cfsr_mod , only : datm_datamode_cfsr_restart_read - - use datm_datamode_gfs_mod , only : datm_datamode_gfs_advertise - use datm_datamode_gfs_mod , only : datm_datamode_gfs_init_pointers - use datm_datamode_gfs_mod , only : datm_datamode_gfs_advance - use datm_datamode_gfs_mod , only : datm_datamode_gfs_restart_write - use datm_datamode_gfs_mod , only : datm_datamode_gfs_restart_read - - use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_advertise - use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_init_pointers - use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_advance - use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_write - use datm_datamode_gfs_hafs_mod , only : datm_datamode_gfs_hafs_restart_read use datm_datamode_simple_mod , only : datm_datamode_simple_advertise use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers @@ -379,9 +361,6 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) trim(datamode) == 'CLMNCEP' .or. & trim(datamode) == 'CPLHIST' .or. & trim(datamode) == 'GEFS' .or. & - trim(datamode) == 'CFSR' .or. & - trim(datamode) == 'GFS' .or. & - trim(datamode) == 'GFS_HAFS' .or. & trim(datamode) == 'ERA5' .or. & trim(datamode) == 'SIMPLE') then else @@ -412,14 +391,6 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) case ('GEFS') call datm_datamode_gefs_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case ('CFSR') - call datm_datamode_cfsr_advertise(exportState, fldsExport, flds_scalar_name, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - case ('GFS') - call datm_datamode_gfs_advertise(exportState, fldsExport, flds_scalar_name, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - case ('GFS_HAFS') - call datm_datamode_gfs_hafs_advertise(exportState, fldsExport, flds_scalar_name, rc) case ('SIMPLE') call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & nlfilename, my_task, vm, rc) @@ -664,14 +635,6 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('GEFS') call datm_datamode_gefs_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('CFSR') - call datm_datamode_cfsr_init_pointers(exportState, sdat, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('GFS') - call datm_datamode_gfs_init_pointers(exportState, sdat, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('GFS_HAFS') - call datm_datamode_gfs_hafs_init_pointers(exportState, sdat, rc) case('SIMPLE') call datm_datamode_simple_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -692,12 +655,6 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_era5_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) case('GEFS') call datm_datamode_gefs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) - case('CFSR') - call datm_datamode_cfsr_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) - case('GFS') - call datm_datamode_gfs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) - case('GFS_HAFS') - call datm_datamode_gfs_hafs_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) case('SIMPLE') call datm_datamode_simple_restart_read(restfilm, inst_suffix, logunit, my_task, mpicom, sdat) end select @@ -751,17 +708,6 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_gefs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & target_tod, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('CFSR') - call datm_datamode_cfsr_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & - target_tod, sdat%model_calendar, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('GFS') - call datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & - target_tod, sdat%model_calendar, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('GFS_HAFS') - call datm_datamode_gfs_hafs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, & - target_tod, sdat%model_calendar, rc) case('SIMPLE') call datm_datamode_simple_advance(target_ymd, target_tod, target_mon, & sdat%model_calendar, rc) @@ -790,16 +736,6 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_gefs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('CFSR') - call datm_datamode_cfsr_restart_write(case_name, inst_suffix, target_ymd, target_tod, & - logunit, my_task, sdat) - case('GFS') - call datm_datamode_gfs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & - logunit, my_task, sdat) - case('GFS_HAFS') - call datm_datamode_gfs_hafs_restart_write(case_name, inst_suffix, target_ymd, target_tod, & - logunit, my_task, sdat) - if (ChkErr(rc,__LINE__,u_FILE_u)) return case('SIMPLE') call datm_datamode_simple_restart_write(case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) diff --git a/datm/datm_datamode_cfsr_mod.F90 b/datm/datm_datamode_cfsr_mod.F90 deleted file mode 100644 index 8ad8cd3d6..000000000 --- a/datm/datm_datamode_cfsr_mod.F90 +++ /dev/null @@ -1,256 +0,0 @@ -module datm_datamode_cfsr_mod - - use ESMF , only : ESMF_State, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO - use NUOPC , only : NUOPC_Advertise - use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs - use shr_sys_mod , only : shr_sys_abort - use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp - use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair - use dshr_methods_mod , only : dshr_state_getfldptr, chkerr - use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer - use dshr_mod , only : dshr_restart_read, dshr_restart_write - use dshr_strdata_mod , only : shr_strdata_type - use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add - - implicit none - private ! except - - public :: datm_datamode_cfsr_advertise - public :: datm_datamode_cfsr_init_pointers - public :: datm_datamode_cfsr_advance - public :: datm_datamode_cfsr_restart_write - public :: datm_datamode_cfsr_restart_read - - ! export state data - real(r8), pointer :: Sa_z(:) => null() - real(r8), pointer :: Sa_u(:) => null() - real(r8), pointer :: Sa_v(:) => null() - real(r8), pointer :: Sa_tbot(:) => null() - real(r8), pointer :: Sa_shum(:) => null() - real(r8), pointer :: Sa_pbot(:) => null() - real(r8), pointer :: Sa_u10m(:) => null() - real(r8), pointer :: Sa_v10m(:) => null() - real(r8), pointer :: Sa_t2m(:) => null() - real(r8), pointer :: Sa_q2m(:) => null() - real(r8), pointer :: Sa_pslv(:) => null() - real(r8), pointer :: Faxa_lwdn(:) => null() - real(r8), pointer :: Faxa_rain(:) => null() - real(r8), pointer :: Faxa_snow(:) => null() - real(r8), pointer :: Faxa_swndr(:) => null() - real(r8), pointer :: Faxa_swndf(:) => null() - real(r8), pointer :: Faxa_swvdr(:) => null() - real(r8), pointer :: Faxa_swvdf(:) => null() - - ! stream data - real(r8), pointer :: strm_mask(:) => null() - - real(r8) :: tbotmax ! units detector - real(r8) :: maskmax ! units detector - - real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ - real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg - real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 - - character(*), parameter :: nullstr = 'undefined' - character(*), parameter :: rpfile = 'rpointer.atm' - character(*), parameter :: u_FILE_u = & - __FILE__ - -!=============================================================================== -contains -!=============================================================================== - - subroutine datm_datamode_cfsr_advertise(exportState, fldsexport, & - flds_scalar_name, rc) - - ! input/output variables - type(esmf_State) , intent(inout) :: exportState - type(fldlist_type) , pointer :: fldsexport - character(len=*) , intent(in) :: flds_scalar_name - integer , intent(out) :: rc - - ! local variables - type(fldlist_type), pointer :: fldList - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) - call dshr_fldList_add(fldsExport, 'Sa_z' ) - call dshr_fldList_add(fldsExport, 'Sa_u' ) - call dshr_fldList_add(fldsExport, 'Sa_v' ) - call dshr_fldList_add(fldsExport, 'Sa_tbot' ) - call dshr_fldList_add(fldsExport, 'Sa_pbot' ) - call dshr_fldList_add(fldsExport, 'Sa_shum' ) - call dshr_fldList_add(fldsExport, 'Sa_u10m' ) - call dshr_fldList_add(fldsExport, 'Sa_v10m' ) - call dshr_fldList_add(fldsExport, 'Sa_t2m' ) - call dshr_fldList_add(fldsExport, 'Sa_q2m' ) - call dshr_fldList_add(fldsExport, 'Sa_pslv' ) - call dshr_fldList_add(fldsExport, 'Faxa_rain' ) - call dshr_fldList_add(fldsExport, 'Faxa_snow' ) - call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) - call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) - call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) - call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) - call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) - - fldlist => fldsExport ! the head of the linked list - do while (associated(fldlist)) - call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) - fldList => fldList%next - enddo - - end subroutine datm_datamode_cfsr_advertise - - !=============================================================================== - subroutine datm_datamode_cfsr_init_pointers(exportState, sdat, rc) - - ! input/output variables - type(ESMF_State) , intent(inout) :: exportState - type(shr_strdata_type) , intent(in) :: sdat - integer , intent(out) :: rc - - ! local variables - character(len=*), parameter :: subname='(datm_init_pointers): ' - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! initialize pointers for module level stream arrays - call shr_strdata_get_stream_pointer( sdat, 'Sa_mask' , strm_mask , rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - ! get export state pointers - call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_t2m' , fldptr1=Sa_t2m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_q2m' , fldptr1=Sa_q2m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_snow' , fldptr1=Faxa_snow, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - end subroutine datm_datamode_cfsr_init_pointers - - !=============================================================================== - subroutine datm_datamode_cfsr_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) - use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MAX, ESMF_VM - - ! input/output variables - type(ESMF_State) , intent(inout) :: exportState - logical , intent(in) :: mainproc - integer , intent(in) :: logunit - integer , intent(in) :: mpicom - integer , intent(in) :: target_ymd - integer , intent(in) :: target_tod - character(len=*) , intent(in) :: model_calendar - integer , intent(out) :: rc - - ! local variables - logical :: first_time = .true. - integer :: n ! indices - integer :: lsize ! size of attr vect - real(r8) :: rtmp(2) - type(ESMF_VM) :: vm - character(len=*), parameter :: subname='(datm_datamode_cfsr_advance): ' - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - lsize = size(strm_mask) - - if (first_time) then - call ESMF_VMGetCurrent(vm, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - ! determine tbotmax (see below for use) - rtmp(1) = maxval(Sa_tbot(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - tbotmax = rtmp(2) - if (mainproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax - - ! determine maskmax (see below for use) - rtmp(1) = maxval(strm_mask(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - maskmax = rtmp(2) - if (mainproc) write(logunit,*) trim(subname),' maskmax = ',maskmax - - ! reset first_time - first_time = .false. - end if - - do n = 1, lsize - !--- temperature --- - if (tbotmax < 50.0_r8) Sa_tbot(n) = Sa_tbot(n) + tkFrz - ! Limit very cold forcing to 180K - Sa_tbot(n) = max(180._r8, Sa_tbot(n)) - end do - - end subroutine datm_datamode_cfsr_advance - - !=============================================================================== - subroutine datm_datamode_cfsr_restart_write(case_name, inst_suffix, ymd, tod, & - logunit, my_task, sdat) - - ! input/output variables - character(len=*) , intent(in) :: case_name - character(len=*) , intent(in) :: inst_suffix - integer , intent(in) :: ymd ! model date - integer , intent(in) :: tod ! model sec into model date - integer , intent(in) :: logunit - integer , intent(in) :: my_task - type(shr_strdata_type) , intent(inout) :: sdat - !------------------------------------------------------------------------------- - - call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, ymd, tod, & - logunit, my_task, sdat) - - end subroutine datm_datamode_cfsr_restart_write - - !=============================================================================== - subroutine datm_datamode_cfsr_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) - - ! input/output arguments - character(len=*) , intent(inout) :: rest_filem - character(len=*) , intent(in) :: inst_suffix - integer , intent(in) :: logunit - integer , intent(in) :: my_task - integer , intent(in) :: mpicom - type(shr_strdata_type) , intent(inout) :: sdat - !------------------------------------------------------------------------------- - - call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) - - end subroutine datm_datamode_cfsr_restart_read - -end module datm_datamode_cfsr_mod diff --git a/datm/datm_datamode_gfs_hafs_mod.F90 b/datm/datm_datamode_gfs_hafs_mod.F90 deleted file mode 100644 index 9e6805071..000000000 --- a/datm/datm_datamode_gfs_hafs_mod.F90 +++ /dev/null @@ -1,230 +0,0 @@ -module datm_datamode_gfs_hafs_mod - - use ESMF , only : ESMF_State, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO - use NUOPC , only : NUOPC_Advertise - use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs - use shr_sys_mod , only : shr_sys_abort - use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp - use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair - use dshr_methods_mod , only : dshr_state_getfldptr, chkerr - use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer - use dshr_mod , only : dshr_restart_read, dshr_restart_write - use dshr_strdata_mod , only : shr_strdata_type - use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add - - implicit none - private ! except - - public :: datm_datamode_gfs_hafs_advertise - public :: datm_datamode_gfs_hafs_init_pointers - public :: datm_datamode_gfs_hafs_advance - public :: datm_datamode_gfs_hafs_restart_write - public :: datm_datamode_gfs_hafs_restart_read - - ! export state data - real(r8), pointer :: Sd_pslv(:) => null() - real(r8), pointer :: Sd_u10m(:) => null() - real(r8), pointer :: Sd_v10m(:) => null() - real(r8), pointer :: Faxd_swvdr(:) => null() - real(r8), pointer :: Faxd_swvdf(:) => null() - real(r8), pointer :: Faxd_swndr(:) => null() - real(r8), pointer :: Faxd_swndf(:) => null() - real(r8), pointer :: Faxd_lwnet(:) => null() - real(r8), pointer :: Faxd_taux(:) => null() - real(r8), pointer :: Faxd_tauy(:) => null() - real(r8), pointer :: Faxd_sen(:) => null() - real(r8), pointer :: Faxd_lat(:) => null() - real(r8), pointer :: Faxd_rain(:) => null() - - ! stream data - real(r8), pointer :: strm_rain(:) => null() - - real(r8) :: rain_min ! rain value detector - - real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ - real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg - real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 - - character(*), parameter :: nullstr = 'undefined' - character(*), parameter :: rpfile = 'rpointer.atm' - character(*), parameter :: u_FILE_u = & - __FILE__ - -!=============================================================================== -contains -!=============================================================================== - - subroutine datm_datamode_gfs_hafs_advertise(exportState, fldsexport, & - flds_scalar_name, rc) - - ! input/output variables - type(esmf_State) , intent(inout) :: exportState - type(fldlist_type) , pointer :: fldsexport - character(len=*) , intent(in) :: flds_scalar_name - integer , intent(out) :: rc - - ! local variables - type(fldlist_type), pointer :: fldList - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) - call dshr_fldList_add(fldsExport, 'Sd_pslv' ) - call dshr_fldList_add(fldsExport, 'Sd_u10m' ) - call dshr_fldList_add(fldsExport, 'Sd_v10m' ) - call dshr_fldList_add(fldsExport, 'Faxd_swvdr' ) - call dshr_fldList_add(fldsExport, 'Faxd_swvdf' ) - call dshr_fldList_add(fldsExport, 'Faxd_swndr' ) - call dshr_fldList_add(fldsExport, 'Faxd_swndf' ) - call dshr_fldList_add(fldsExport, 'Faxd_lwnet' ) - call dshr_fldList_add(fldsExport, 'Faxd_taux' ) - call dshr_fldList_add(fldsExport, 'Faxd_tauy' ) - call dshr_fldList_add(fldsExport, 'Faxd_sen' ) - call dshr_fldList_add(fldsExport, 'Faxd_lat' ) - call dshr_fldList_add(fldsExport, 'Faxd_rain' ) - - fldlist => fldsExport ! the head of the linked list - do while (associated(fldlist)) - call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) - fldList => fldList%next - enddo - - end subroutine datm_datamode_gfs_hafs_advertise - - !=============================================================================== - subroutine datm_datamode_gfs_hafs_init_pointers(exportState, sdat, rc) - - ! input/output variables - type(ESMF_State) , intent(inout) :: exportState - type(shr_strdata_type) , intent(in) :: sdat - integer , intent(out) :: rc - - ! local variables - character(len=*), parameter :: subname='(datm_init_pointers): ' - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! initialize pointers for module level stream arrays - !call shr_strdata_get_stream_pointer( sdat, 'Sa_mask' , strm_mask , rc) - call shr_strdata_get_stream_pointer( sdat, 'Faxd_rain' , strm_rain , rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - ! get export state pointers - call dshr_state_getfldptr(exportState, 'Sd_pslv' , fldptr1=Sd_pslv , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sd_u10m' , fldptr1=Sd_u10m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sd_v10m' , fldptr1=Sd_v10m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_swvdr' , fldptr1=Faxd_swvdr , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_swvdf' , fldptr1=Faxd_swvdf , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_swndr' , fldptr1=Faxd_swndr , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_swndf' , fldptr1=Faxd_swndf , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_lwnet' , fldptr1=Faxd_lwnet, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_taux' , fldptr1=Faxd_taux , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_tauy' , fldptr1=Faxd_tauy , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_sen' , fldptr1=Faxd_sen , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_lat' , fldptr1=Faxd_lat , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxd_rain' , fldptr1=Faxd_rain , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - end subroutine datm_datamode_gfs_hafs_init_pointers - - !=============================================================================== - subroutine datm_datamode_gfs_hafs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) - use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MIN, ESMF_VM - - ! input/output variables - type(ESMF_State) , intent(inout) :: exportState - logical , intent(in) :: mainproc - integer , intent(in) :: logunit - integer , intent(in) :: mpicom - integer , intent(in) :: target_ymd - integer , intent(in) :: target_tod - character(len=*) , intent(in) :: model_calendar - integer , intent(out) :: rc - - ! local variables - logical :: first_time = .true. - integer :: n ! indices - integer :: lsize ! size of attr vect - real(r8) :: rtmp(2) - type(ESMF_VM) :: vm - character(len=*), parameter :: subname='(datm_datamode_gfs_hafs_advance): ' - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - lsize = size(strm_rain) - - if (first_time) then - call ESMF_VMGetCurrent(vm, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - ! determine minimum Faxd_rain (see below for use) - rtmp(1) = minval(strm_rain(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MIN, rc=rc) - rain_min = rtmp(2) - if (mainproc) write(logunit,*) trim(subname),' rain_min = ',rain_min - - ! reset first_time - first_time = .false. - end if - - do n = 1, lsize - !--- Faxd_rain is positive --- - if (associated(Faxd_rain)) then - if (rain_min < 0.0_r8) Faxd_rain(n) = max(0.0_r8,Faxd_rain(n)) - end if - end do - - end subroutine datm_datamode_gfs_hafs_advance - - !=============================================================================== - subroutine datm_datamode_gfs_hafs_restart_write(case_name, inst_suffix, ymd, tod, & - logunit, my_task, sdat) - - ! input/output variables - character(len=*) , intent(in) :: case_name - character(len=*) , intent(in) :: inst_suffix - integer , intent(in) :: ymd ! model date - integer , intent(in) :: tod ! model sec into model date - integer , intent(in) :: logunit - integer , intent(in) :: my_task - type(shr_strdata_type) , intent(inout) :: sdat - !------------------------------------------------------------------------------- - - call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, ymd, tod, & - logunit, my_task, sdat) - - end subroutine datm_datamode_gfs_hafs_restart_write - - !=============================================================================== - subroutine datm_datamode_gfs_hafs_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) - - ! input/output arguments - character(len=*) , intent(inout) :: rest_filem - character(len=*) , intent(in) :: inst_suffix - integer , intent(in) :: logunit - integer , intent(in) :: my_task - integer , intent(in) :: mpicom - type(shr_strdata_type) , intent(inout) :: sdat - !------------------------------------------------------------------------------- - - call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) - - end subroutine datm_datamode_gfs_hafs_restart_read - -end module datm_datamode_gfs_hafs_mod diff --git a/datm/datm_datamode_gfs_mod.F90 b/datm/datm_datamode_gfs_mod.F90 deleted file mode 100644 index cc4b05fa4..000000000 --- a/datm/datm_datamode_gfs_mod.F90 +++ /dev/null @@ -1,255 +0,0 @@ -module datm_datamode_gfs_mod - - use ESMF , only : ESMF_State, ESMF_SUCCESS, ESMF_LogWrite, ESMF_LOGMSG_INFO - use NUOPC , only : NUOPC_Advertise - use shr_kind_mod , only : r8=>shr_kind_r8, i8=>shr_kind_i8, cl=>shr_kind_cl, cs=>shr_kind_cs - use shr_sys_mod , only : shr_sys_abort - use shr_precip_mod , only : shr_precip_partition_rain_snow_ramp - use shr_const_mod , only : shr_const_tkfrz, shr_const_rhofw, shr_const_rdair - use dshr_methods_mod , only : dshr_state_getfldptr, chkerr - use dshr_strdata_mod , only : shr_strdata_type, shr_strdata_get_stream_pointer - use dshr_mod , only : dshr_restart_read, dshr_restart_write - use dshr_strdata_mod , only : shr_strdata_type - use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add - - implicit none - private ! except - - public :: datm_datamode_gfs_advertise - public :: datm_datamode_gfs_init_pointers - public :: datm_datamode_gfs_advance - public :: datm_datamode_gfs_restart_write - public :: datm_datamode_gfs_restart_read - - ! export state data - real(r8), pointer :: Sa_z(:) => null() - real(r8), pointer :: Sa_u(:) => null() - real(r8), pointer :: Sa_v(:) => null() - real(r8), pointer :: Sa_tbot(:) => null() - real(r8), pointer :: Sa_shum(:) => null() - real(r8), pointer :: Sa_pbot(:) => null() - real(r8), pointer :: Sa_u10m(:) => null() - real(r8), pointer :: Sa_v10m(:) => null() - real(r8), pointer :: Sa_t2m(:) => null() - real(r8), pointer :: Sa_q2m(:) => null() - real(r8), pointer :: Sa_pslv(:) => null() - real(r8), pointer :: Faxa_lwdn(:) => null() - real(r8), pointer :: Faxa_rain(:) => null() - real(r8), pointer :: Faxa_snow(:) => null() - real(r8), pointer :: Faxa_swndr(:) => null() - real(r8), pointer :: Faxa_swndf(:) => null() - real(r8), pointer :: Faxa_swvdr(:) => null() - real(r8), pointer :: Faxa_swvdf(:) => null() - - ! stream data - real(r8), pointer :: strm_mask(:) => null() - - real(r8) :: tbotmax ! units detector - real(r8) :: maskmax ! units detector - - real(r8) , parameter :: tKFrz = SHR_CONST_TKFRZ - real(r8) , parameter :: rdair = SHR_CONST_RDAIR ! dry air gas constant ~ J/K/kg - real(r8) , parameter :: rhofw = SHR_CONST_RHOFW ! density of fresh water ~ kg/m^3 - - character(*), parameter :: nullstr = 'undefined' - character(*), parameter :: rpfile = 'rpointer.atm' - character(*), parameter :: u_FILE_u = & - __FILE__ - -!=============================================================================== -contains -!=============================================================================== - - subroutine datm_datamode_gfs_advertise(exportState, fldsexport, & - flds_scalar_name, rc) - - ! input/output variables - type(esmf_State) , intent(inout) :: exportState - type(fldlist_type) , pointer :: fldsexport - character(len=*) , intent(in) :: flds_scalar_name - integer , intent(out) :: rc - - ! local variables - type(fldlist_type), pointer :: fldList - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) - call dshr_fldList_add(fldsExport, 'Sa_z' ) - call dshr_fldList_add(fldsExport, 'Sa_u' ) - call dshr_fldList_add(fldsExport, 'Sa_v' ) - call dshr_fldList_add(fldsExport, 'Sa_tbot' ) - call dshr_fldList_add(fldsExport, 'Sa_pbot' ) - call dshr_fldList_add(fldsExport, 'Sa_shum' ) - call dshr_fldList_add(fldsExport, 'Sa_u10m' ) - call dshr_fldList_add(fldsExport, 'Sa_v10m' ) - call dshr_fldList_add(fldsExport, 'Sa_t2m' ) - call dshr_fldList_add(fldsExport, 'Sa_q2m' ) - call dshr_fldList_add(fldsExport, 'Sa_pslv' ) - call dshr_fldList_add(fldsExport, 'Faxa_rain' ) - call dshr_fldList_add(fldsExport, 'Faxa_snow' ) - call dshr_fldList_add(fldsExport, 'Faxa_swndr' ) - call dshr_fldList_add(fldsExport, 'Faxa_swvdr' ) - call dshr_fldList_add(fldsExport, 'Faxa_swndf' ) - call dshr_fldList_add(fldsExport, 'Faxa_swvdf' ) - call dshr_fldList_add(fldsExport, 'Faxa_lwdn' ) - - fldlist => fldsExport ! the head of the linked list - do while (associated(fldlist)) - call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) - fldList => fldList%next - enddo - - end subroutine datm_datamode_gfs_advertise - - !=============================================================================== - subroutine datm_datamode_gfs_init_pointers(exportState, sdat, rc) - - ! input/output variables - type(ESMF_State) , intent(inout) :: exportState - type(shr_strdata_type) , intent(in) :: sdat - integer , intent(out) :: rc - - ! local variables - character(len=*), parameter :: subname='(datm_init_pointers): ' - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - ! initialize pointers for module level stream arrays - call shr_strdata_get_stream_pointer( sdat, 'Sa_mask' , strm_mask , rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - ! get export state pointers - call dshr_state_getfldptr(exportState, 'Sa_z' , fldptr1=Sa_z , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_u' , fldptr1=Sa_u , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_v' , fldptr1=Sa_v , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_tbot' , fldptr1=Sa_tbot , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_pbot' , fldptr1=Sa_pbot , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_shum' , fldptr1=Sa_shum , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_u10m' , fldptr1=Sa_u10m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_v10m' , fldptr1=Sa_v10m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_t2m' , fldptr1=Sa_t2m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_q2m' , fldptr1=Sa_q2m , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Sa_pslv' , fldptr1=Sa_pslv , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_rain' , fldptr1=Faxa_rain , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_snow' , fldptr1=Faxa_snow, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swvdr' , fldptr1=Faxa_swvdr , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swvdf' , fldptr1=Faxa_swvdf , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swndr' , fldptr1=Faxa_swndr , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_swndf' , fldptr1=Faxa_swndf , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - end subroutine datm_datamode_gfs_init_pointers - - !=============================================================================== - subroutine datm_datamode_gfs_advance(exportstate, mainproc, logunit, mpicom, target_ymd, target_tod, model_calendar, rc) - use ESMF, only: ESMF_VMGetCurrent, ESMF_VMAllReduce, ESMF_REDUCE_MAX, ESMF_VM - ! input/output variables - type(ESMF_State) , intent(inout) :: exportState - logical , intent(in) :: mainproc - integer , intent(in) :: logunit - integer , intent(in) :: mpicom - integer , intent(in) :: target_ymd - integer , intent(in) :: target_tod - character(len=*) , intent(in) :: model_calendar - integer , intent(out) :: rc - - ! local variables - logical :: first_time = .true. - integer :: n ! indices - integer :: lsize ! size of attr vect - real(r8) :: rtmp(2) - type(ESMF_VM) :: vm - character(len=*), parameter :: subname='(datm_datamode_gfs_advance): ' - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - lsize = size(strm_mask) - - if (first_time) then - call ESMF_VMGetCurrent(vm, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - ! determine tbotmax (see below for use) - rtmp(1) = maxval(Sa_tbot(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - tbotmax = rtmp(2) - if (mainproc) write(logunit,*) trim(subname),' tbotmax = ',tbotmax - - ! determine maskmax (see below for use) - rtmp(1) = maxval(strm_mask(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - maskmax = rtmp(2) - if (mainproc) write(logunit,*) trim(subname),' maskmax = ',maskmax - - ! reset first_time - first_time = .false. - end if - - do n = 1, lsize - !--- temperature --- - if (tbotmax < 50.0_r8) Sa_tbot(n) = Sa_tbot(n) + tkFrz - ! Limit very cold forcing to 180K - Sa_tbot(n) = max(180._r8, Sa_tbot(n)) - end do - - end subroutine datm_datamode_gfs_advance - - !=============================================================================== - subroutine datm_datamode_gfs_restart_write(case_name, inst_suffix, ymd, tod, & - logunit, my_task, sdat) - - ! input/output variables - character(len=*) , intent(in) :: case_name - character(len=*) , intent(in) :: inst_suffix - integer , intent(in) :: ymd ! model date - integer , intent(in) :: tod ! model sec into model date - integer , intent(in) :: logunit - integer , intent(in) :: my_task - type(shr_strdata_type) , intent(inout) :: sdat - !------------------------------------------------------------------------------- - - call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, ymd, tod, & - logunit, my_task, sdat) - - end subroutine datm_datamode_gfs_restart_write - - !=============================================================================== - subroutine datm_datamode_gfs_restart_read(rest_filem, inst_suffix, logunit, my_task, mpicom, sdat) - - ! input/output arguments - character(len=*) , intent(inout) :: rest_filem - character(len=*) , intent(in) :: inst_suffix - integer , intent(in) :: logunit - integer , intent(in) :: my_task - integer , intent(in) :: mpicom - type(shr_strdata_type) , intent(inout) :: sdat - !------------------------------------------------------------------------------- - - call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat) - - end subroutine datm_datamode_gfs_restart_read - -end module datm_datamode_gfs_mod From 7a181896f16fd9f1bbdaf556248395fa5ae716ad Mon Sep 17 00:00:00 2001 From: Nick Szapiro Date: Mon, 7 Oct 2024 18:16:53 +0000 Subject: [PATCH 14/28] Remove duplicate SIMPLE case statements (from merge) --- datm/atm_comp_nuopc.F90 | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 6259dbc4d..5180164d7 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -401,10 +401,6 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & nlfilename, my_task, vm, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case ('SIMPLE') - call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & - nlfilename, my_task, vm, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return end select end subroutine InitializeAdvertise @@ -648,9 +644,6 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe case('SIMPLE') call datm_datamode_simple_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('SIMPLE') - call datm_datamode_simple_init_pointers(exportState, sdat, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Read restart if needed @@ -725,10 +718,6 @@ subroutine datm_comp_run(importState, exportState, target_ymd, target_tod, targe call datm_datamode_simple_advance(target_ymd, target_tod, target_mon, & sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('SIMPLE') - call datm_datamode_simple_advance(target_ymd, target_tod, target_mon, & - sdat%model_calendar, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Write restarts if needed From 395f9dd6f8c6870cdb4592dba07c3f6f484aac69 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Tue, 8 Oct 2024 03:35:39 -0400 Subject: [PATCH 15/28] Remove duplicate use datm_datamode_simple_mod in atm_comp_nuopc.F90 --- datm/atm_comp_nuopc.F90 | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 5180164d7..048501a20 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -82,18 +82,6 @@ module cdeps_datm_comp use datm_datamode_simple_mod , only : datm_datamode_simple_restart_write use datm_datamode_simple_mod , only : datm_datamode_simple_restart_read - use datm_datamode_simple_mod , only : datm_datamode_simple_advertise - use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers - use datm_datamode_simple_mod , only : datm_datamode_simple_advance - use datm_datamode_simple_mod , only : datm_datamode_simple_restart_write - use datm_datamode_simple_mod , only : datm_datamode_simple_restart_read - - use datm_datamode_simple_mod , only : datm_datamode_simple_advertise - use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers - use datm_datamode_simple_mod , only : datm_datamode_simple_advance - use datm_datamode_simple_mod , only : datm_datamode_simple_restart_write - use datm_datamode_simple_mod , only : datm_datamode_simple_restart_read - implicit none private ! except From 51f8cd20c15fe39ef1168d59d5077812b6508544 Mon Sep 17 00:00:00 2001 From: Nick Szapiro Date: Tue, 10 Dec 2024 22:21:20 +0000 Subject: [PATCH 16/28] Compile fixes --- dice/dice_datamode_cplhist_mod.F90 | 5 ++--- dice/ice_comp_nuopc.F90 | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/dice/dice_datamode_cplhist_mod.F90 b/dice/dice_datamode_cplhist_mod.F90 index 6f5494a1f..8b42feb2f 100644 --- a/dice/dice_datamode_cplhist_mod.F90 +++ b/dice/dice_datamode_cplhist_mod.F90 @@ -180,12 +180,11 @@ subroutine dice_datamode_cplhist_restart_write(rpfile, case_name, inst_suffix, y end subroutine dice_datamode_cplhist_restart_write !=============================================================================== - subroutine dice_datamode_cplhist_restart_read(rest_filem, rpfile, inst_suffix, logunit, my_task, mpicom, sdat) + subroutine dice_datamode_cplhist_restart_read(rest_filem, rpfile, logunit, my_task, mpicom, sdat) ! input/output arguments character(len=*) , intent(inout) :: rest_filem character(len=*) , intent(in) :: rpfile - character(len=*) , intent(in) :: inst_suffix integer , intent(in) :: logunit integer , intent(in) :: my_task integer , intent(in) :: mpicom @@ -194,7 +193,7 @@ subroutine dice_datamode_cplhist_restart_read(rest_filem, rpfile, inst_suffix, l integer :: rc - call dshr_restart_read(rest_filem, rpfile, inst_suffix, nullstr, logunit, my_task, mpicom, sdat, rc) + call dshr_restart_read(rest_filem, rpfile, logunit, my_task, mpicom, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end subroutine dice_datamode_cplhist_restart_read diff --git a/dice/ice_comp_nuopc.F90 b/dice/ice_comp_nuopc.F90 index 3a0ba86a8..62186f2c8 100644 --- a/dice/ice_comp_nuopc.F90 +++ b/dice/ice_comp_nuopc.F90 @@ -533,7 +533,7 @@ subroutine dice_comp_run(gcomp, importstate, exportstate, target_ymd, target_tod case('ssmi', 'ssmi_iaf') call dice_datamode_ssmi_restart_read(gcomp, restfilm, rpfile, logunit, my_task, mpicom, sdat) case('cplhist') - call dice_datamode_cplhist_restart_read(restfilm, rpfile, inst_suffix, logunit, my_task, mpicom, sdat) + call dice_datamode_cplhist_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat) end select end if From 7477bea2c723289af296713f26951033324deed0 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Fri, 25 Sep 2026 00:07:35 -0400 Subject: [PATCH 17/28] Start datm_datamode_ufs_mod.F90 --- datm/datm_datamode_ufs_mod.F90 | 272 +++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 datm/datm_datamode_ufs_mod.F90 diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 new file mode 100644 index 000000000..908e2b601 --- /dev/null +++ b/datm/datm_datamode_ufs_mod.F90 @@ -0,0 +1,272 @@ +!=============================================================================== +! +! Module: datm_datamode_ufs_mod +! +! Description: +! Unified datamode for CDEPS. Replaces hardcoded datamodes with a dynamic, +! configuration-driven approach. +! +! Phase 1: Automatically maps any variable defined in the ESMF config stream +! directly to the export state. +! Phase 2: Executes user-configurable, chained derived-variable calculations +! driven by the calc_opts string passed from the NUOPC cap. +! +!=============================================================================== +module datm_datamode_ufs_mod + + use ESMF + use NUOPC + + ! CDEPS-native imports + use shr_kind_mod, only: r8 => shr_kind_r8 + use shr_strdata_mod, only: shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_state_mod, only: dshr_state_getfldptr + use shr_log_mod, only: shr_log_error + use dshr_utils_mod, only: ChkErr + use dshr_stream_mod, only: dshr_stream_type, shr_stream_init_from_esmfconfig + + implicit none + private + + public :: DatamodeUnifiedInit + public :: DatamodeUnifiedRun + public :: unified_datamode_type + + character(len=*), parameter :: u_FILE_u = 'cdeps_datamode_unified_mod.F90' + + !> \brief Maps configuration string to persistent memory pointers + type :: unified_var_map + character(len=64) :: var_name + real(r8), pointer :: ptr_strm(:) => null() + real(r8), pointer :: ptr_exp(:) => null() + end type unified_var_map + + !> \brief Master state for the unified datamode + type :: unified_datamode_type + type(unified_var_map), allocatable :: var_maps(:) + end type unified_datamode_type + +contains + + !============================================================================= + ! \brief Parse ESMF config for stream variables and dynamically build map + !============================================================================= + subroutine DatamodeUnifiedInit(config, unified_state, rc) + type(ESMF_Config), intent(in) :: config + type(unified_datamode_type), intent(inout) :: unified_state + integer, intent(out) :: rc + + character(len=*), parameter :: subName = 'DatamodeUnifiedInit: ' + type(dshr_stream_type), allocatable :: streams(:) + integer :: i, j + + rc = ESMF_SUCCESS + + ! Parse ESMF Config for 1-to-1 Stream Variables (Dynamically Appended) + call shr_stream_init_from_esmfconfig(streams, config, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (allocated(streams)) then + do i = 1, size(streams) + do j = 1, streams(i)%nvars + ! Dynamically grow the var_maps array using move_alloc + call append_var_map(unified_state%var_maps, streams(i)%fldName(j)) + end do + end do + deallocate(streams) + end if + + end subroutine DatamodeUnifiedInit + + + !============================================================================= + ! \brief Maps raw variables, then chains calculations driven by calc_opts + !============================================================================= + subroutine DatamodeUnifiedRun(sdat, exportState, unified_state, calc_opts, rc) + type(shr_strdata_type), intent(inout) :: sdat + type(ESMF_State), intent(inout) :: exportState + type(unified_datamode_type), intent(inout) :: unified_state + character(len=*), intent(in) :: calc_opts + integer, intent(out) :: rc + + character(len=*), parameter :: subName = 'DatamodeUnifiedRun: ' + integer :: i + + rc = ESMF_SUCCESS + + ! ------------------------------------------------------------------------- + ! Phase 1: Ingestion (Stream -> Export State) + ! ------------------------------------------------------------------------- + if (allocated(unified_state%var_maps)) then + do i = 1, size(unified_state%var_maps) + + call shr_strdata_get_stream_pointer(sdat, trim(unified_state%var_maps(i)%var_name), & + unified_state%var_maps(i)%ptr_strm, requirePointer=.true., & + errmsg=trim(subName)//'ERROR: stream pointer missing for '//trim(unified_state%var_maps(i)%var_name), & + rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call dshr_state_getfldptr(exportState, trim(unified_state%var_maps(i)%var_name), & + fldptr1=unified_state%var_maps(i)%ptr_exp, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + unified_state%var_maps(i)%ptr_exp(:) = unified_state%var_maps(i)%ptr_strm(:) + + end do + end if + + ! ------------------------------------------------------------------------- + ! Phase 2: Chained Calculations Driver + ! ------------------------------------------------------------------------- + ! Only enter the driver if there are options requested to save overhead + if (len_trim(calc_opts) > 0) then + call DatamodeUnifiedCalcDriver(exportState, calc_opts, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine DatamodeUnifiedRun + + + !============================================================================= + ! \brief Subroutine to dynamically append variables (Fortran 2003 move_alloc) + !============================================================================= + subroutine append_var_map(var_maps, new_var_name) + type(unified_var_map), allocatable, intent(inout) :: var_maps(:) + character(len=*), intent(in) :: new_var_name + + type(unified_var_map), allocatable :: temp_maps(:) + integer :: current_size + + if (allocated(var_maps)) then + current_size = size(var_maps) + allocate(temp_maps(current_size + 1)) + temp_maps(1:current_size) = var_maps + temp_maps(current_size + 1)%var_name = trim(new_var_name) + call move_alloc(from=temp_maps, to=var_maps) + else + allocate(var_maps(1)) + var_maps(1)%var_name = trim(new_var_name) + end if + end subroutine append_var_map + + + !============================================================================= + ! \brief Driver subroutine to route execution based on calc_opts string + !============================================================================= + subroutine DatamodeUnifiedCalcDriver(exportState, calc_opts, rc) + type(ESMF_State), intent(inout) :: exportState + character(len=*), intent(in) :: calc_opts + integer, intent(out) :: rc + + rc = ESMF_SUCCESS + + ! 1. Convert cumulative precipitation (m) to rate (kg/m^2/s) + if (index(calc_opts, 'convert_precip_accum_to_rate') > 0) then + call calc_convert_precip_accum_to_rate(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! 2. Convert cumulative radiation (J/m^2) to flux (W/m^2) + if (index(calc_opts, 'convert_rad_accum_to_flux') > 0) then + call calc_convert_rad_accum_to_flux(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! 3. Partition net shortwave radiation into bands + if (index(calc_opts, 'partition_sw_4band') > 0) then + call calc_partition_sw_4band(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! 4. Partition precipitation into rain and snow + if (index(calc_opts, 'partition_precip_freezing') > 0) then + call calc_partition_precip_freezing(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine DatamodeUnifiedCalcDriver + + + !============================================================================= + ! Modular Calculation Subroutines + !============================================================================= + + subroutine calc_convert_precip_accum_to_rate(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + character(len=*), parameter :: subName = 'calc_convert_precip_accum_to_rate: ' + real(r8), pointer :: Faxa_prec(:) => null() + + rc = ESMF_SUCCESS + call dshr_state_getfldptr(exportState, 'Faxa_prec', fldptr1=Faxa_prec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (.not. associated(Faxa_prec)) then + call shr_log_error(trim(subName)//'ERROR: Faxa_prec required.', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! Convert from cumulative meters per hour to kg/m^2/s + ! (rho_water = 1000 kg/m^3, time = 3600 s) + Faxa_prec(:) = Faxa_prec(:) * (1000.0_r8 / 3600.0_r8) + end subroutine calc_convert_precip_accum_to_rate + + + subroutine calc_convert_rad_accum_to_flux(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + character(len=*), parameter :: subName = 'calc_convert_rad_accum_to_flux: ' + real(r8), pointer :: Faxa_swdn(:) => null() + + rc = ESMF_SUCCESS + call dshr_state_getfldptr(exportState, 'Faxa_swdn', fldptr1=Faxa_swdn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (associated(Faxa_swdn)) then + Faxa_swdn(:) = Faxa_swdn(:) / 3600.0_r8 + end if + end subroutine calc_convert_rad_accum_to_flux + + + subroutine calc_partition_sw_4band(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + character(len=*), parameter :: subName = 'calc_partition_sw_4band: ' + + real(r8), pointer :: Faxa_swdn(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + + rc = ESMF_SUCCESS + ! (Fetch pointers and validate them here...) + end subroutine calc_partition_sw_4band + + + subroutine calc_partition_precip_freezing(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + character(len=*), parameter :: subName = 'calc_partition_precip_freezing: ' + + real(r8), pointer :: Faxa_prec(:) => null() + real(r8), pointer :: Faxa_prrn(:) => null() + real(r8), pointer :: Faxa_prsn(:) => null() + + rc = ESMF_SUCCESS + call dshr_state_getfldptr(exportState, 'Faxa_prec', fldptr1=Faxa_prec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (.not. associated(Faxa_prec)) then + call shr_log_error(trim(subName)//'ERROR: Faxa_prec required.', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + call dshr_state_getfldptr(exportState, 'Faxa_prrn', fldptr1=Faxa_prrn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_prsn', fldptr1=Faxa_prsn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Check associations and partition... + end subroutine calc_partition_precip_freezing + +end module datm_datamode_ufs_mod From cf94bfd3052f72524ec74113e19956a836535995 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Fri, 25 Sep 2026 01:12:19 -0400 Subject: [PATCH 18/28] Next version of datm/datm_datamode_ufs_mod.F90 following API of other datamodes --- datm/datm_datamode_ufs_mod.F90 | 276 ++++++++++++++++++++------------- 1 file changed, 166 insertions(+), 110 deletions(-) diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index 908e2b601..9011bad7d 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -3,13 +3,12 @@ ! Module: datm_datamode_ufs_mod ! ! Description: -! Unified datamode for CDEPS. Replaces hardcoded datamodes with a dynamic, +! Configurable datamode for UFS. Replaces hardcoded datamodes with a dynamic, ! configuration-driven approach. ! -! Phase 1: Automatically maps any variable defined in the ESMF config stream -! directly to the export state. -! Phase 2: Executes user-configurable, chained derived-variable calculations -! driven by the calc_opts string passed from the NUOPC cap. +! - datm_datamode_ufs_advertise: Parses config and advertises stream variables. +! - datm_datamode_ufs_init_pointers: Caches pass-through pointers in state object. +! - datm_datamode_ufs_advance: Executes raw copy and chained calculations in-place. ! !=============================================================================== module datm_datamode_ufs_mod @@ -18,173 +17,198 @@ module datm_datamode_ufs_mod use NUOPC ! CDEPS-native imports - use shr_kind_mod, only: r8 => shr_kind_r8 - use shr_strdata_mod, only: shr_strdata_type, shr_strdata_get_stream_pointer - use dshr_state_mod, only: dshr_state_getfldptr - use shr_log_mod, only: shr_log_error - use dshr_utils_mod, only: ChkErr - use dshr_stream_mod, only: dshr_stream_type, shr_stream_init_from_esmfconfig + use shr_kind_mod, only: r8 => shr_kind_r8 + use shr_strdata_mod, only: shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_state_mod, only: dshr_state_getfldptr + use shr_log_mod, only: shr_log_error + use dshr_utils_mod, only: ChkErr + use dshr_stream_mod, only: dshr_stream_type, shr_stream_init_from_esmfconfig + use dshr_fldList_mod, only: dshr_fldList_type, dshr_fldList_add implicit none private - public :: DatamodeUnifiedInit - public :: DatamodeUnifiedRun - public :: unified_datamode_type + public :: datm_datamode_ufs_advertise + public :: datm_datamode_ufs_init_pointers + public :: datm_datamode_ufs_advance + public :: ufs_datamode_state - character(len=*), parameter :: u_FILE_u = 'cdeps_datamode_unified_mod.F90' + character(len=*), parameter :: u_FILE_u = 'datm_datamode_ufs_mod.F90' - !> \brief Maps configuration string to persistent memory pointers - type :: unified_var_map + !> \brief Dynamic mapping for pass-through variables + type :: ufs_var_map character(len=64) :: var_name real(r8), pointer :: ptr_strm(:) => null() real(r8), pointer :: ptr_exp(:) => null() - end type unified_var_map + end type ufs_var_map - !> \brief Master state for the unified datamode - type :: unified_datamode_type - type(unified_var_map), allocatable :: var_maps(:) - end type unified_datamode_type + !> \brief Instance-specific state object for thread-safe operations + type :: ufs_datamode_state + type(ufs_var_map), allocatable :: var_maps(:) + end type ufs_datamode_state contains !============================================================================= - ! \brief Parse ESMF config for stream variables and dynamically build map + ! \brief Reads config streams and advertises to CDEPS field list !============================================================================= - subroutine DatamodeUnifiedInit(config, unified_state, rc) - type(ESMF_Config), intent(in) :: config - type(unified_datamode_type), intent(inout) :: unified_state - integer, intent(out) :: rc + subroutine datm_datamode_ufs_advertise(fldsExport, config, ufs_state, rc) + type(dshr_fldList_type), intent(inout) :: fldsExport + type(ESMF_Config), intent(in) :: config + type(ufs_datamode_state), intent(inout) :: ufs_state + integer, intent(out) :: rc - character(len=*), parameter :: subName = 'DatamodeUnifiedInit: ' type(dshr_stream_type), allocatable :: streams(:) - integer :: i, j + integer :: istrm, ivar + + ! Dummy variables for the shr_stream_init_from_esmfconfig call + character(len=256) :: streamfilename = 'dummy_config' + integer :: logunit = 6 + integer :: pio_subsystem = 0 + integer :: io_type = 0 + integer :: io_format = 0 rc = ESMF_SUCCESS - ! Parse ESMF Config for 1-to-1 Stream Variables (Dynamically Appended) - call shr_stream_init_from_esmfconfig(streams, config, rc=rc) + ! Parse ESMF Config for 1-to-1 Stream Variables using dummy IO handles + call shr_stream_init_from_esmfconfig(streamfilename, streams, logunit, & + pio_subsystem, io_type, io_format, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (allocated(streams)) then - do i = 1, size(streams) - do j = 1, streams(i)%nvars - ! Dynamically grow the var_maps array using move_alloc - call append_var_map(unified_state%var_maps, streams(i)%fldName(j)) + do istrm = 1, size(streams) + ! Loop over stream nvars and fetch nameinmodel per CDEPS structs + do ivar = 1, streams(istrm)%nvars + call append_var_map(ufs_state%var_maps, streams(istrm)%varlist(ivar)%nameinmodel) + call dshr_fldList_add(fldsExport, trim(streams(istrm)%varlist(ivar)%nameinmodel)) end do end do deallocate(streams) end if - end subroutine DatamodeUnifiedInit + end subroutine datm_datamode_ufs_advertise !============================================================================= - ! \brief Maps raw variables, then chains calculations driven by calc_opts + ! \brief Caches pass-through pointers natively into the instance state object !============================================================================= - subroutine DatamodeUnifiedRun(sdat, exportState, unified_state, calc_opts, rc) - type(shr_strdata_type), intent(inout) :: sdat - type(ESMF_State), intent(inout) :: exportState - type(unified_datamode_type), intent(inout) :: unified_state - character(len=*), intent(in) :: calc_opts - integer, intent(out) :: rc + subroutine datm_datamode_ufs_init_pointers(sdat, exportState, ufs_state, rc) + type(shr_strdata_type), intent(inout) :: sdat + type(ESMF_State), intent(inout) :: exportState + type(ufs_datamode_state), intent(inout) :: ufs_state + integer, intent(out) :: rc - character(len=*), parameter :: subName = 'DatamodeUnifiedRun: ' + character(len=*), parameter :: subName = 'datm_datamode_ufs_init_pointers: ' integer :: i rc = ESMF_SUCCESS - ! ------------------------------------------------------------------------- - ! Phase 1: Ingestion (Stream -> Export State) - ! ------------------------------------------------------------------------- - if (allocated(unified_state%var_maps)) then - do i = 1, size(unified_state%var_maps) - - call shr_strdata_get_stream_pointer(sdat, trim(unified_state%var_maps(i)%var_name), & - unified_state%var_maps(i)%ptr_strm, requirePointer=.true., & - errmsg=trim(subName)//'ERROR: stream pointer missing for '//trim(unified_state%var_maps(i)%var_name), & - rc=rc) + ! Cache standard pass-through pointers to eliminate overhead in the run loop + if (allocated(ufs_state%var_maps)) then + do i = 1, size(ufs_state%var_maps) + call shr_strdata_get_stream_pointer(sdat, trim(ufs_state%var_maps(i)%var_name), & + ufs_state%var_maps(i)%ptr_strm, requirePointer=.true., & + errmsg=trim(subName)//'ERROR: stream pointer missing for '//trim(ufs_state%var_maps(i)%var_name), rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call dshr_state_getfldptr(exportState, trim(unified_state%var_maps(i)%var_name), & - fldptr1=unified_state%var_maps(i)%ptr_exp, rc=rc) + call dshr_state_getfldptr(exportState, trim(ufs_state%var_maps(i)%var_name), & + fldptr1=ufs_state%var_maps(i)%ptr_exp, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - - unified_state%var_maps(i)%ptr_exp(:) = unified_state%var_maps(i)%ptr_strm(:) - end do end if - ! ------------------------------------------------------------------------- - ! Phase 2: Chained Calculations Driver - ! ------------------------------------------------------------------------- - ! Only enter the driver if there are options requested to save overhead - if (len_trim(calc_opts) > 0) then - call DatamodeUnifiedCalcDriver(exportState, calc_opts, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - end if - - end subroutine DatamodeUnifiedRun + end subroutine datm_datamode_ufs_init_pointers !============================================================================= - ! \brief Subroutine to dynamically append variables (Fortran 2003 move_alloc) + ! \brief Core run loop. Performs array copies and triggers calculation driver. !============================================================================= - subroutine append_var_map(var_maps, new_var_name) - type(unified_var_map), allocatable, intent(inout) :: var_maps(:) - character(len=*), intent(in) :: new_var_name + subroutine datm_datamode_ufs_advance(exportState, ufs_state, calc_opts, rc) + type(ESMF_State), intent(inout) :: exportState + type(ufs_datamode_state), intent(inout) :: ufs_state + character(len=*), intent(in) :: calc_opts + integer, intent(out) :: rc - type(unified_var_map), allocatable :: temp_maps(:) - integer :: current_size + integer :: i + rc = ESMF_SUCCESS - if (allocated(var_maps)) then - current_size = size(var_maps) - allocate(temp_maps(current_size + 1)) - temp_maps(1:current_size) = var_maps - temp_maps(current_size + 1)%var_name = trim(new_var_name) - call move_alloc(from=temp_maps, to=var_maps) - else - allocate(var_maps(1)) - var_maps(1)%var_name = trim(new_var_name) + ! ------------------------------------------------------------------------- + ! Phase 1: Ingestion (Stream -> Export State) + ! 100% Native, 100% Thread-Safe Array Math + ! ------------------------------------------------------------------------- + if (allocated(ufs_state%var_maps)) then + do i = 1, size(ufs_state%var_maps) + if (associated(ufs_state%var_maps(i)%ptr_exp) .and. associated(ufs_state%var_maps(i)%ptr_strm)) then + ufs_state%var_maps(i)%ptr_exp(:) = ufs_state%var_maps(i)%ptr_strm(:) + end if + end do end if - end subroutine append_var_map + + ! ------------------------------------------------------------------------- + ! Phase 2: Chained Calculations Driver + ! ------------------------------------------------------------------------- + if (len_trim(calc_opts) > 0) then + call datm_datamode_ufs_calc_driver(exportState, calc_opts, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine datm_datamode_ufs_advance !============================================================================= ! \brief Driver subroutine to route execution based on calc_opts string !============================================================================= - subroutine DatamodeUnifiedCalcDriver(exportState, calc_opts, rc) + subroutine datm_datamode_ufs_calc_driver(exportState, calc_opts, rc) type(ESMF_State), intent(inout) :: exportState character(len=*), intent(in) :: calc_opts integer, intent(out) :: rc rc = ESMF_SUCCESS - ! 1. Convert cumulative precipitation (m) to rate (kg/m^2/s) if (index(calc_opts, 'convert_precip_accum_to_rate') > 0) then call calc_convert_precip_accum_to_rate(exportState, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if - ! 2. Convert cumulative radiation (J/m^2) to flux (W/m^2) if (index(calc_opts, 'convert_rad_accum_to_flux') > 0) then call calc_convert_rad_accum_to_flux(exportState, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if - ! 3. Partition net shortwave radiation into bands if (index(calc_opts, 'partition_sw_4band') > 0) then call calc_partition_sw_4band(exportState, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if - ! 4. Partition precipitation into rain and snow if (index(calc_opts, 'partition_precip_freezing') > 0) then call calc_partition_precip_freezing(exportState, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if - end subroutine DatamodeUnifiedCalcDriver + end subroutine datm_datamode_ufs_calc_driver + + + !============================================================================= + ! \brief Subroutine to dynamically append variables via Fortran 2003 move_alloc + !============================================================================= + subroutine append_var_map(maps_array, new_var_name) + type(ufs_var_map), allocatable, intent(inout) :: maps_array(:) + character(len=*), intent(in) :: new_var_name + + type(ufs_var_map), allocatable :: temp_maps(:) + integer :: current_size + + if (allocated(maps_array)) then + current_size = size(maps_array) + allocate(temp_maps(current_size + 1)) + temp_maps(1:current_size) = maps_array + temp_maps(current_size + 1)%var_name = trim(new_var_name) + call move_alloc(from=temp_maps, to=maps_array) + else + allocate(maps_array(1)) + maps_array(1)%var_name = trim(new_var_name) + end if + end subroutine append_var_map !============================================================================= @@ -194,6 +218,7 @@ end subroutine DatamodeUnifiedCalcDriver subroutine calc_convert_precip_accum_to_rate(exportState, rc) type(ESMF_State), intent(inout) :: exportState integer, intent(out) :: rc + character(len=*), parameter :: subName = 'calc_convert_precip_accum_to_rate: ' real(r8), pointer :: Faxa_prec(:) => null() @@ -202,71 +227,102 @@ subroutine calc_convert_precip_accum_to_rate(exportState, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return if (.not. associated(Faxa_prec)) then - call shr_log_error(trim(subName)//'ERROR: Faxa_prec required.', rc=rc) + call shr_log_error(trim(subName)//'ERROR: Faxa_prec required for precip calculation.', rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if - ! Convert from cumulative meters per hour to kg/m^2/s - ! (rho_water = 1000 kg/m^3, time = 3600 s) - Faxa_prec(:) = Faxa_prec(:) * (1000.0_r8 / 3600.0_r8) + if (associated(Faxa_prec)) then + Faxa_prec(:) = Faxa_prec(:) * (1000.0_r8 / 3600.0_r8) + end if end subroutine calc_convert_precip_accum_to_rate subroutine calc_convert_rad_accum_to_flux(exportState, rc) type(ESMF_State), intent(inout) :: exportState integer, intent(out) :: rc + character(len=*), parameter :: subName = 'calc_convert_rad_accum_to_flux: ' real(r8), pointer :: Faxa_swdn(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() rc = ESMF_SUCCESS call dshr_state_getfldptr(exportState, 'Faxa_swdn', fldptr1=Faxa_swdn, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn', fldptr1=Faxa_lwdn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (associated(Faxa_swdn)) then - Faxa_swdn(:) = Faxa_swdn(:) / 3600.0_r8 - end if + ! Apply conversion safely to whatever radiation variables the user provided + if (associated(Faxa_swdn)) Faxa_swdn(:) = Faxa_swdn(:) / 3600.0_r8 + if (associated(Faxa_lwdn)) Faxa_lwdn(:) = Faxa_lwdn(:) / 3600.0_r8 end subroutine calc_convert_rad_accum_to_flux subroutine calc_partition_sw_4band(exportState, rc) type(ESMF_State), intent(inout) :: exportState integer, intent(out) :: rc - character(len=*), parameter :: subName = 'calc_partition_sw_4band: ' - real(r8), pointer :: Faxa_swdn(:) => null() - real(r8), pointer :: Faxa_swvdr(:) => null() - real(r8), pointer :: Faxa_swvdf(:) => null() + character(len=*), parameter :: subName = 'calc_partition_sw_4band: ' + real(r8), pointer :: Faxa_swdn(:) => null() real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() rc = ESMF_SUCCESS - ! (Fetch pointers and validate them here...) + + call dshr_state_getfldptr(exportState, 'Faxa_swdn', fldptr1=Faxa_swdn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr', fldptr1=Faxa_swndr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr', fldptr1=Faxa_swvdr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf', fldptr1=Faxa_swndf, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf', fldptr1=Faxa_swvdf, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (.not. associated(Faxa_swdn)) then + call shr_log_error(trim(subName)//'ERROR: Faxa_swdn required as input for sw partitioning.', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! Only write to the output fields that the user explicitly allocated/advertised + if (associated(Faxa_swdn)) then + if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swdn(:) * 0.25_r8 + if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swdn(:) * 0.25_r8 + if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swdn(:) * 0.25_r8 + if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swdn(:) * 0.25_r8 + end if end subroutine calc_partition_sw_4band subroutine calc_partition_precip_freezing(exportState, rc) type(ESMF_State), intent(inout) :: exportState integer, intent(out) :: rc - character(len=*), parameter :: subName = 'calc_partition_precip_freezing: ' + character(len=*), parameter :: subName = 'calc_partition_precip_freezing: ' real(r8), pointer :: Faxa_prec(:) => null() real(r8), pointer :: Faxa_prrn(:) => null() real(r8), pointer :: Faxa_prsn(:) => null() rc = ESMF_SUCCESS + call dshr_state_getfldptr(exportState, 'Faxa_prec', fldptr1=Faxa_prec, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (.not. associated(Faxa_prec)) then - call shr_log_error(trim(subName)//'ERROR: Faxa_prec required.', rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - end if - call dshr_state_getfldptr(exportState, 'Faxa_prrn', fldptr1=Faxa_prrn, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, 'Faxa_prsn', fldptr1=Faxa_prsn, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - ! Check associations and partition... + if (.not. associated(Faxa_prec)) then + call shr_log_error(trim(subName)//'ERROR: Faxa_prec required as input for precip partitioning.', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (associated(Faxa_prec)) then + if (associated(Faxa_prrn)) Faxa_prrn(:) = Faxa_prec(:) * 0.5_r8 + if (associated(Faxa_prsn)) Faxa_prsn(:) = Faxa_prec(:) * 0.5_r8 + end if end subroutine calc_partition_precip_freezing end module datm_datamode_ufs_mod From 57e7cfa9efe4625d3026036a79c9d48f42ccaaef Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Fri, 25 Sep 2026 01:15:44 -0400 Subject: [PATCH 19/28] Use __FILE_ --- datm/datm_datamode_ufs_mod.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index 9011bad7d..7c8767003 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -33,7 +33,7 @@ module datm_datamode_ufs_mod public :: datm_datamode_ufs_advance public :: ufs_datamode_state - character(len=*), parameter :: u_FILE_u = 'datm_datamode_ufs_mod.F90' + character(len=*), parameter :: u_FILE_u = __FILE__ !> \brief Dynamic mapping for pass-through variables type :: ufs_var_map From b33838435939a657937f3e9763db3d3f15f24b40 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Fri, 25 Sep 2026 13:24:58 -0400 Subject: [PATCH 20/28] add datamode to datm/atm_comp_nuopc.F90 --- datm/atm_comp_nuopc.F90 | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 6f1ca2358..7837c886d 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -63,6 +63,11 @@ module cdeps_datm_comp use datm_datamode_gefs_mod , only : datm_datamode_gefs_init_pointers use datm_datamode_gefs_mod , only : datm_datamode_gefs_advance + use datm_datamode_ufs_mod , only : datm_datamode_ufs_advertise + use datm_datamode_ufs_mod , only : datm_datamode_ufs_init_pointers + use datm_datamode_ufs_mod , only : datm_datamode_ufs_advance + use datm_datamode_ufs_mod , only : ufs_datamode_state + use datm_datamode_simple_mod , only : datm_datamode_simple_advertise use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers use datm_datamode_simple_mod , only : datm_datamode_simple_advance @@ -141,6 +146,8 @@ module cdeps_datm_comp logical :: skip_restart_read = .false. ! true => skip restart read in continuation run logical :: export_all = .false. ! true => export all fields, do not check connected or not logical :: first_call = .true. + + character(CX) :: calc_opts = nullstr ! model restart file namelist ! linked lists type(fldList_type) , pointer :: fldsImport => null() @@ -249,7 +256,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) skip_restart_read, & flds_presndep, & flds_preso3, & - export_all + export_all, & + calc_opts rc = ESMF_SUCCESS @@ -305,6 +313,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,'(2a,l6)') subname,' flds_co2 = ',flds_co2 write(logunit,'(2a,l6)') subname,' skip_restart_read = ',skip_restart_read write(logunit,'(2a,l6)') subname,' export_all = ',export_all + write(logunit,'(2a,l6)') subname,' calc_opts = ',trim(calc_opts) bcasttmp = 0 bcasttmp(1) = nx_global @@ -341,6 +350,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, bcasttmp, 10, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, calc_opts, CX, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return nx_global = bcasttmp(1) ny_global = bcasttmp(2) @@ -366,7 +377,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) select case (trim(datamode)) case ('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA', 'JRA55do', & 'CORE_RYF6162_JRA','CORE_RYF8485_JRA','CORE_RYF9091_JRA','CORE_RYF0304_JRA', & - 'CLMNCEP','CPLHIST','GEFS','ERA5','SIMPLE') + 'CLMNCEP','CPLHIST','GEFS','UFS','ERA5','SIMPLE') if (mainproc) write(logunit,'(3a)') subname,'datm datamode = ',trim(datamode) case default call shr_log_error(' ERROR illegal datm datamode = '//trim(datamode), rc=rc) @@ -407,6 +418,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) case ('GEFS') call datm_datamode_gefs_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('UFS') + call datm_datamode_ufs_advertise(fldsExport, config, ufs_state, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('SIMPLE') call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & nlfilename, my_task, vm, rc) @@ -674,6 +688,9 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('GEFS') call datm_datamode_gefs_init_pointers(exportState, sdat, logunit, mainproc, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('UFS') + call datm_datamode_ufs_init_pointers(sdat, exportState, ufs_state, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return case('SIMPLE') call datm_datamode_simple_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -687,7 +704,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA',& 'CORE_RYF6162_JRA','CORE_RYF8485_JRA' ,& 'CORE_RYF9091_JRA','CORE_RYF0304_JRA' , 'JRA55do', & - 'CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + 'CLMNCEP','CPLHIST','ERA5','GEFS','UFS','SIMPLE') call dshr_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case default @@ -752,6 +769,9 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('GEFS') call datm_datamode_gefs_advance(exportstate, sdat, mainproc, logunit, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('UFS') + call datm_datamode_ufs_advance(exportState, ufs_state, calc_opts, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return case('SIMPLE') call datm_datamode_simple_advance(target_ymd, target_tod, target_mon, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -765,7 +785,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA',& 'CORE_RYF6162_JRA','CORE_RYF8485_JRA' ,& 'CORE_RYF9091_JRA','CORE_RYF0304_JRA','JRA55do' ,& - 'CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + 'CLMNCEP','CPLHIST','ERA5','GEFS','UFS','SIMPLE') call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, & target_ymd, target_tod, logunit, my_task, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return From ac0999eebd626e25b6fe104ba70611cc5d78e0e5 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Fri, 25 Sep 2026 13:46:20 -0400 Subject: [PATCH 21/28] Better datm_datamode_ufs_advertise --- datm/datm_datamode_ufs_mod.F90 | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index 7c8767003..e98d8c2a1 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -52,17 +52,18 @@ module datm_datamode_ufs_mod !============================================================================= ! \brief Reads config streams and advertises to CDEPS field list !============================================================================= - subroutine datm_datamode_ufs_advertise(fldsExport, config, ufs_state, rc) + subroutine datm_datamode_ufs_advertise(fldsExport, ufs_state, rc) type(dshr_fldList_type), intent(inout) :: fldsExport - type(ESMF_Config), intent(in) :: config type(ufs_datamode_state), intent(inout) :: ufs_state integer, intent(out) :: rc type(dshr_stream_type), allocatable :: streams(:) integer :: istrm, ivar - ! Dummy variables for the shr_stream_init_from_esmfconfig call - character(len=256) :: streamfilename = 'dummy_config' + character(len=18) :: streamfilename = 'datm.streams' + + ! Dummy IO variables for parsing stage. + ! The actual IO handles will be set up by sdat during Realize. integer :: logunit = 6 integer :: pio_subsystem = 0 integer :: io_type = 0 @@ -70,7 +71,7 @@ subroutine datm_datamode_ufs_advertise(fldsExport, config, ufs_state, rc) rc = ESMF_SUCCESS - ! Parse ESMF Config for 1-to-1 Stream Variables using dummy IO handles + ! Parse stream file for 1-to-1 variables using dummy IO handles call shr_stream_init_from_esmfconfig(streamfilename, streams, logunit, & pio_subsystem, io_type, io_format, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -92,9 +93,9 @@ end subroutine datm_datamode_ufs_advertise !============================================================================= ! \brief Caches pass-through pointers natively into the instance state object !============================================================================= - subroutine datm_datamode_ufs_init_pointers(sdat, exportState, ufs_state, rc) - type(shr_strdata_type), intent(inout) :: sdat + subroutine datm_datamode_ufs_init_pointers(exportState, sdat, ufs_state, rc) type(ESMF_State), intent(inout) :: exportState + type(shr_strdata_type), intent(inout) :: sdat type(ufs_datamode_state), intent(inout) :: ufs_state integer, intent(out) :: rc From 79a36735f143453a5acdd6155988bff4720b77a8 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Fri, 25 Sep 2026 13:47:54 -0400 Subject: [PATCH 22/28] Update datamode_ufs APIs in datm/atm_comp_nuopc.F90 --- datm/atm_comp_nuopc.F90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 7837c886d..8ed3039e5 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -419,7 +419,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call datm_datamode_gefs_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('UFS') - call datm_datamode_ufs_advertise(fldsExport, config, ufs_state, rc) + call datm_datamode_ufs_advertise(fldsExport, ufs_state, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('SIMPLE') call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & @@ -689,7 +689,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod call datm_datamode_gefs_init_pointers(exportState, sdat, logunit, mainproc, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case('UFS') - call datm_datamode_ufs_init_pointers(sdat, exportState, ufs_state, rc) + call datm_datamode_ufs_init_pointers(exportState, sdat, ufs_state, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case('SIMPLE') call datm_datamode_simple_init_pointers(exportState, sdat, rc) From b94bb36b2b612f77965e68573da00277829a91e1 Mon Sep 17 00:00:00 2001 From: Nick Szapiro Date: Fri, 25 Sep 2026 21:54:50 +0000 Subject: [PATCH 23/28] Compiles --- datm/atm_comp_nuopc.F90 | 3 ++- datm/datm_datamode_ufs_mod.F90 | 35 +++++++++++++++++----------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 8ed3039e5..ccac04e13 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -120,6 +120,7 @@ module cdeps_datm_comp logical :: restart_read ! start from restart character(CL) :: case_name ! case name character(len=*) , parameter :: nullstr = 'null' + type(ufs_datamode_state) :: ufs_state ! datm_in namelist input character(CX) :: nlfilename = nullstr ! filename to obtain namelist info from @@ -147,7 +148,7 @@ module cdeps_datm_comp logical :: export_all = .false. ! true => export all fields, do not check connected or not logical :: first_call = .true. - character(CX) :: calc_opts = nullstr ! model restart file namelist + character(CX) :: calc_opts = nullstr ! derived variable calculation options ! linked lists type(fldList_type) , pointer :: fldsImport => null() diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index e98d8c2a1..b19bd01b7 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -18,12 +18,11 @@ module datm_datamode_ufs_mod ! CDEPS-native imports use shr_kind_mod, only: r8 => shr_kind_r8 - use shr_strdata_mod, only: shr_strdata_type, shr_strdata_get_stream_pointer - use dshr_state_mod, only: dshr_state_getfldptr + use dshr_strdata_mod, only: shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_methods_mod, only: dshr_state_getfldptr, chkerr use shr_log_mod, only: shr_log_error - use dshr_utils_mod, only: ChkErr - use dshr_stream_mod, only: dshr_stream_type, shr_stream_init_from_esmfconfig - use dshr_fldList_mod, only: dshr_fldList_type, dshr_fldList_add + use dshr_stream_mod, only: shr_stream_streamType, shr_stream_init_from_esmfconfig + use dshr_fldList_mod, only: fldList_type, dshr_fldList_add implicit none private @@ -53,11 +52,13 @@ module datm_datamode_ufs_mod ! \brief Reads config streams and advertises to CDEPS field list !============================================================================= subroutine datm_datamode_ufs_advertise(fldsExport, ufs_state, rc) - type(dshr_fldList_type), intent(inout) :: fldsExport + use pio, only : iosystem_desc_t + + type(fldList_type), pointer :: fldsExport type(ufs_datamode_state), intent(inout) :: ufs_state integer, intent(out) :: rc - type(dshr_stream_type), allocatable :: streams(:) + type(shr_stream_streamType), pointer :: streamdat(:) integer :: istrm, ivar character(len=18) :: streamfilename = 'datm.streams' @@ -65,27 +66,25 @@ subroutine datm_datamode_ufs_advertise(fldsExport, ufs_state, rc) ! Dummy IO variables for parsing stage. ! The actual IO handles will be set up by sdat during Realize. integer :: logunit = 6 - integer :: pio_subsystem = 0 + type(iosystem_desc_t), pointer :: pio_subsystem integer :: io_type = 0 integer :: io_format = 0 rc = ESMF_SUCCESS ! Parse stream file for 1-to-1 variables using dummy IO handles - call shr_stream_init_from_esmfconfig(streamfilename, streams, logunit, & + call shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, & pio_subsystem, io_type, io_format, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - if (allocated(streams)) then - do istrm = 1, size(streams) - ! Loop over stream nvars and fetch nameinmodel per CDEPS structs - do ivar = 1, streams(istrm)%nvars - call append_var_map(ufs_state%var_maps, streams(istrm)%varlist(ivar)%nameinmodel) - call dshr_fldList_add(fldsExport, trim(streams(istrm)%varlist(ivar)%nameinmodel)) - end do + do istrm = 1, size(streamdat) + ! Loop over stream nvars and fetch nameinmodel per CDEPS structs + do ivar = 1, streamdat(istrm)%nvars + call append_var_map(ufs_state%var_maps, streamdat(istrm)%varlist(ivar)%nameinmodel) + call dshr_fldList_add(fldsExport, trim(streamdat(istrm)%varlist(ivar)%nameinmodel)) end do - deallocate(streams) - end if + end do + ! deallocate(streamdat) end subroutine datm_datamode_ufs_advertise From 41fbe246690a56b3a433f9cad88945471b7b4461 Mon Sep 17 00:00:00 2001 From: Nick Szapiro Date: Fri, 25 Sep 2026 22:25:27 +0000 Subject: [PATCH 24/28] Fix write format --- datm/atm_comp_nuopc.F90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index ccac04e13..076df2f9c 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -314,7 +314,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,'(2a,l6)') subname,' flds_co2 = ',flds_co2 write(logunit,'(2a,l6)') subname,' skip_restart_read = ',skip_restart_read write(logunit,'(2a,l6)') subname,' export_all = ',export_all - write(logunit,'(2a,l6)') subname,' calc_opts = ',trim(calc_opts) + write(logunit,'(3a)') subname,' calc_opts = ',trim(calc_opts) bcasttmp = 0 bcasttmp(1) = nx_global From 999400e546a4b047e2078b6a4df9bbf25fe21517 Mon Sep 17 00:00:00 2001 From: Nick Szapiro Date: Sun, 27 Sep 2026 23:35:54 +0000 Subject: [PATCH 25/28] Getting stream_variables via shr_stream_init_from_esmfconfig is messy and not necessary. TODO: parse datm.streams in ufs datamode to add_stream_variables_to_export --- datm/atm_comp_nuopc.F90 | 2 +- datm/datm_datamode_ufs_mod.F90 | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 076df2f9c..793483474 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -420,7 +420,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call datm_datamode_gefs_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('UFS') - call datm_datamode_ufs_advertise(fldsExport, ufs_state, rc) + call datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('SIMPLE') call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index b19bd01b7..3ccdb2cd4 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -51,32 +51,26 @@ module datm_datamode_ufs_mod !============================================================================= ! \brief Reads config streams and advertises to CDEPS field list !============================================================================= - subroutine datm_datamode_ufs_advertise(fldsExport, ufs_state, rc) - use pio, only : iosystem_desc_t + subroutine datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_scalar_name, rc) + type(esmf_State) , intent(inout) :: exportState type(fldList_type), pointer :: fldsExport type(ufs_datamode_state), intent(inout) :: ufs_state + character(len=*) , intent(in) :: flds_scalar_name integer, intent(out) :: rc type(shr_stream_streamType), pointer :: streamdat(:) integer :: istrm, ivar character(len=18) :: streamfilename = 'datm.streams' + type(fldlist_type), pointer :: fldList - ! Dummy IO variables for parsing stage. - ! The actual IO handles will be set up by sdat during Realize. - integer :: logunit = 6 - type(iosystem_desc_t), pointer :: pio_subsystem - integer :: io_type = 0 - integer :: io_format = 0 - rc = ESMF_SUCCESS - ! Parse stream file for 1-to-1 variables using dummy IO handles - call shr_stream_init_from_esmfconfig(streamfilename, streamdat, logunit, & - pio_subsystem, io_type, io_format, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! TODO - parse datm.streams stream_variables to fldsExport + Error + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) do istrm = 1, size(streamdat) ! Loop over stream nvars and fetch nameinmodel per CDEPS structs do ivar = 1, streamdat(istrm)%nvars @@ -86,6 +80,14 @@ subroutine datm_datamode_ufs_advertise(fldsExport, ufs_state, rc) end do ! deallocate(streamdat) + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + end subroutine datm_datamode_ufs_advertise @@ -112,7 +114,7 @@ subroutine datm_datamode_ufs_init_pointers(exportState, sdat, ufs_state, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call dshr_state_getfldptr(exportState, trim(ufs_state%var_maps(i)%var_name), & - fldptr1=ufs_state%var_maps(i)%ptr_exp, rc=rc) + fldptr1=ufs_state%var_maps(i)%ptr_exp, allowNullReturn=.true., rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end do end if From e3beee49afee07a67ee6bbf03846e7e62c245581 Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Sun, 27 Sep 2026 19:55:04 -0400 Subject: [PATCH 26/28] TODO: finish add_stream_variables_to_export Added a new subroutine to handle stream variables export. --- datm/datm_datamode_ufs_mod.F90 | 80 +++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 11 deletions(-) diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index 3ccdb2cd4..fb8aa57de 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -48,6 +48,73 @@ module datm_datamode_ufs_mod contains + subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) + character(len=*), intent(in) :: streamfilename + type(dshr_fldList_type), intent(inout) :: fldsExport + type(ufs_datamode_state), intent(inout) :: ufs_state + integer, intent(out) :: rc + + rc = ESMF_SUCCESS + + ! allocate streamdat instance on all tasks + nstrms = 0 + + ! set ESMF config + cf = ESMF_ConfigCreate(rc=RC) + call ESMF_ConfigLoadFile(config=CF ,filename=trim(streamfilename), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get number of streams + nstrms = ESMF_ConfigGetLen(config=CF, label='stream_info:', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! allocate an array of shr_stream_streamtype objects + if (nstrms > 0) then + allocate(streamdat(nstrms), stat=istat) + if ( istat /= 0 ) then + call shr_log_error(subName//': allocation error for streamdat with size '//toString(nstrms),rc=rc) + return + end if + else + call shr_log_error("no stream_info in config file "//trim(streamfilename), rc=rc) + return + endif + + do i=1, nstrms + ! Get name of stream variables in file and model + streamdat(i)%nvars = ESMF_ConfigGetLen(config=CF, label="stream_data_variables"//mystrm//':', rc=rc) + if( streamdat(i)%nvars > 0) then + allocate(streamdat(i)%varlist(streamdat(i)%nvars), stat=istat) + if ( istat /= 0 ) then + call shr_log_error(subName//& + ': allocation error for streamdat('//toString(i)//')%varlist'//& + ' with size '//toString(streamdat(i)%nvars), rc=rc) + return + end if + allocate(strm_tmpstrings(streamdat(i)%nvars), stat=istat) + if ( istat /= 0 ) then + call shr_log_error(subName//& + ': allocation error for strm_tmpstrings('//toString(i)//')%varlist'//& + ' with size '//toString(streamdat(i)%nvars), rc=rc) + return + end if + call ESMF_ConfigGetAttribute(CF,valueList=strm_tmpstrings,label="stream_data_variables"//mystrm//':', rc=rc) + do n=1, streamdat(i)%nvars + streamdat(i)%varlist(n)%nameinfile = strm_tmpstrings(n)(1:index(trim(strm_tmpstrings(n)), " ")) + streamdat(i)%varlist(n)%nameinmodel = strm_tmpstrings(n)(index(trim(strm_tmpstrings(n)), " ", .true.)+1:) + + call append_var_map(ufs_state%var_maps, trim(streamdat(i)%varlist(n)%nameinmodel)) + call dshr_fldList_add(fldsExport, trim(streamdat(i)%varlist(n)%nameinmodel)) + enddo + deallocate(strm_tmpstrings) + else + call shr_log_error("stream data variables must be provided", rc=rc) + return + endif + end do ! i nstrms + + end subroutine add_stream_variables_to_export + !============================================================================= ! \brief Reads config streams and advertises to CDEPS field list !============================================================================= @@ -67,17 +134,8 @@ subroutine datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_ rc = ESMF_SUCCESS - ! TODO - parse datm.streams stream_variables to fldsExport - Error - - call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) - do istrm = 1, size(streamdat) - ! Loop over stream nvars and fetch nameinmodel per CDEPS structs - do ivar = 1, streamdat(istrm)%nvars - call append_var_map(ufs_state%var_maps, streamdat(istrm)%varlist(ivar)%nameinmodel) - call dshr_fldList_add(fldsExport, trim(streamdat(istrm)%varlist(ivar)%nameinmodel)) - end do - end do + ! parse datm.streams stream_variables to fldsExport and ufs_state + call add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) ! deallocate(streamdat) fldlist => fldsExport ! the head of the linked list From aed24835fcb46786fdacfaf6e74c4c24f9481b4f Mon Sep 17 00:00:00 2001 From: Nicholas Szapiro <149816583+NickSzapiro-NOAA@users.noreply.github.com> Date: Sun, 27 Sep 2026 20:57:50 -0400 Subject: [PATCH 27/28] filled in add_stream_variables_to_export in datm/datm_datamode_ufs_mod.F90 --- datm/datm_datamode_ufs_mod.F90 | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index fb8aa57de..aa687bee7 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -21,7 +21,7 @@ module datm_datamode_ufs_mod use dshr_strdata_mod, only: shr_strdata_type, shr_strdata_get_stream_pointer use dshr_methods_mod, only: dshr_state_getfldptr, chkerr use shr_log_mod, only: shr_log_error - use dshr_stream_mod, only: shr_stream_streamType, shr_stream_init_from_esmfconfig + use dshr_stream_mod, only: shr_stream_streamType use dshr_fldList_mod, only: fldList_type, dshr_fldList_add implicit none @@ -49,11 +49,25 @@ module datm_datamode_ufs_mod contains subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) + character(len=*), intent(in) :: streamfilename type(dshr_fldList_type), intent(inout) :: fldsExport type(ufs_datamode_state), intent(inout) :: ufs_state integer, intent(out) :: rc + ! local variables + type(ESMF_VM) :: vm + type(ESMF_Config) :: cf + integer :: i, n, nstrms + integer :: myid + character(2) :: mystrm + integer :: istat + character(len=ESMF_MAXSTR), allocatable :: strm_tmpstrings(:) + type(shr_stream_streamType), pointer :: streamdat(:) + + character(len=*), parameter :: u_FILE_u = __FILE__ + character(len=*), parameter :: subName = '(add_stream_variables_to_export)' + rc = ESMF_SUCCESS ! allocate streamdat instance on all tasks @@ -113,6 +127,14 @@ subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, endif end do ! i nstrms + ! Clean up local memory + if (allocated(streamdat)) then + do i=1, nstrms + if (allocated(streamdat(i)%varlist)) deallocate(streamdat(i)%varlist) + end do + deallocate(streamdat) + end if + end subroutine add_stream_variables_to_export !============================================================================= @@ -126,9 +148,6 @@ subroutine datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_ character(len=*) , intent(in) :: flds_scalar_name integer, intent(out) :: rc - type(shr_stream_streamType), pointer :: streamdat(:) - integer :: istrm, ivar - character(len=18) :: streamfilename = 'datm.streams' type(fldlist_type), pointer :: fldList @@ -136,7 +155,6 @@ subroutine datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_ ! parse datm.streams stream_variables to fldsExport and ufs_state call add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) - ! deallocate(streamdat) fldlist => fldsExport ! the head of the linked list do while (associated(fldlist)) From 9597a944a0633eb9244d9f42bab026c3147f245a Mon Sep 17 00:00:00 2001 From: Nick Szapiro Date: Mon, 28 Sep 2026 02:46:35 +0000 Subject: [PATCH 28/28] Runs on Ursa --- datm/datm_datamode_gefs_mod.F90 | 13 +------------ datm/datm_datamode_ufs_mod.F90 | 12 +++++++++--- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/datm/datm_datamode_gefs_mod.F90 b/datm/datm_datamode_gefs_mod.F90 index 157cb5c94..82a1cfab0 100644 --- a/datm/datm_datamode_gefs_mod.F90 +++ b/datm/datm_datamode_gefs_mod.F90 @@ -39,7 +39,6 @@ module datm_datamode_gefs_mod real(r8), pointer :: Faxa_swvdf(:) => null() ! stream data - real(r8), pointer :: strm_Sa_mask(:) => null() real(r8), pointer :: strm_Sa_z(:) => null() real(r8), pointer :: strm_Sa_u(:) => null() real(r8), pointer :: strm_Sa_v(:) => null() @@ -135,9 +134,6 @@ subroutine datm_datamode_gefs_init_pointers(exportState, sdat, logunit, mainproc rc = ESMF_SUCCESS ! initialize pointers for module level stream arrays - call shr_strdata_get_stream_pointer( sdat, 'Sa_mask', strm_Sa_mask , requirePointer=.true., & - errmsg=subname//'ERROR: strm_Sa_mask must be associated for gefs datamode', rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return call shr_strdata_get_stream_pointer( sdat, 'Sa_z', strm_Sa_z , requirePointer=.true., & errmsg=subname//'ERROR: strm_Sa_z must be associated for gefs datamode', rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -256,7 +252,7 @@ subroutine datm_datamode_gefs_advance(exportstate, sdat, mainproc, logunit, rc) rc = ESMF_SUCCESS - lsize = size(strm_Sa_mask) + lsize = size(strm_Sa_tbot) if (first_time) then call ESMF_VMGetCurrent(vm, rc=rc) @@ -270,13 +266,6 @@ subroutine datm_datamode_gefs_advance(exportstate, sdat, mainproc, logunit, rc) if (mainproc) write(logunit,*) subname,' tbotmax = ',tbotmax - ! determine maskmax (see below for use) - rtmp(1) = maxval(strm_Sa_mask(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - maskmax = rtmp(2) - if (mainproc) write(logunit,*) subname,' maskmax = ',maskmax - ! reset first_time first_time = .false. end if diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 index aa687bee7..b350cc3eb 100644 --- a/datm/datm_datamode_ufs_mod.F90 +++ b/datm/datm_datamode_ufs_mod.F90 @@ -50,8 +50,10 @@ module datm_datamode_ufs_mod subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) + use shr_strconvert_mod, only : toString + character(len=*), intent(in) :: streamfilename - type(dshr_fldList_type), intent(inout) :: fldsExport + type(fldList_type), pointer :: fldsExport type(ufs_datamode_state), intent(inout) :: ufs_state integer, intent(out) :: rc @@ -62,8 +64,8 @@ subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, integer :: myid character(2) :: mystrm integer :: istat - character(len=ESMF_MAXSTR), allocatable :: strm_tmpstrings(:) - type(shr_stream_streamType), pointer :: streamdat(:) + character(len=ESMF_MAXSTR), allocatable :: strm_tmpstrings(:) + type(shr_stream_streamType), allocatable :: streamdat(:) character(len=*), parameter :: u_FILE_u = __FILE__ character(len=*), parameter :: subName = '(add_stream_variables_to_export)' @@ -96,6 +98,7 @@ subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, do i=1, nstrms ! Get name of stream variables in file and model + write(mystrm,"(I2.2)") i streamdat(i)%nvars = ESMF_ConfigGetLen(config=CF, label="stream_data_variables"//mystrm//':', rc=rc) if( streamdat(i)%nvars > 0) then allocate(streamdat(i)%varlist(streamdat(i)%nvars), stat=istat) @@ -134,6 +137,8 @@ subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, end do deallocate(streamdat) end if + call ESMF_ConfigDestroy(config=CF, rc=RC) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end subroutine add_stream_variables_to_export @@ -155,6 +160,7 @@ subroutine datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_ ! parse datm.streams stream_variables to fldsExport and ufs_state call add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) fldlist => fldsExport ! the head of the linked list do while (associated(fldlist))