diff --git a/.github/workflows/extbuild.yml b/.github/workflows/extbuild.yml index 185f6d85d..44a0a2972 100644 --- a/.github/workflows/extbuild.yml +++ b/.github/workflows/extbuild.yml @@ -19,8 +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.6.1 - ParallelIO_VERSION: pio2_6_2 + ESMF_VERSION: v8.9.0 + ParallelIO_VERSION: pio2_6_6 steps: - id: checkout-CDEPS uses: actions/checkout@v4 @@ -39,8 +39,8 @@ jobs: id: cache-PARALLELIO uses: actions/cache@v4 with: - path: ${GITHUB_WORKSPACE}/pio - key: ${{ runner.os }}-${{ env.ParallelIO_VERSION }}-parallelio2 + path: /home/runner/work/CDEPS/CDEPS/pio + key: ${{ runner.os }}-${{ env.ParallelIO_VERSION }}-parallelio - name: Build ParallelIO if: steps.cache-PARALLELIO.outputs.cache-hit != 'true' uses: NCAR/ParallelIO/.github/actions/parallelio_cmake@9390e30e29d4ebbfbef0fc72162cacd9e8f25e4e @@ -49,7 +49,7 @@ jobs: enable_fortran: True install_prefix: ${GITHUB_WORKSPACE}/pio - name: Install ESMF - uses: esmf-org/install-esmf-action@v1 + uses: esmf-org/install-esmf-action@v1.0.2 env: ESMF_COMPILER: gfortran ESMF_BOPT: g diff --git a/cime_config/stream_cdeps.py b/cime_config/stream_cdeps.py index e9e956d6d..17fbf6c1d 100644 --- a/cime_config/stream_cdeps.py +++ b/cime_config/stream_cdeps.py @@ -76,7 +76,8 @@ def create_stream_xml( data_list_file, user_mods_file, available_neon_data=None, - available_plumber_data=None + available_plumber_data=None, + lnd2rof_nonh2o_number=0, ): """ Create the stream xml file and append the required stream input data to the input data list file @@ -230,6 +231,7 @@ def create_stream_xml( datavars = child.xml_element.text.strip() datavars = self._resolve_values(case, datavars) datavars = self._sub_glc_fields(datavars, case) + datavars = self._sub_rof_fields(datavars, case, lnd2rof_nonh2o_number=lnd2rof_nonh2o_number) datavars = self._add_xml_delimiter(datavars.split("\n"), "var") if stream_vars[node_name]: stream_vars[node_name] = ( @@ -520,11 +522,11 @@ def _sub_glc_fields(self, datavars, case): Returns a string. - Example: If `_sub_fields` is called with an array containing two + Example: If `_sub_glc_fields` is called with an array containing two elements, each of which contains two strings, and glc_nec=3: foo bar s2x_Ss_tsrf%glc tsrf%glc - then the returned array will be: + then the returned array will be: foo bar s2x_Ss_tsrf00 tsrf00 s2x_Ss_tsrf01 tsrf01 @@ -547,6 +549,56 @@ def _sub_glc_fields(self, datavars, case): new_lines.append(line) return "\n".join(new_lines) + def _sub_rof_fields(self, datavars, case, lnd2rof_nonh2o_number=0): + """Substitute indicators with given values in a list of fields. + Replace any instance of the following substring indicators with the + appropriate values: + %lnd2rof_nonh2o_number = two-digit number from 0 through the number + of non-h2o tracers sent from the dlnd to mosart. + + The difference between this function and `_sub_paths` is that this + function is intended to be used for variable names (especially from the + `strm_datvar` defaults), whereas `_sub_paths` is intended for use on + input data file paths. + + Returns a string. + + Example: If `_sub_rof_fields` is called with an array containing only one + element, and lnd2rof_nonh2o_number = 2 + foo bar + lndImp_Flrl_rofsur_nonh2o%rof Flrl_rofsur_nonh2o%rof + then the returned array will be: + foo bar + lndImp_Flrl_rofsur_nonh2o Flrl_rofsur_nonh2o + + Example: If `_sub_rof_fields` is called with an array containing two + elements, each of which contains two strings, and lnd2rof_nonh2o_number = 2 + foo bar + lndImp_Flrl_rofsur_nonh2o%rof Flrl_rofsur_nonh2o%rof + then the returned array will be: + foo bar + lndImp_Flrl_rofsur_nonh2o%01 Flrl_rofsur_nonh2o%01 + lndImp_Flrl_rofsur_nonh2o%02 Flrl_rofsur_nonh2o%02 + """ + lines = datavars.split("\n") + new_lines = [] + for line in lines: + if not line: + continue + if "%rof" in line: + if lnd2rof_nonh2o_number == 0: + lnd2rof_indices = [] + else: + lnd2rof_indices = range(1,lnd2rof_nonh2o_number + 1) + for i in lnd2rof_indices: + if len(lnd2rof_indices) == 1: + new_lines.append(line.replace("%rof", "".format(i))) + else: + new_lines.append(line.replace("%rof", "{:02d}".format(i))) + else: + new_lines.append(line) + return "\n".join(new_lines) + @staticmethod def _days_in_month(month, year=1): """Number of days in the given month (specified as an int, 1-12). @@ -664,8 +716,11 @@ def _sub_paths( 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) + new_file = line.replace(match.group(0), date_string) + if os.path.exists(new_file): + new_lines.append(new_file) + else: + print(f" WARNING:not adding missing file {new_file}") elif match.group("month"): for month in range(1, 13): date_string = (year_format + "-{:02d}").format(year, month) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index 8e19799c2..ff96448fb 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -356,6 +356,10 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if ( trim(datamode) == 'CORE2_NYF' .or. & trim(datamode) == 'CORE2_IAF' .or. & trim(datamode) == 'CORE_IAF_JRA' .or. & + trim(datamode) == 'CORE_RYF6162_JRA' .or. & + trim(datamode) == 'CORE_RYF8485_JRA' .or. & + trim(datamode) == 'CORE_RYF9091_JRA' .or. & + trim(datamode) == 'CORE_RYF0304_JRA' .or. & trim(datamode) == 'CLMNCEP' .or. & trim(datamode) == 'CPLHIST' .or. & trim(datamode) == 'GEFS' .or. & @@ -372,7 +376,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) call datm_datamode_core2_advertise(exportState, fldsExport, flds_scalar_name, & flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case ('CORE_IAF_JRA') + case ('CORE_IAF_JRA', 'CORE_RYF6162_JRA', 'CORE_RYF8485_JRA', 'CORE_RYF9091_JRA', 'CORE_RYF0304_JRA') call datm_datamode_jra_advertise(exportState, fldsExport, flds_scalar_name, & flds_co2, flds_wiso, flds_presaero, flds_presndep, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -621,7 +625,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('CORE2_NYF','CORE2_IAF') call datm_datamode_core2_init_pointers(exportState, sdat, datamode, factorfn_mesh, factorfn_data, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('CORE_IAF_JRA') + case ('CORE_IAF_JRA', 'CORE_RYF6162_JRA', 'CORE_RYF8485_JRA', 'CORE_RYF9091_JRA', 'CORE_RYF0304_JRA') call datm_datamode_jra_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case('CLMNCEP') @@ -646,7 +650,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod call shr_get_rpointer_name(gcomp, 'atm', target_ymd, target_tod, rpfile, 'read', rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return select case (trim(datamode)) - case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA','CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA','CORE_RYF6162_JRA','CORE_RYF8485_JRA','CORE_RYF9091_JRA','CORE_RYF0304_JRA','CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') call dshr_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case default @@ -686,7 +690,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod call datm_datamode_core2_advance(datamode, target_ymd, target_tod, target_mon, & sdat%model_calendar, factorfn_mesh, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('CORE_IAF_JRA') + case('CORE_IAF_JRA','CORE_RYF6162_JRA','CORE_RYF8485_JRA','CORE_RYF9091_JRA','CORE_RYF0304_JRA') call datm_datamode_jra_advance(exportstate, target_ymd, target_tod, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case('CLMNCEP') @@ -714,7 +718,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod call shr_get_rpointer_name(gcomp, 'atm', target_ymd, target_tod, rpfile, 'write', rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return select case (trim(datamode)) - case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA','CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA','CORE_RYF6162_JRA','CORE_RYF8485_JRA','CORE_RYF9091_JRA','CORE_RYF0304_JRA','CLMNCEP','CPLHIST','ERA5','GEFS','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 diff --git a/datm/cime_config/config_component.xml b/datm/cime_config/config_component.xml index 57762b9e2..c3b5269e7 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 CRUJRA 2024 data set @@ -24,6 +24,7 @@ interannual JRA55 forcing interannual JRA55 forcing, v1.4, through 2018 interannual JRA55 forcing, v1.5, through 2023 + JRA55 Repeat Year Forcing v1.3 1961-1962 JRA55 Repeat Year Forcing v1.3 1984-1985 JRA55 Repeat Year Forcing v1.3 1990-1991 JRA55 Repeat Year Forcing v1.3 2003-2004 @@ -42,7 +43,7 @@ char - CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,1PT,CLMCRUJRA2024,CLMCRUNCEPv7,CLMGSWP3v1,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,CORE_IAF_JRA_1p4_2018,CORE_IAF_JRA_1p5_2023,ERA5,SIMPLE + CORE2_NYF,CORE2_IAF,CLM_QIAN,CLM_QIAN_WISO,1PT,CLMCRUJRA2024,CLMCRUNCEPv7,CLMGSWP3v1,CLMNLDAS2,CPLHIST,CORE_IAF_JRA,CORE_IAF_JRA_1p4_2018,CORE_IAF_JRA_1p5_2023,CORE_RYF6162_JRA,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,ERA5,SIMPLE CORE2_NYF run_component_datm env_run.xml @@ -56,6 +57,10 @@ CORE_IAF_JRA CORE_IAF_JRA_1p4_2018 CORE_IAF_JRA_1p5_2023 + CORE_RYF6162_JRA + CORE_RYF8485_JRA + CORE_RYF9091_JRA + CORE_RYF0304_JRA CLM_QIAN CLM_QIAN_WISO CLMCRUJRA2024 diff --git a/datm/cime_config/namelist_definition_datm.xml b/datm/cime_config/namelist_definition_datm.xml index ded33cd3d..8ca888bb3 100644 --- a/datm/cime_config/namelist_definition_datm.xml +++ b/datm/cime_config/namelist_definition_datm.xml @@ -61,6 +61,9 @@ CORE_IAF_JRA_1p5_2023.GCGCS.PREC,CORE_IAF_JRA_1p5_2023.GISS.LWDN,CORE_IAF_JRA_1p5_2023.GISS.SWDN,CORE_IAF_JRA_1p5_2023.NCEP.Q_10,CORE_IAF_JRA_1p5_2023.NCEP.SLP_,CORE_IAF_JRA_1p5_2023.NCEP.T_10,CORE_IAF_JRA_1p5_2023.NCEP.U_10,CORE_IAF_JRA_1p5_2023.NCEP.V_10 + + CORE_RYF6162_JRA.GISS.LWDN,CORE_RYF6162_JRA.GISS.SWDN,CORE_RYF6162_JRA.GCGCS,CORE_RYF6162_JRA.NCEP + CORE_RYF8485_JRA.GISS.LWDN,CORE_RYF8485_JRA.GISS.SWDN,CORE_RYF8485_JRA.GCGCS,CORE_RYF8485_JRA.NCEP @@ -90,7 +93,7 @@ char datm datm_nml - CLMNCEP,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,ERA5,SIMPLE,CPLHIST,1PT + CLMNCEP,CORE2_NYF,CORE2_IAF,CORE_IAF_JRA,CORE_RYF6162_JRA,CORE_RYF8485_JRA,CORE_RYF9091_JRA,CORE_RYF0304_JRA,ERA5,SIMPLE,CPLHIST,1PT general method that operates on the data. ----datamode = "CPLHIST"---- @@ -115,6 +118,14 @@ Clm Dyn doi 10.1007/s00382-008-0441-3. ----datamode = "CORE_IAF_JRA"---- JRA55 intra-annual year forcing + ----datamode = "CORE_RYF6162_JRA"---- + JRA55 Repeat Year Forcing 1961-1962 + ----datamode = "CORE_RYF8485_JRA"---- + JRA55 Repeat Year Forcing 1984-1985 + ----datamode = "CORE_RYF9091_JRA"---- + JRA55 Repeat Year Forcing 1990-1991 + ----datamode = "CORE_RYF0304_JRA"---- + JRA55 Repeat Year Forcing 2003-2004 ----datamode = "CLMNCEP"---- In conjunction with NCEP climatological atmosphere data, provides the atmosphere forcing favored by the Land Model Working Group when diff --git a/datm/cime_config/stream_definition_datm.xml b/datm/cime_config/stream_definition_datm.xml index 8ce6fad3d..8f838aa20 100644 --- a/datm/cime_config/stream_definition_datm.xml +++ b/datm/cime_config/stream_definition_datm.xml @@ -39,6 +39,7 @@ CORE_IAF_JRA = JRA55 intra-annual year forcing (for forcing MOM6 and CICE) CORE_IAF_JRA_1p4_2018 = JRA55 intra-annual year forcing, v1.4, through 2018 (for forcing MOM6 and CICE) CORE_IAF_JRA_1p5_2023 = JRA55 intra-annual year forcing, v1.5, through 2023 (for forcing MOM6 and CICE) + CORE_RYF6162_JRA = JRA55 repeat year forcing, v1.3, 1961-1962 (for forcing MOM6 and CICE) CORE_RYF8485_JRA = JRA55 repeat year forcing, v1.3, 1984-1985 (for forcing MOM6 and CICE) CORE_RYF9091_JRA = JRA55 repeat year forcing, v1.3, 1990-1991 (for forcing MOM6 and CICE) CORE_RYF0304_JRA = JRA55 repeat year forcing, v1.3, 2003-2004 (for forcing MOM6 and CICE) @@ -2788,6 +2789,138 @@ single + + + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_6162.JRA.v1.3.radiation.lwdn.TL319.250427.nc + + + lwdn Faxa_lwdn + + null + + bilinear + + null + 1 + 1961 + 1961 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_6162.JRA.v1.3.radiation.swdn.TL319.250427.nc + + + swdn Faxa_swdn + + null + + bilinear + + null + 1 + 1961 + 1961 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_6162.JRA.v1.3.prec.TL319.250427.nc + + + prec Faxa_prec + + null + + bilinear + + null + 1 + 1961 + 1961 + 0 + + linear + + + cycle + + + 1.5 + + single + + + + + $DIN_LOC_ROOT/share/meshes/TL319_151007_ESMFmesh.nc + + + $DIN_LOC_ROOT/ocn/jra55/v1.3_ryf/RAF_6162.JRA.v1.3.states.TL319.250427.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 + 1961 + 1961 + 0 + + linear + + + cycle + + + 1.5 + + single + + diff --git a/datm/cime_config/testdefs/testlist_datm.xml b/datm/cime_config/testdefs/testlist_datm.xml index 8821baf84..70d849cd6 100644 --- a/datm/cime_config/testdefs/testlist_datm.xml +++ b/datm/cime_config/testdefs/testlist_datm.xml @@ -104,7 +104,7 @@ - + @@ -134,7 +134,6 @@ - @@ -143,7 +142,6 @@ - @@ -152,7 +150,6 @@ - @@ -161,7 +158,6 @@ - @@ -170,7 +166,6 @@ - @@ -186,4 +181,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/datm/datm_datamode_cplhist_mod.F90 b/datm/datm_datamode_cplhist_mod.F90 index c73b51efc..a260182e9 100644 --- a/datm/datm_datamode_cplhist_mod.F90 +++ b/datm/datm_datamode_cplhist_mod.F90 @@ -1,7 +1,8 @@ module datm_datamode_cplhist_mod use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_State - use ESMF , only : ESMF_StateItem_Flag + use ESMF , only : ESMF_StateItem_Flag, ESMF_STATEITEM_NOTFOUND, operator(/=) + use ESMF , only : ESMF_StateGet 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 dshr_methods_mod , only : dshr_state_getfldptr, chkerr @@ -38,6 +39,7 @@ module datm_datamode_cplhist_mod real(r8), pointer :: Faxa_swvdr(:) => null() real(r8), pointer :: Faxa_swvdf(:) => null() real(r8), pointer :: Faxa_swnet(:) => null() + real(r8), pointer :: Faxa_ndep(:,:) => null() character(*), parameter :: nullstr = 'null' character(*), parameter :: u_FILE_u = & @@ -129,6 +131,7 @@ subroutine datm_datamode_cplhist_init_pointers(importState, exportState, sdat, r integer , intent(out) :: rc ! local variables + type(ESMF_StateItem_Flag) :: itemFlag character(len=*), parameter :: subname='(datm_init_pointers): ' !------------------------------------------------------------------------------- @@ -174,7 +177,14 @@ subroutine datm_datamode_cplhist_init_pointers(importState, exportState, sdat, r call dshr_state_getfldptr(exportState, 'Faxa_lwdn' , fldptr1=Faxa_lwdn , rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - end subroutine datm_datamode_cplhist_init_pointers + 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_cplhist_init_pointers !=============================================================================== subroutine datm_datamode_cplhist_advance(mainproc, logunit, mpicom, rc) @@ -191,7 +201,10 @@ subroutine datm_datamode_cplhist_advance(mainproc, logunit, mpicom, rc) rc = ESMF_SUCCESS - ! For now - do nothing special + if (associated(Faxa_ndep)) then + ! convert ndep flux to units of kgN/m2/s (assumes that input is in gN/m2/s) + Faxa_ndep(:,:) = Faxa_ndep(:,:) / 1000._r8 + end if end subroutine datm_datamode_cplhist_advance diff --git a/dglc/cime_config/testdefs/testlist_dglc.xml b/dglc/cime_config/testdefs/testlist_dglc.xml index f39fbba2e..89f23f4d2 100644 --- a/dglc/cime_config/testdefs/testlist_dglc.xml +++ b/dglc/cime_config/testdefs/testlist_dglc.xml @@ -22,11 +22,28 @@ - + + + + + + + + + + + + + + + + + + diff --git a/dice/cime_config/testdefs/testlist_dice.xml b/dice/cime_config/testdefs/testlist_dice.xml index 948dc092d..69edd4f74 100644 --- a/dice/cime_config/testdefs/testlist_dice.xml +++ b/dice/cime_config/testdefs/testlist_dice.xml @@ -4,7 +4,6 @@ - @@ -13,11 +12,26 @@ - + + + + + + + + + + + + + + + + diff --git a/dlnd/CMakeLists.txt b/dlnd/CMakeLists.txt index 865f31e6b..cb7995d48 100644 --- a/dlnd/CMakeLists.txt +++ b/dlnd/CMakeLists.txt @@ -1,5 +1,7 @@ project(dlnd Fortran) -set(SRCFILES lnd_comp_nuopc.F90) +set(SRCFILES lnd_comp_nuopc.F90 + dlnd_datamode_glc_forcing_mod.F90 + dlnd_datamode_rof_forcing_mod.F90) foreach(FILE ${SRCFILES}) if(EXISTS "${CASEROOT}/SourceMods/src.dlnd/${FILE}") diff --git a/dlnd/cime_config/buildnml b/dlnd/cime_config/buildnml index 058c01339..69638cd35 100755 --- a/dlnd/cime_config/buildnml +++ b/dlnd/cime_config/buildnml @@ -87,13 +87,39 @@ def _create_namelists(case, confdir, inst_string, infile, nmlgen, data_list_path if type(streamlist) == type(str()): streamlist = [] + # count the number of tracers + dlnd_nonh2o = case.get_value("DLND_LND2ROF_NONH2O") + if dlnd_nonh2o == "": + dlnd_nonh2o_count = 0 + else: + dlnd_nonh2o_count = dlnd_nonh2o.count(':') + 1 + # Generate dlnd.streams.xml outfile = os.path.join(confdir, "dlnd.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, "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)) + os.path.join(caseroot,'user_nl_dlnd_streams'+inst_string), + lnd2rof_nonh2o_number=dlnd_nonh2o_count) + +#################################################################################### +def _create_drv_flds_in(case, confdir): +#################################################################################### + + # for now we are hard-coding this file name and values because we + # only need it for non-water tracers from lnd to rof + # Generate drv_flds_in file + outfile = os.path.join(confdir, "drv_flds_in") + lnd2rof_nl_name = "&lnd2rof_tracers_inparm" + nl_fin = "/" + + dlnd_nonh2o = case.get_value("DLND_LND2ROF_NONH2O") + with open(outfile, "w") as drv_fl: + drv_fl.write(f"{lnd2rof_nl_name}\n") + if dlnd_nonh2o != "none": + drv_fl.write(f" lnd2rof_tracers = \"{dlnd_nonh2o}\"\n") + drv_fl.write(f"{nl_fin}\n") ############################################################################### def buildnml(case, caseroot, compname): @@ -165,6 +191,9 @@ def buildnml(case, caseroot, compname): create_namelist_infile(case, user_nl_file, infile) namelist_infile = [infile] + # first create drv_flds_in to determine number of tracer fields + _create_drv_flds_in(case, confdir) + # create namelist and xml stream file(s) _create_namelists(case, confdir, inst_string, namelist_infile, nmlgen, data_list_path) diff --git a/dlnd/cime_config/config_component.xml b/dlnd/cime_config/config_component.xml index ab40fa583..126afbc0f 100644 --- a/dlnd/cime_config/config_component.xml +++ b/dlnd/cime_config/config_component.xml @@ -12,9 +12,10 @@ This file may have lnd desc entries. --> - Data land model (DLND) - snow coupling mode - non-snow coupling + Data land model (DLND) + snow coupling mode to drive glc with data from cpl7 run) + snow coupling mode to drive glc with data from cmeps run) + river output coupling mode to drive mosart with data from cmeps run) @@ -28,23 +29,32 @@ char - SCPL,LCPL - SCPL + SCPL,GCPL,RCPL + GCPL SCPL - LCPL + GCPL + RCPL run_component_dlnd env_run.xml model mode. - In SCPL, glc coupling data (produced by CISM) from a previous + In SCPL or GCPL mode glc coupling data produced by lnd from a previous model run is read in from a coupler history file. - In LCPL, land forcing data (produced by CLM) from a previous + In RCPL mode rof coupling data produced by lnd from a previous model run is read in from a coupler history file. + + char + none + run_component_dlnd + env_run.xml + colon delimited string of non water tracers to be sent from dlnd to the mediator - only used for DLND%RCPL + + char UNSET @@ -77,7 +87,7 @@ env_run.xml Simulation year corresponding to DLND_CPLHIST_YR_START (only used - when DLND_MODE is CPLHIST or GLC_CPLHIST). A common usage is to + when DLND_MODE is SCPL or GCPL or RCPL). A common usage is to set this to RUN_STARTDATE. With this setting, the forcing in the first year of the run will be the forcing of year DLND_CPLHIST_YR_START. Another use case is to align the calendar @@ -98,7 +108,7 @@ run_component_dlnd env_run.xml - starting year to loop data over (only used when DLND_MODE is CPLHIST or GLC_CPLHIST) + starting year to loop data over (only used when DLND_MODE is SCPL or GCPL or RCPL) @@ -109,7 +119,7 @@ run_component_dlnd env_run.xml - ending year to loop data over (only used when DLND_MODE is CPLHIST or GLC_CPLHIST) + ending year to loop data over (only used when DLND_MODE is SCPL or GCPL or RCPL) diff --git a/dlnd/cime_config/namelist_definition_dlnd.xml b/dlnd/cime_config/namelist_definition_dlnd.xml index b10350b74..f133e74a9 100644 --- a/dlnd/cime_config/namelist_definition_dlnd.xml +++ b/dlnd/cime_config/namelist_definition_dlnd.xml @@ -17,8 +17,9 @@ streams_file List of streams used for each supported dlnd_mode - lnd.cplhist - sno.cplhist + glc_forcing_mct + glc_forcing + rof_forcing @@ -26,13 +27,15 @@ char dlnd dlnd_nml - copyall + glc_forcing_mct,glc_forcing,rof_forcing Copies all fields directly from the input data streams Any required fields not found on an input stream will be set to zero. - copyall + glc_forcing_mct + glc_forcing + rof_forcing diff --git a/dlnd/cime_config/stream_definition_dlnd.xml b/dlnd/cime_config/stream_definition_dlnd.xml index 292d8834d..661a5fbc3 100644 --- a/dlnd/cime_config/stream_definition_dlnd.xml +++ b/dlnd/cime_config/stream_definition_dlnd.xml @@ -14,7 +14,7 @@ - + $LND_DOMAIN_MESH @@ -49,4 +49,104 @@ single + + + $LND_DOMAIN_MESH + + + + $DLND_CPLHIST_DIR/$DLND_CPLHIST_CASE.cpl.hx.lnd2glc.%y-01-01-00000.nc + + + lndImp_Sl_topo_elev1 Sl_topo_elev1 + lndImp_Sl_topo_elev2 Sl_topo_elev2 + lndImp_Sl_topo_elev3 Sl_topo_elev3 + lndImp_Sl_topo_elev4 Sl_topo_elev4 + lndImp_Sl_topo_elev5 Sl_topo_elev5 + lndImp_Sl_topo_elev6 Sl_topo_elev6 + lndImp_Sl_topo_elev7 Sl_topo_elev7 + lndImp_Sl_topo_elev8 Sl_topo_elev8 + lndImp_Sl_topo_elev9 Sl_topo_elev9 + lndImp_Sl_topo_elev10 Sl_topo_elev10 + lndImp_Sl_topo_elev11 Sl_topo_elev11 + lndImp_Sl_tsrf_elev1 Sl_tsrf_elev1 + lndImp_Sl_tsrf_elev2 Sl_tsrf_elev2 + lndImp_Sl_tsrf_elev3 Sl_tsrf_elev3 + lndImp_Sl_tsrf_elev4 Sl_tsrf_elev4 + lndImp_Sl_tsrf_elev5 Sl_tsrf_elev5 + lndImp_Sl_tsrf_elev6 Sl_tsrf_elev6 + lndImp_Sl_tsrf_elev7 Sl_tsrf_elev7 + lndImp_Sl_tsrf_elev8 Sl_tsrf_elev8 + lndImp_Sl_tsrf_elev9 Sl_tsrf_elev9 + lndImp_Sl_tsrf_elev10 Sl_tsrf_elev10 + lndImp_Sl_tsrf_elev11 Sl_tsrf_elev11 + lndImp_Flgl_qice_elev1 Flgl_qice_elev1 + lndImp_Flgl_qice_elev2 Flgl_qice_elev2 + lndImp_Flgl_qice_elev3 Flgl_qice_elev3 + lndImp_Flgl_qice_elev4 Flgl_qice_elev4 + lndImp_Flgl_qice_elev5 Flgl_qice_elev5 + lndImp_Flgl_qice_elev6 Flgl_qice_elev6 + lndImp_Flgl_qice_elev7 Flgl_qice_elev7 + lndImp_Flgl_qice_elev8 Flgl_qice_elev8 + lndImp_Flgl_qice_elev9 Flgl_qice_elev9 + lndImp_Flgl_qice_elev10 Flgl_qice_elev10 + lndImp_Flgl_qice_elev11 Flgl_qice_elev11 + + null + + bilinear + + null + $DLND_CPLHIST_YR_ALIGN + $DLND_CPLHIST_YR_START + $DLND_CPLHIST_YR_END + 0 + + lower + + + cycle + + + 1.5 + + single + + + + + $LND_DOMAIN_MESH + + + $DLND_CPLHIST_DIR/$DLND_CPLHIST_CASE.cpl.hx.lnd2rof.24hr.avg.%y-01-01-00000.nc + + + lndImp_Flrl_rofsur_nonh2o%rof Flrl_rofsur_nonh2o%rof + lndImp_Flrl_rofsur Flrl_rofsur + lndImp_Flrl_rofsub Flrl_rofsub + lndImp_Flrl_rofgwl Flrl_rofgwl + lndImp_Flrl_rofi Flrl_rofi + + null + + bilinear + + null + $DLND_CPLHIST_YR_ALIGN + $DLND_CPLHIST_YR_START + $DLND_CPLHIST_YR_END + 0 + + lower + + + cycle + + + 1.5 + + single + + diff --git a/dlnd/cime_config/testdefs/testlist_dlnd.xml b/dlnd/cime_config/testdefs/testlist_dlnd.xml index 59026878c..8839147b0 100644 --- a/dlnd/cime_config/testdefs/testlist_dlnd.xml +++ b/dlnd/cime_config/testdefs/testlist_dlnd.xml @@ -1,7 +1,7 @@ - + @@ -11,4 +11,22 @@ + + + + + + + + + + + + + + + + + + diff --git a/dlnd/cime_config/testdefs/testmods_dirs/dlnd/glc_forcing/shell_commands b/dlnd/cime_config/testdefs/testmods_dirs/dlnd/glc_forcing/shell_commands new file mode 100644 index 000000000..f2c10621d --- /dev/null +++ b/dlnd/cime_config/testdefs/testmods_dirs/dlnd/glc_forcing/shell_commands @@ -0,0 +1,9 @@ +./xmlchange DLND_CPLHIST_CASE=B2G1850_f09_tn14_gl4ais8_coldstart_20250122 +./xmlchange DLND_CPLHIST_DIR='$DIN_LOC_ROOT/cplhist/noresm3_0/test-dlnd2glc-docn2glc' +./xmlchange DLND_CPLHIST_YR_ALIGN=2 +./xmlchange DLND_CPLHIST_YR_END=6 +./xmlchange DLND_CPLHIST_YR_START=2 +./xmlchange RUN_STARTDATE=0002-01-01 +./xmlchange ATM_NCPL=1 +./xmlchange ROF_NCPL=1 +./xmlchange NCPL_BASE_PERIOD=year diff --git a/dlnd/cime_config/testdefs/testmods_dirs/dlnd/rof_forcing/shell_commands b/dlnd/cime_config/testdefs/testmods_dirs/dlnd/rof_forcing/shell_commands new file mode 100644 index 000000000..bdbe36e2d --- /dev/null +++ b/dlnd/cime_config/testdefs/testmods_dirs/dlnd/rof_forcing/shell_commands @@ -0,0 +1,7 @@ +./xmlchange DLND_CPLHIST_CASE=create_lnd2rof_tracers +./xmlchange DLND_CPLHIST_DIR='$DIN_LOC_ROOT/cplhist/noresm3_0/test-dlnd2rof' +./xmlchange DLND_CPLHIST_YR_END=2000 +./xmlchange DLND_CPLHIST_YR_START=2000 +./xmlchange DLND_CPLHIST_YR_ALIGN=1 +./xmlchange DLND_LND2ROF_NONH2O=tracer1 +./xmlchange RUN_STARTDATE=0001-01-01 diff --git a/dlnd/dlnd_datamode_glc_forcing_mod.F90 b/dlnd/dlnd_datamode_glc_forcing_mod.F90 new file mode 100644 index 000000000..82bad9282 --- /dev/null +++ b/dlnd/dlnd_datamode_glc_forcing_mod.F90 @@ -0,0 +1,201 @@ +module dlnd_datamode_glc_forcing_mod + + use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_State + use ESMF , only : ESMF_StateItem_Flag, ESMF_GridComp + use NUOPC , only : NUOPC_CompAttributeGet, 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_log_mod , only : shr_log_error + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + use dshr_dfield_mod , only : dfield_type, dshr_dfield_add + use glc_elevclass_mod, only : glc_elevclass_as_string, glc_elevclass_init + + implicit none + private ! except + + public :: dlnd_datamode_glc_forcing_advertise + public :: dlnd_datamode_glc_forcing_init_pointers + public :: dlnd_datamode_glc_forcing_advance + + ! module pointer arrays + real(r8), pointer :: lfrac(:) + + integer :: glc_nec + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine dlnd_datamode_glc_forcing_advertise(gcomp, exportState, fldsExport, flds_scalar_name, logunit, mainproc, rc) + + ! determine export state to advertise to mediator + + ! input/output arguments + type(ESMF_GridComp), intent(inout) :: gcomp + type(ESMF_State) , intent(inout) :: exportState + type(fldList_type) , pointer :: fldsExport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(in) :: logunit + logical , intent(in) :: mainproc + integer , intent(out) :: rc + + ! local variables + type(fldlist_type), pointer :: fldList + character(cl) :: cvalue + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Determine glc_nec + call NUOPC_CompAttributeGet(gcomp, name='glc_nec', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) glc_nec + call ESMF_LogWrite('glc_nec = '// trim(cvalue), ESMF_LOGMSG_INFO) + + ! Initialize GLC elevation class data to default boundaries, based on given glc_nec + call glc_elevclass_init(glc_nec) + + !------------------- + ! Advertise export fields + !------------------- + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldlist_add(fldsExport, "Sl_lfrin") + + ! The following puts all of the elevation class fields as an + ! undidstributed dimension in the export state field - index1 is bare land - and the total number of + ! elevation classes not equal to bare land go from index2 -> glc_nec+1 + if (glc_nec > 0) then + call dshr_fldList_add(fldsExport, 'Sl_tsrf_elev' , ungridded_lbound=1, ungridded_ubound=glc_nec+1) + call dshr_fldList_add(fldsExport, 'Sl_topo_elev' , ungridded_lbound=1, ungridded_ubound=glc_nec+1) + call dshr_fldList_add(fldsExport, 'Flgl_qice_elev', ungridded_lbound=1, ungridded_ubound=glc_nec+1) + end if + + 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('(dlnd_comp_advertise): Fr_lnd '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine dlnd_datamode_glc_forcing_advertise + + !=============================================================================== + subroutine dlnd_datamode_glc_forcing_init_pointers(exportState, sdat, dfields, model_frac, datamode, logunit, mainproc, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type), intent(in) :: sdat + type(dfield_type) , pointer :: dfields + real(r8) , intent(in) :: model_frac(:) + character(len=*) , intent(in) :: datamode + integer , intent(in) :: logunit + logical , intent(in) :: mainproc + integer , intent(out) :: rc + + ! local variables + integer :: n + character(len=2) :: nec_str + character(CS), allocatable :: strm_flds_topo(:) + character(CS), allocatable :: strm_flds_tsrf(:) + character(CS), allocatable :: strm_flds_qice(:) + character(len=*), parameter :: subname='(dlnd_datamode_glc_forcing_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Set fractional land pointer in export state + call dshr_state_getfldptr(exportState, fldname='Sl_lfrin', fldptr1=lfrac, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + lfrac(:) = model_frac(:) + + ! Create stream-> export state mapping + ! Note that strm_flds is the model name for the stream field + ! Note that state_fld is the model name for the export field + + if (trim(datamode) == 'glc_forcing_mct') then + allocate(strm_flds_tsrf(0:glc_nec)) + allocate(strm_flds_topo(0:glc_nec)) + allocate(strm_flds_qice(0:glc_nec)) + do n = 0,glc_nec + write(nec_str, '(i2.2)') n + strm_flds_tsrf(n) = 'Sl_tsrf_elev' // trim(nec_str) + strm_flds_topo(n) = 'Sl_topo_elev' // trim(nec_str) + strm_flds_qice(n) = 'Flgl_qice_elev' // trim(nec_str) + end do + + else if (trim(datamode) == 'glc_forcing' ) then + allocate(strm_flds_tsrf(1:glc_nec+1)) + allocate(strm_flds_topo(1:glc_nec+1)) + allocate(strm_flds_qice(1:glc_nec+1)) + do n = 1,glc_nec+1 + write(nec_str, '(i0)') n + strm_flds_tsrf(n) = 'Sl_tsrf_elev' // trim(nec_str) + strm_flds_topo(n) = 'Sl_topo_elev' // trim(nec_str) + strm_flds_qice(n) = 'Flgl_qice_elev' // trim(nec_str) + end do + else + call shr_log_error(subname//'ERROR illegal datamode = '//trim(datamode), rc=rc) + return + end if + + ! The following maps stream input fields to export fields that have an ungridded dimension + call dshr_dfield_add(dfields, sdat, state_fld='Sl_tsrf_elev', strm_flds=strm_flds_tsrf, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_dfield_add(dfields, sdat, state_fld='Sl_topo_elev', strm_flds=strm_flds_topo, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_dfield_add(dfields, sdat, state_fld='Flgl_qice_elev', strm_flds=strm_flds_qice, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + deallocate(strm_flds_tsrf) + deallocate(strm_flds_topo) + deallocate(strm_flds_qice) + + end subroutine dlnd_datamode_glc_forcing_init_pointers + + !=============================================================================== + subroutine dlnd_datamode_glc_forcing_advance(exportState, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + integer , intent(out) :: rc + + ! local variables + integer :: n + real(r8), pointer :: fldptr2(:,:) + character(len=*), parameter :: subname='(dlnd_datamode_glc_forcing_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Set special value over masked points + call dshr_state_getfldptr(exportState, 'Sl_tsrf_elev', fldptr2=fldptr2, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1,size(fldptr2,dim=2) + if (lfrac(n) == 0._r8) fldptr2(:,n) = 1.e30_r8 + end do + + call dshr_state_getfldptr(exportState, 'Sl_topo_elev', fldptr2=fldptr2, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1,size(fldptr2,dim=2) + if (lfrac(n) == 0._r8) fldptr2(:,n) = 1.e30_r8 + end do + + call dshr_state_getfldptr(exportState, 'Flgl_qice_elev', fldptr2=fldptr2, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1,size(fldptr2,dim=2) + if (lfrac(n) == 0._r8) fldptr2(:,n) = 1.e30_r8 + end do + + end subroutine dlnd_datamode_glc_forcing_advance + +end module dlnd_datamode_glc_forcing_mod diff --git a/dlnd/dlnd_datamode_rof_forcing_mod.F90 b/dlnd/dlnd_datamode_rof_forcing_mod.F90 new file mode 100644 index 000000000..2576e5ac5 --- /dev/null +++ b/dlnd/dlnd_datamode_rof_forcing_mod.F90 @@ -0,0 +1,212 @@ +module dlnd_datamode_rof_forcing_mod + + use ESMF , only : ESMF_SUCCESS, ESMF_LOGMSG_INFO, ESMF_LogWrite, ESMF_State + use ESMF , only : ESMF_StateItem_Flag + 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_string_mod , only : shr_string_listGetNum, shr_string_listGetName + use dshr_methods_mod , only : dshr_state_getfldptr, chkerr + use dshr_strdata_mod , only : shr_strdata_type + use dshr_fldlist_mod , only : fldlist_type, dshr_fldlist_add + use dshr_dfield_mod , only : dfield_type, dshr_dfield_add + use shr_lnd2rof_tracers_mod , only : shr_lnd2rof_tracers_readnl + + implicit none + private ! except + + public :: dlnd_datamode_rof_forcing_advertise + public :: dlnd_datamode_rof_forcing_init_pointers + public :: dlnd_datamode_rof_forcing_advance + + ! module pointer arrays + real(r8), pointer :: lfrac(:) + + character(*), parameter :: Flrl_rofsur_nonh2o = 'Flrl_rofsur_nonh2o' + character(*), parameter :: Flrl_rofsur = 'Flrl_rofsur' + character(*), parameter :: Flrl_rofsub = 'Flrl_rofsub' + character(*), parameter :: Flrl_rofgwl = 'Flrl_rofgwl' + character(*), parameter :: Flrl_rofi = 'Flrl_rofi' + character(*), parameter :: Flrl_irrig = 'Flrl_irrig' + + character(len=11) :: fldnames_h2o(5) = & + (/'Flrl_rofsur', 'Flrl_rofsub','Flrl_rofgwl','Flrl_rofi ','Flrl_irrig '/) + + integer :: ntracers_nonh2o + + character(*), parameter :: nullstr = 'null' + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine dlnd_datamode_rof_forcing_advertise(exportState, fldsExport, flds_scalar_name, logunit, mainproc, rc) + + ! determine export fields to advertise to mediator + + ! input/output arguments + type(ESMF_State) :: exportState + type(fldList_type) , pointer :: fldsExport + character(len=*) , intent(in) :: flds_scalar_name + integer , intent(in) :: logunit + logical , intent(in) :: mainproc + integer , intent(out) :: rc + + ! local variables + character(len=CS) :: lnd2rof_tracers + type(fldlist_type), pointer :: fldList + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! lnd2rof liquid tracers (liquid tracers OTHER than water) + ! coupling the land input of tracers other than standard water to MOSART + if (mainproc) then + write(logunit,'(a)') 'reading in non-water tracers from land (if any) in drv_flds_in ' + end if + lnd2rof_tracers = ' ' + call shr_lnd2rof_tracers_readnl('drv_flds_in', lnd2rof_tracers) + if (lnd2rof_tracers /= ' ') then + ntracers_nonh2o = shr_string_listGetNum(lnd2rof_tracers) + else + ntracers_nonh2o = 0 + end if + + !------------------- + ! Advertise export fields to rof + !------------------- + + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + call dshr_fldlist_add(fldsExport, "Sl_lfrin") + + ! The following puts all non-water tracers as an undidstributed dimension in the export state field + if (ntracers_nonh2o > 1) then + call dshr_fldList_add(fldsExport, Flrl_rofsur_nonh2o, ungridded_lbound=1, ungridded_ubound=ntracers_nonh2o) + else if (ntracers_nonh2o == 1) then + call dshr_fldList_add(fldsExport, Flrl_rofsur_nonh2o) + end if + call dshr_fldlist_add(FldsExport, Flrl_rofsur) + call dshr_fldlist_add(FldsExport, Flrl_rofsub) + call dshr_fldlist_add(FldsExport, Flrl_rofgwl) + call dshr_fldlist_add(FldsExport, Flrl_rofi ) + call dshr_fldlist_add(FldsExport, Flrl_irrig ) + + 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('(dlnd_comp_advertise): Fr_lnd '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + if (mainproc) then + write(logunit,'(a)') '(dlnd_comp_advertise): Fr_lnd '//trim(fldList%stdname) + end if + fldList => fldList%next + enddo + + end subroutine dlnd_datamode_rof_forcing_advertise + + !=============================================================================== + + subroutine dlnd_datamode_rof_forcing_init_pointers(exportState, sdat, dfields, model_frac, logunit, mainproc, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type), intent(in) :: sdat + type(dfield_type) , pointer :: dfields + real(r8) , intent(in) :: model_frac(:) + integer , intent(in) :: logunit + logical , intent(in) :: mainproc + integer , intent(out) :: rc + + ! local variables + integer :: n + character(len=2) :: nchar + character(CS), allocatable :: strm_flds(:) + character(CS) :: fieldname + character(len=*), parameter :: subname='(dlnd_datamode_rof_forcing_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Set fractional land pointer in export state + call dshr_state_getfldptr(exportState, fldname='Sl_lfrin', fldptr1=lfrac, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + lfrac(:) = model_frac(:) + + ! Create stream-> export state mapping for the case where the + ! stream field is 1d but the export state field is 2d + ! Note that strm_flds is the model name for the stream field (1d) + ! Note that state_fld is the model name for the export field (2d) + if (ntracers_nonh2o > 0) then + if (ntracers_nonh2o == 1) then + fieldname = trim(Flrl_rofsur_nonh2o) + call dshr_dfield_add( dfields, sdat, trim(fieldname), trim(fieldname), exportState, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + allocate(strm_flds(ntracers_nonh2o)) + do n = 1,ntracers_nonh2o + write(nchar,'(i2.2)') n + strm_flds(n) = trim(Flrl_rofsur_nonh2o) // trim(nchar) + end do + call dshr_dfield_add(dfields, sdat, state_fld=Flrl_rofsur_nonh2o, strm_flds=strm_flds, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + end if + + ! Initialize dfields data type (to map streams to export state fields) + ! Create dfields linked list - used for copying stream fields to export state fields + do n = 1,size(fldnames_h2o) + fieldname = trim(fldnames_h2o(n)) + call dshr_dfield_add( dfields, sdat, trim(fieldname), trim(fieldname), exportState, logunit, mainproc, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end do + + end subroutine dlnd_datamode_rof_forcing_init_pointers + + !=============================================================================== + subroutine dlnd_datamode_rof_forcing_advance(exportState, rc) + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + integer , intent(out) :: rc + + ! local variables + integer :: n,nfld + real(r8), pointer :: fldptr1(:) + real(r8), pointer :: fldptr2(:,:) + character(CS) :: fieldname + character(len=*), parameter :: subname='(dlnd_datamode_rof_forcing_advance): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + if (ntracers_nonh2o > 0) then + ! Set special value over masked points + if (ntracers_nonh2o == 1) then + call dshr_state_getfldptr(exportState, Flrl_rofsur_nonh2o, fldptr1=fldptr1, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1,size(fldptr1) + if (lfrac(n) == 0._r8) fldptr1(n) = 1.e30_r8 + end do + else + call dshr_state_getfldptr(exportState, Flrl_rofsur_nonh2o, fldptr2=fldptr2, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1,size(fldptr2,dim=2) + if (lfrac(n) == 0._r8) fldptr2(:,n) = 1.e30_r8 + end do + end if + end if + + do nfld = 1,size(fldnames_h2o) + fieldname = trim(fldnames_h2o(nfld)) + call dshr_state_getfldptr(exportState, fieldname, fldptr1=fldptr1, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do n = 1,size(fldptr1) + if (lfrac(n) == 0._r8) fldptr1(n) = 1.e30_r8 + end do + end do + + end subroutine dlnd_datamode_rof_forcing_advance + +end module dlnd_datamode_rof_forcing_mod diff --git a/dlnd/lnd_comp_nuopc.F90 b/dlnd/lnd_comp_nuopc.F90 index df4c37941..30d10b22c 100644 --- a/dlnd/lnd_comp_nuopc.F90 +++ b/dlnd/lnd_comp_nuopc.F90 @@ -34,9 +34,18 @@ module cdeps_dlnd_comp 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 - use glc_elevclass_mod , only : glc_elevclass_as_string, glc_elevclass_init + + ! Datamode specialized modules + use dlnd_datamode_glc_forcing_mod, only : dlnd_datamode_glc_forcing_advertise + use dlnd_datamode_glc_forcing_mod, only : dlnd_datamode_glc_forcing_init_pointers + use dlnd_datamode_glc_forcing_mod, only : dlnd_datamode_glc_forcing_advance + + use dlnd_datamode_rof_forcing_mod, only : dlnd_datamode_rof_forcing_advertise + use dlnd_datamode_rof_forcing_mod, only : dlnd_datamode_rof_forcing_init_pointers + use dlnd_datamode_rof_forcing_mod, only : dlnd_datamode_rof_forcing_advance + use nuopc_shr_methods , only : shr_get_rpointer_name - + implicit none private ! except @@ -45,10 +54,8 @@ module cdeps_dlnd_comp private :: InitializeAdvertise private :: InitializeRealize private :: ModelAdvance - private :: ModelFinalize - private :: dlnd_comp_advertise - private :: dlnd_comp_realize private :: dlnd_comp_run + private :: ModelFinalize !-------------------------------------------------------------------------- ! Private module data @@ -62,7 +69,7 @@ module cdeps_dlnd_comp integer :: flds_scalar_index_ny = 0 integer :: mpicom ! mpi communicator integer :: my_task ! my task in mpi communicator mpicom - logical :: mainproc ! true of my_task == main_task + logical :: mainproc ! true if my_task == main_task integer :: inst_index ! number of current instance (ie. 1) character(len=16) :: inst_suffix = "" ! char string associated with instance (ie. "_0001" or "") integer :: logunit ! logging unit number @@ -76,8 +83,6 @@ module cdeps_dlnd_comp character(CX) :: model_maskfile = nullstr ! full pathname to obtain mask from character(CX) :: streamfilename ! filename to obtain stream info from character(CX) :: nlfilename = nullstr ! filename to obtain namelist info from -! not currently used -! logical :: force_prognostic_true = .false. ! if true set prognostic true character(CX) :: restfilm = nullstr ! model restart file namelist integer :: nx_global ! global nx dimension of model mesh integer :: ny_global ! global ny dimension of model mesh @@ -92,11 +97,7 @@ module cdeps_dlnd_comp real(r8), pointer :: model_frac(:) => null() integer , pointer :: model_mask(:) => null() - ! module pointer arrays - real(r8), pointer :: lfrac(:) - ! module constants - integer :: glc_nec logical :: diagnose_data = .true. integer , parameter :: main_task=0 ! task number of main task #ifdef CESMCOUPLED @@ -167,7 +168,6 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) ! local variables type(ESMF_VM) :: vm - character(CL) :: cvalue integer :: nu ! unit number integer :: bcasttmp(4) integer :: ierr ! error code @@ -246,20 +246,23 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) endif ! Validate sdat datamode - if (trim(datamode) == 'copyall') then + if ( trim(datamode) == 'glc_forcing_mct' .or. & + trim(datamode) == 'glc_forcing' .or. & + trim(datamode) == 'rof_forcing') then if (my_task == main_task) write(logunit,*) 'dlnd datamode = ',trim(datamode) else call shr_log_error(' ERROR illegal dlnd datamode = '//trim(datamode), rc=rc) return end if - call NUOPC_CompAttributeGet(gcomp, name='glc_nec', value=cvalue, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - read(cvalue,*) glc_nec - call ESMF_LogWrite('glc_nec = '// trim(cvalue), ESMF_LOGMSG_INFO) ! Advertise the export fields - call dlnd_comp_advertise(importState, exportState, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (trim(datamode) == 'glc_forcing' .or. trim(datamode) == 'glc_forcing_mct') then + call dlnd_datamode_glc_forcing_advertise(gcomp, exportState, fldsExport, flds_scalar_name, logunit, mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else if (trim(datamode) == 'rof_forcing') then + call dlnd_datamode_rof_forcing_advertise(exportState, fldsExport, flds_scalar_name, logunit, mainproc, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if end subroutine InitializeAdvertise @@ -300,8 +303,10 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) call ESMF_TraceRegionExit('dlnd_strdata_init') ! 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, export_all, rc=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//':dlndExport', export_all, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return ! get the time to interpolate the stream data to @@ -319,7 +324,6 @@ subroutine InitializeRealize(gcomp, importState, exportState, clock, rc) if (chkerr(rc,__LINE__,u_FILE_u)) return end if - ! Run dlnd to create export state call dlnd_comp_run(importState, exportState, current_ymd, current_tod, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -340,7 +344,9 @@ end subroutine InitializeRealize !=============================================================================== subroutine ModelAdvance(gcomp, rc) + use nuopc_shr_methods, only : shr_get_rpointer_name + ! input/output variables type(ESMF_GridComp) :: gcomp integer, intent(out) :: rc @@ -395,7 +401,6 @@ subroutine ModelAdvance(gcomp, rc) call ESMF_TraceRegionExit('dlnd_restart') endif - ! write diagnostics if (diagnose_data) then call dshr_state_diagnose(exportState, flds_scalar_name, subname//':ES',rc=rc) @@ -426,84 +431,6 @@ subroutine ModelFinalize(gcomp, rc) end subroutine ModelFinalize - !=============================================================================== - subroutine dlnd_comp_advertise(importState, exportState, rc) - - ! determine export and import fields to advertise to mediator - - ! input/output arguments - type(ESMF_State) :: importState - type(ESMF_State) :: exportState - integer , intent(out) :: rc - - ! local variables - type(fldlist_type), pointer :: fldList - !------------------------------------------------------------------------------- - - rc = ESMF_SUCCESS - - call glc_elevclass_init(glc_nec) - - !------------------- - ! Advertise export fields - !------------------- - - call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) - call dshr_fldlist_add(fldsExport, "Sl_lfrin") - - ! The following puts all of the elevation class fields as an - ! undidstributed dimension in the export state field - index1 is bare land - and the total number of - ! elevation classes not equal to bare land go from index2 -> glc_nec+1 - if (glc_nec > 0) then - call dshr_fldList_add(fldsExport, 'Sl_tsrf_elev' , ungridded_lbound=1, ungridded_ubound=glc_nec+1) - call dshr_fldList_add(fldsExport, 'Sl_topo_elev' , ungridded_lbound=1, ungridded_ubound=glc_nec+1) - call dshr_fldList_add(fldsExport, 'Flgl_qice_elev', ungridded_lbound=1, ungridded_ubound=glc_nec+1) - end if - - 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('(dlnd_comp_advertise): Fr_lnd '//trim(fldList%stdname), ESMF_LOGMSG_INFO) - fldList => fldList%next - enddo - - ! TODO: Non snow fields that nead to be added if dlnd is in cplhist mode - ! "Sl_t " "Sl_tref " "Sl_qref " "Sl_avsdr " - ! "Sl_anidr " "Sl_avsdf " "Sl_anidf " "Sl_snowh " - ! "Fall_taux " "Fall_tauy " "Fall_lat " "Fall_sen " - ! "Fall_lwup " "Fall_evap " "Fall_swnet " "Sl_landfrac " - ! "Sl_fv " "Sl_ram1 " - ! "Fall_flxdst1" "Fall_flxdst2" "Fall_flxdst3" "Fall_flxdst4" - - end subroutine dlnd_comp_advertise - - !=============================================================================== - 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 - character(*), parameter :: subName = "(dlnd_comp_realize) " - ! ---------------------------------------------- - - rc = ESMF_SUCCESS - - ! ------------------------------------- - ! 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//':dlndExport', export_all, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - end subroutine dlnd_comp_realize - !=============================================================================== subroutine dlnd_comp_run(importState, exportState, target_ymd, target_tod, rc) @@ -519,10 +446,7 @@ subroutine dlnd_comp_run(importState, exportState, target_ymd, target_tod, rc) integer , intent(out) :: rc ! local variables - logical :: first_time = .true. - integer :: n - character(len=2) :: nec_str - character(CS), allocatable :: strm_flds(:) + logical :: first_time = .true. !------------------------------------------------------------------------------- rc = ESMF_SUCCESS @@ -530,49 +454,31 @@ subroutine dlnd_comp_run(importState, exportState, target_ymd, target_tod, rc) call ESMF_TraceRegionEnter('DLND_RUN') !-------------------- - ! set module pointers + ! First time initialization !-------------------- if (first_time) then - - ! Set fractional land pointer in export state - call dshr_state_getfldptr(exportState, fldname='Sl_lfrin', fldptr1=lfrac, rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - lfrac(:) = model_frac(:) - - ! Create stream-> export state mapping - ! Note that strm_flds is the model name for the stream field - ! Note that state_fld is the model name for the export field - allocate(strm_flds(0:glc_nec)) - do n = 0,glc_nec - nec_str = glc_elevclass_as_string(n) - strm_flds(n) = 'Sl_tsrf_elev' // trim(nec_str) - end do - call dshr_dfield_add(dfields, sdat, state_fld='Sl_tsrf_elev', strm_flds=strm_flds, state=exportState, & - logunit=logunit, mainproc=mainproc, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - do n = 0,glc_nec - nec_str = glc_elevclass_as_string(n) - strm_flds(n) = 'Sl_topo_elev' // trim(nec_str) - end do - call dshr_dfield_add(dfields, sdat, state_fld='Sl_topo_elev', strm_flds=strm_flds, state=exportState, & - logunit=logunit, mainproc=mainproc, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - do n = 0,glc_nec - nec_str = glc_elevclass_as_string(n) - strm_flds(n) = 'Flgl_qice_elev' // trim(nec_str) - end do - call dshr_dfield_add(dfields, sdat, state_fld='Flgl_qice_elev', strm_flds=strm_flds, state=exportState, & - logunit=logunit, mainproc=mainproc, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! Initialize datamode module pointers AND dfields + select case (trim(datamode)) + case('glc_forcing_mct') + call dlnd_datamode_glc_forcing_init_pointers(exportState, sdat, dfields, model_frac, datamode, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('glc_forcing') + call dlnd_datamode_glc_forcing_init_pointers(exportState, sdat, dfields, model_frac, datamode, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('rof_forcing') + call dlnd_datamode_rof_forcing_init_pointers(exportState, sdat, dfields, model_frac, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case default + call shr_log_error(' ERROR illegal dlnd datamode = '//trim(datamode), rc=rc) + return + end select first_time = .false. end if !-------------------- - ! advance dlnd streams + ! Update export !-------------------- ! time and spatially interpolate to model time and grid @@ -583,19 +489,22 @@ subroutine dlnd_comp_run(importState, exportState, target_ymd, target_tod, rc) ! copy all fields from streams to export state as default ! This automatically will update the fields in the export state - call ESMF_TraceRegionEnter('dlnd_strdata_copy') + call ESMF_TraceRegionEnter('dlnd_dfield_copy') call dshr_dfield_copy(dfields, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_TraceRegionExit('dlnd_strdata_copy') + call ESMF_TraceRegionExit('dlnd_dfield_copy') - ! determine data model behavior based on the mode - call ESMF_TraceRegionEnter('dlnd_datamode') - select case (trim(datamode)) - case('copyall') - ! do nothing extra - end select + if (trim(datamode) == 'glc_forcing_mct' .or. trim(datamode) == 'glc_forcing' ) then + call dlnd_datamode_glc_forcing_advance(exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else if (trim(datamode) == 'rof_forcing') then + call dlnd_datamode_rof_forcing_advance(exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + call shr_log_error(' ERROR illegal dlnd datamode = '//trim(datamode), rc=rc) + return + end if - call ESMF_TraceRegionExit('dlnd_datamode') call ESMF_TraceRegionExit('DLND_RUN') end subroutine dlnd_comp_run diff --git a/dlnd/stream_definition_dlnd.xml b/dlnd/stream_definition_dlnd.xml new file mode 100644 index 000000000..0de561caf --- /dev/null +++ b/dlnd/stream_definition_dlnd.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + $LND_DOMAIN_MESH + + + + $DLND_DIR/$DLND_CASE.cpl.hl2x1yr_glc.%y-01-01.nc + + + lndImp_Sl_tsrf_elev%glc Sl_tsrf_elev%glc + lndImp_Sl_topo_elev%glc Sl_topo_elev%glc + lndImp_Flgl_qice_elev%glc Flgl_qice_elev%glc + + null + + bilinear + + null + $DLND_YR_ALIGN + $DLND_YR_START + $DLND_YR_END + 0 + + lower + + + cycle + + + 1.5 + + single + + + + + $LND_DOMAIN_MESH + + + TBD + + + lndImp_Flrl_rofsur_nonh2o%rof Flrl_rofsur_nonh2o%rof + lndImp_Flrl_rofsur Flrl_rofsur + lndImp_Flrl_rofsub Flrl_rofsub + lndImp_Flrl_rofgwl Flrl_rofgwl + lndImp_Flrl_rofi Flrl_rofi + + null + + bilinear + + null + $DLND_YR_ALIGN + $DLND_YR_START + $DLND_YR_END + 0 + + lower + + + cycle + + + 1.5 + + single + + + diff --git a/doc/source/drof.rst b/doc/source/drof.rst index abcda2f44..f0a55dfb5 100644 --- a/doc/source/drof.rst +++ b/doc/source/drof.rst @@ -109,6 +109,12 @@ DROF%IAF_JRA_1p4_2018 - streams: rof.iaf_jra_1p4_2018 - datamode: copyall +DROF%RYF6162_JRA + - JRA55 v1.3 data from 1961 May - 1962 Apr RAF + - drof_mode: RYF6162_JRA + - streams: rof.ryf6162_jra + - datamode: copyall + DROF%RYF8485_JRA - JRA55 v1.3 data from 1984 May - 1985 Apr RAF - drof_mode: RYF8485_JRA diff --git a/docn/CMakeLists.txt b/docn/CMakeLists.txt index 46e51007f..ab12861cd 100644 --- a/docn/CMakeLists.txt +++ b/docn/CMakeLists.txt @@ -7,6 +7,7 @@ set(SRCFILES ocn_comp_nuopc.F90 docn_datamode_cplhist_mod.F90 docn_datamode_multilev_mod.F90 docn_datamode_multilev_dom_mod.F90 + docn_datamode_multilev_cplhist_mod.F90 docn_import_data_mod.F90) foreach(FILE ${SRCFILES}) diff --git a/docn/cime_config/config_component.xml b/docn/cime_config/config_component.xml index 251dddf66..114eb7f8d 100644 --- a/docn/cime_config/config_component.xml +++ b/docn/cime_config/config_component.xml @@ -13,7 +13,7 @@ This file may have ocn desc entries. --> - DOCN + DOCN prescribed ocean mode slab ocean mode aquaplanet slab ocean mode @@ -34,6 +34,7 @@ mediator history output for ocean fields imported to mediator input stream files have multi level data input stream files have multi level data and prescribed ocean SST + mediator history output for multi-level ocean fields imported to mediator @@ -47,7 +48,7 @@ char - prescribed,sst_aquap1,sst_aquap2,sst_aquap3,sst_aquap4,sst_aquap5,sst_aquap6,sst_aquap7,sst_aquap8,sst_aquap9,sst_aquap10,sst_aquapfile,som,som_aquap,sst_aquap_constant,interannual,cplhist,multilev,multilev_dom + prescribed,sst_aquap1,sst_aquap2,sst_aquap3,sst_aquap4,sst_aquap5,sst_aquap6,sst_aquap7,sst_aquap8,sst_aquap9,sst_aquap10,sst_aquapfile,som,som_aquap,sst_aquap_constant,interannual,cplhist,multilev,multilev_dom,multilev_cplhist prescribed prescribed @@ -69,6 +70,7 @@ cplhist multilev multilev_dom + multilev_cplhist run_component_docn env_run.xml @@ -255,6 +257,22 @@ This is only used when DOCN_MODE=prescribed. + + char + UNSET + run_component_docn + env_run.xml + directory for coupler history data mode (only used for CPLHIST mode) + + + + char + UNSET + run_component_docn + env_run.xml + case name for coupler history data mode (only used for CPLHIST mode) + + integer diff --git a/docn/cime_config/namelist_definition_docn.xml b/docn/cime_config/namelist_definition_docn.xml index 3e6d12558..03b43af9d 100644 --- a/docn/cime_config/namelist_definition_docn.xml +++ b/docn/cime_config/namelist_definition_docn.xml @@ -19,7 +19,6 @@ interannual som_aquap som - cplhist aquapfile '' '' @@ -32,8 +31,10 @@ '' '' '' + multilev_cplhist sst_salinity_depth_blom,prescribed sst_salinity_depth_blom + cplhist @@ -41,7 +42,7 @@ char docn docn_nml - sstdata,sst_aquap1,sst_aquap2,sst_aquap3,sst_aquap4,sst_aquap5,sst_aquap6,sst_aquap7,sst_aquap8,sst_aquap9,sst_aquap10,sst_aquapfile,sst_aquap_constant,som,som_aquap,iaf,cplhist,multilev,multilev_dom + sstdata,sst_aquap1,sst_aquap2,sst_aquap3,sst_aquap4,sst_aquap5,sst_aquap6,sst_aquap7,sst_aquap8,sst_aquap9,sst_aquap10,sst_aquapfile,sst_aquap_constant,som,som_aquap,iaf,cplhist,multilev,multilev_dom,multilev_cplhist General method that operates on the data for a given docn_mode. ==> dataMode = "sstdata" @@ -108,9 +109,10 @@ sst_aquap10 sst_aquap_file sst_aquap_constant - cplhist + multilev_cplhist multilev_dom multilev + cplhist diff --git a/docn/cime_config/stream_definition_docn.xml b/docn/cime_config/stream_definition_docn.xml index 4e4dd6655..ea8738750 100644 --- a/docn/cime_config/stream_definition_docn.xml +++ b/docn/cime_config/stream_definition_docn.xml @@ -175,6 +175,96 @@ single + + + $OCN_DOMAIN_MESH + + + $DOCN_CPLHIST_DIR/$DOCN_CPLHIST_CASE.cpl.hx.ocn2glc.%y-01-01-00000.nc + + + ocnImp_So_s_depth1 So_s_depth1 + ocnImp_So_s_depth2 So_s_depth2 + ocnImp_So_s_depth3 So_s_depth3 + ocnImp_So_s_depth4 So_s_depth4 + ocnImp_So_s_depth5 So_s_depth5 + ocnImp_So_s_depth6 So_s_depth6 + ocnImp_So_s_depth7 So_s_depth7 + ocnImp_So_s_depth8 So_s_depth8 + ocnImp_So_s_depth9 So_s_depth9 + ocnImp_So_s_depth10 So_s_depth10 + ocnImp_So_s_depth11 So_s_depth11 + ocnImp_So_s_depth12 So_s_depth12 + ocnImp_So_s_depth13 So_s_depth13 + ocnImp_So_s_depth14 So_s_depth14 + ocnImp_So_s_depth15 So_s_depth15 + ocnImp_So_s_depth16 So_s_depth16 + ocnImp_So_s_depth17 So_s_depth17 + ocnImp_So_s_depth18 So_s_depth18 + ocnImp_So_s_depth19 So_s_depth19 + ocnImp_So_s_depth20 So_s_depth20 + ocnImp_So_s_depth21 So_s_depth21 + ocnImp_So_s_depth22 So_s_depth22 + ocnImp_So_s_depth23 So_s_depth23 + ocnImp_So_s_depth24 So_s_depth24 + ocnImp_So_s_depth25 So_s_depth25 + ocnImp_So_s_depth26 So_s_depth26 + ocnImp_So_s_depth27 So_s_depth27 + ocnImp_So_s_depth28 So_s_depth28 + ocnImp_So_s_depth29 So_s_depth29 + ocnImp_So_s_depth30 So_s_depth30 + ocnImp_So_t_depth1 So_t_depth1 + ocnImp_So_t_depth2 So_t_depth2 + ocnImp_So_t_depth3 So_t_depth3 + ocnImp_So_t_depth4 So_t_depth4 + ocnImp_So_t_depth5 So_t_depth5 + ocnImp_So_t_depth6 So_t_depth6 + ocnImp_So_t_depth7 So_t_depth7 + ocnImp_So_t_depth8 So_t_depth8 + ocnImp_So_t_depth9 So_t_depth9 + ocnImp_So_t_depth10 So_t_depth10 + ocnImp_So_t_depth11 So_t_depth11 + ocnImp_So_t_depth12 So_t_depth12 + ocnImp_So_t_depth13 So_t_depth13 + ocnImp_So_t_depth14 So_t_depth14 + ocnImp_So_t_depth15 So_t_depth15 + ocnImp_So_t_depth16 So_t_depth16 + ocnImp_So_t_depth17 So_t_depth17 + ocnImp_So_t_depth18 So_t_depth18 + ocnImp_So_t_depth19 So_t_depth19 + ocnImp_So_t_depth20 So_t_depth20 + ocnImp_So_t_depth21 So_t_depth21 + ocnImp_So_t_depth22 So_t_depth22 + ocnImp_So_t_depth23 So_t_depth23 + ocnImp_So_t_depth24 So_t_depth24 + ocnImp_So_t_depth25 So_t_depth25 + ocnImp_So_t_depth26 So_t_depth26 + ocnImp_So_t_depth27 So_t_depth27 + ocnImp_So_t_depth28 So_t_depth28 + ocnImp_So_t_depth29 So_t_depth29 + ocnImp_So_t_depth30 So_t_depth30 + + null + + bilinear + + null + $DOCN_CPLHIST_YR_ALIGN + $DOCN_CPLHIST_YR_START + $DOCN_CPLHIST_YR_END + 0 + + nearest + + + cycle + + + 1.e30 + + single + + $OCN_DOMAIN_MESH diff --git a/docn/cime_config/testdefs/testlist_docn.xml b/docn/cime_config/testdefs/testlist_docn.xml index 5c279cabf..0913fd994 100644 --- a/docn/cime_config/testdefs/testlist_docn.xml +++ b/docn/cime_config/testdefs/testlist_docn.xml @@ -28,5 +28,23 @@ + + + + + + + + + + + + + + + + + + diff --git a/docn/cime_config/testdefs/testmods_dirs/docn/multilev_cplhist/shell_commands b/docn/cime_config/testdefs/testmods_dirs/docn/multilev_cplhist/shell_commands new file mode 100644 index 000000000..6c4191f24 --- /dev/null +++ b/docn/cime_config/testdefs/testmods_dirs/docn/multilev_cplhist/shell_commands @@ -0,0 +1,9 @@ +./xmlchange DOCN_CPLHIST_CASE=B2G1850_f09_tn14_gl4ais8_coldstart_20250122 +./xmlchange DOCN_CPLHIST_DIR='$DIN_LOC_ROOT/cplhist/noresm3_0/test-dlnd2glc-docn2glc' +./xmlchange DOCN_CPLHIST_YR_ALIGN=2 +./xmlchange DOCN_CPLHIST_YR_END=6 +./xmlchange DOCN_CPLHIST_YR_START=2 +./xmlchange RUN_STARTDATE=0002-01-01 +./xmlchange ATM_NCPL=1 +./xmlchange ROF_NCPL=1 +./xmlchange NCPL_BASE_PERIOD=year diff --git a/docn/cime_config/testdefs/testmods_dirs/docn/multilev_cplhist/user_nl_cpl b/docn/cime_config/testdefs/testmods_dirs/docn/multilev_cplhist/user_nl_cpl new file mode 100644 index 000000000..e31c13784 --- /dev/null +++ b/docn/cime_config/testdefs/testmods_dirs/docn/multilev_cplhist/user_nl_cpl @@ -0,0 +1,20 @@ +!------------------------------------------------------------------------ +! Users should ONLY USE user_nl_cpl to change namelists variables +! for namelist variables in drv_in (except for the ones below) and +! any keyword/values in seq_maps.rc +! Users should add ALL user specific namelist and seq_maps.rc changes below +! using the following syntax +! namelist_var = new_namelist_value +! or +! mapname = new_map_name +! For example to change the default value of ocn2atm_fmapname to 'foo' use +! ocn2atm_fmapname = 'foo' +! +! Note that some namelist variables MAY NOT be changed in user_nl_cpl - +! they are defined in a $CASEROOT xml file and must be changed with +! xmlchange. +! +! For example, rather than set username to 'foo' in user_nl_cpl, call +! ./xmlchange USER=foo +!------------------------------------------------------------------------ +ocn2glc_coupling = .true. \ No newline at end of file diff --git a/docn/docn_datamode_multilev_cplhist_mod.F90 b/docn/docn_datamode_multilev_cplhist_mod.F90 new file mode 100644 index 000000000..2f79cd117 --- /dev/null +++ b/docn/docn_datamode_multilev_cplhist_mod.F90 @@ -0,0 +1,157 @@ +module docn_datamode_multilev_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_TkFrz, shr_const_pi, shr_const_ocn_ref_sal, shr_const_spval + 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_strdata_mod , only : shr_strdata_get_stream_pointer, shr_strdata_type + use dshr_dfield_mod , only : dfield_type, dshr_dfield_add + + implicit none + private ! except + + public :: docn_datamode_multilev_cplhist_advertise + public :: docn_datamode_multilev_cplhist_init_pointers + public :: docn_datamode_multilev_cplhist_advance + + ! pointers to export fields + real(r8), pointer :: So_omask(:) => null() ! real ocean fraction sent to mediator + + + integer, parameter :: nlev_export = 30 + + ! constants + character(*) , parameter :: nullstr = 'null' + character(*) , parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine docn_datamode_multilev_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, 'So_omask') + call dshr_fldList_add(fldsExport, 'So_t_depth', ungridded_lbound=1, ungridded_ubound=nlev_export) + call dshr_fldList_add(fldsExport, 'So_s_depth', ungridded_lbound=1, ungridded_ubound=nlev_export) + + 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('(docn_comp_advertise): Fr_ocn'//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine docn_datamode_multilev_cplhist_advertise + + !=============================================================================== + subroutine docn_datamode_multilev_cplhist_init_pointers(dfields, & + exportState, sdat, ocn_fraction, logunit, mainproc, rc) + + ! input/output variables + type(dfield_type) , pointer :: dfields + type(ESMF_State) , intent(inout) :: exportState + type(shr_strdata_type) , intent(in) :: sdat + real(r8) , intent(in) :: ocn_fraction(:) + integer , intent(in) :: logunit + logical , intent(in) :: mainproc + integer , intent(out) :: rc + + ! local variables + integer :: n + character(len=2) :: num_str + character(CS), allocatable :: strm_flds_t_depth(:) + character(CS), allocatable :: strm_flds_s_depth(:) + character(len=*), parameter :: subname='(docn_init_pointers): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + ! Note - docn_datamode_multilev_mod the assumption is that the stream files contain single + ! stream fields which contain the full set of levels in the stream data (i.e. 2d) + ! Whereas here we are assuming a different stream field for each vertical level + ! However, in both cases the export field contains an ungridded dimension for each vertical level + + ! Create stream-> export state mapping + ! Note that strm_flds is the model name for the stream field + ! Note that state_fld is the model name for the export field + + allocate(strm_flds_t_depth(1:nlev_export)) + allocate(strm_flds_s_depth(1:nlev_export)) + do n = 1,nlev_export + write(num_str, '(i0)') n + strm_flds_t_depth(n) = 'So_t_depth' // trim(num_str) + strm_flds_s_depth(n) = 'So_s_depth' // trim(num_str) + end do + + ! The following maps stream input multiple fields to export field that has an ungridded dimension + call dshr_dfield_add(dfields, sdat, state_fld='So_t_depth', strm_flds=strm_flds_t_depth, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + call dshr_dfield_add(dfields, sdat, state_fld='So_s_depth', strm_flds=strm_flds_s_depth, state=exportState, & + logunit=logunit, mainproc=mainproc, rc=rc) + + ! Set export state ocean fraction (So_omask) + call dshr_state_getfldptr(exportState, 'So_omask', fldptr1=So_omask , rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + So_omask(:) = ocn_fraction(:) + + end subroutine docn_datamode_multilev_cplhist_init_pointers + + !=============================================================================== + subroutine docn_datamode_multilev_cplhist_advance(exportState, rc) + + use dshr_methods_mod , only : dshr_state_getfldptr + + ! input/output variables + type(ESMF_State) , intent(inout) :: exportState + integer , intent(out) :: rc + + ! local variables + integer :: idim1,idim2 + real(r8), pointer :: fldptr2(:,:) + character(len=*), parameter :: subname='(docn_datamode_multilev): ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + call dshr_state_getfldptr(exportState, 'So_t_depth', fldptr2=fldptr2, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do idim2 = 1,size(fldptr2,dim=2) + do idim1 = 1,size(fldptr2,dim=1) + if (fldptr2(idim1,idim2) == 0._r8) then + fldptr2(idim1,idim2) = 1.e30_r8 + end if + end do + end do + + call dshr_state_getfldptr(exportState, 'So_s_depth', fldptr2=fldptr2, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + do idim2 = 1,size(fldptr2,dim=2) + do idim1 = 1,size(fldptr2,dim=1) + if (fldptr2(idim1,idim2) == 0._r8) then + fldptr2(idim1,idim2) = 1.e30_r8 + end if + end do + end do + + end subroutine docn_datamode_multilev_cplhist_advance + +end module docn_datamode_multilev_cplhist_mod diff --git a/docn/ocn_comp_nuopc.F90 b/docn/ocn_comp_nuopc.F90 index accd9ac15..5aab1dead 100644 --- a/docn/ocn_comp_nuopc.F90 +++ b/docn/ocn_comp_nuopc.F90 @@ -37,30 +37,33 @@ module cdeps_docn_comp use nuopc_shr_methods, only : shr_get_rpointer_name ! Datamode specialized modules - use docn_datamode_copyall_mod , only : docn_datamode_copyall_advertise - use docn_datamode_copyall_mod , only : docn_datamode_copyall_init_pointers - use docn_datamode_copyall_mod , only : docn_datamode_copyall_advance - use docn_datamode_iaf_mod , only : docn_datamode_iaf_advertise - use docn_datamode_iaf_mod , only : docn_datamode_iaf_init_pointers - use docn_datamode_iaf_mod , only : docn_datamode_iaf_advance - use docn_datamode_som_mod , only : docn_datamode_som_advertise - use docn_datamode_som_mod , only : docn_datamode_som_init_pointers - use docn_datamode_som_mod , only : docn_datamode_som_advance - use docn_datamode_som_mod , only : docn_datamode_som_restart_read - use docn_datamode_som_mod , only : docn_datamode_som_restart_write - use docn_datamode_aquaplanet_mod , only : docn_datamode_aquaplanet_advertise - use docn_datamode_aquaplanet_mod , only : docn_datamode_aquaplanet_init_pointers - use docn_datamode_aquaplanet_mod , only : docn_datamode_aquaplanet_advance - use docn_datamode_cplhist_mod , only : docn_datamode_cplhist_advertise - use docn_datamode_cplhist_mod , only : docn_datamode_cplhist_init_pointers - use docn_datamode_cplhist_mod , only : docn_datamode_cplhist_advance - use docn_datamode_multilev_mod , only : docn_datamode_multilev_advertise - use docn_datamode_multilev_mod , only : docn_datamode_multilev_init_pointers - use docn_datamode_multilev_mod , only : docn_datamode_multilev_advance - use docn_datamode_multilev_dom_mod, only : docn_datamode_multilev_dom_advertise - use docn_datamode_multilev_dom_mod, only : docn_datamode_multilev_dom_init_pointers - use docn_datamode_multilev_dom_mod, only : docn_datamode_multilev_dom_advance - use docn_import_data_mod , only : docn_import_data_advertise + use docn_datamode_copyall_mod , only : docn_datamode_copyall_advertise + use docn_datamode_copyall_mod , only : docn_datamode_copyall_init_pointers + use docn_datamode_copyall_mod , only : docn_datamode_copyall_advance + use docn_datamode_iaf_mod , only : docn_datamode_iaf_advertise + use docn_datamode_iaf_mod , only : docn_datamode_iaf_init_pointers + use docn_datamode_iaf_mod , only : docn_datamode_iaf_advance + use docn_datamode_som_mod , only : docn_datamode_som_advertise + use docn_datamode_som_mod , only : docn_datamode_som_init_pointers + use docn_datamode_som_mod , only : docn_datamode_som_advance + use docn_datamode_som_mod , only : docn_datamode_som_restart_read + use docn_datamode_som_mod , only : docn_datamode_som_restart_write + use docn_datamode_aquaplanet_mod , only : docn_datamode_aquaplanet_advertise + use docn_datamode_aquaplanet_mod , only : docn_datamode_aquaplanet_init_pointers + use docn_datamode_aquaplanet_mod , only : docn_datamode_aquaplanet_advance + use docn_datamode_cplhist_mod , only : docn_datamode_cplhist_advertise + use docn_datamode_cplhist_mod , only : docn_datamode_cplhist_init_pointers + use docn_datamode_cplhist_mod , only : docn_datamode_cplhist_advance + use docn_datamode_multilev_cplhist_mod , only : docn_datamode_multilev_cplhist_advertise + use docn_datamode_multilev_cplhist_mod , only : docn_datamode_multilev_cplhist_init_pointers + use docn_datamode_multilev_cplhist_mod , only : docn_datamode_multilev_cplhist_advance + use docn_datamode_multilev_dom_mod , only : docn_datamode_multilev_dom_advertise + use docn_datamode_multilev_dom_mod , only : docn_datamode_multilev_dom_init_pointers + use docn_datamode_multilev_dom_mod , only : docn_datamode_multilev_dom_advance + use docn_datamode_multilev_mod , only : docn_datamode_multilev_advertise + use docn_datamode_multilev_mod , only : docn_datamode_multilev_init_pointers + use docn_datamode_multilev_mod , only : docn_datamode_multilev_advance + use docn_import_data_mod , only : docn_import_data_advertise implicit none private ! except @@ -305,6 +308,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) trim(datamode) == 'cplhist' .or. & ! read stream, needs import data trim(datamode) == 'sst_aquap_analytic' .or. & ! analytic, no streams, import or export data trim(datamode) == 'sst_aquap_constant' .or. & ! analytic, no streams, import or export data + trim(datamode) == 'multilev_cplhist' .or. & ! multilevel ocean input trim(datamode) == 'multilev' .or. & ! multilevel ocean input trim(datamode) == 'multilev_dom') then ! multilevel ocean input and sst export ! success do nothing @@ -333,6 +337,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) else if (trim(datamode) == 'multilev') then call docn_datamode_multilev_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + else if (trim(datamode) == 'multilev_cplhist') then + call docn_datamode_multilev_cplhist_advertise(exportState, fldsExport, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return else if (trim(datamode) == 'multilev_dom') then call docn_datamode_multilev_dom_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -544,11 +551,13 @@ subroutine docn_comp_run(gcomp, importState, exportState, clock, target_ymd, tar if (first_time) then - ! Initialize dfields - call docn_init_dfields(importState, exportState, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - - ! Initialize datamode module ponters + if (trim(datamode) /= 'multilev_cplhist') then + ! with multilev_cplhist we explicitly create initilize dfields + ! within the rpointer call + call docn_init_dfields(importState, exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + endif + ! Initialize datamode module pointers select case (trim(datamode)) case('sstdata', 'sst_aquap_file') call docn_datamode_copyall_init_pointers(exportState, model_frac, rc) @@ -572,6 +581,12 @@ subroutine docn_comp_run(gcomp, importState, exportState, clock, target_ymd, tar case('multilev_dom') call docn_datamode_multilev_dom_init_pointers(exportState, sdat, model_frac, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('multilev_cplhist') + call docn_datamode_multilev_cplhist_init_pointers(dfields, & + exportState, sdat, model_frac, logunit, mainproc, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! Note that there is no call to docn_init_dfields since the + ! initialization of dfields is done in the above routine end select ! Read restart if needed @@ -580,7 +595,7 @@ subroutine docn_comp_run(gcomp, importState, exportState, clock, target_ymd, tar if (ChkErr(rc,__LINE__,u_FILE_u)) return select case (trim(datamode)) - case('sstdata', 'sst_aquap_file', 'iaf', 'cplhist', 'multilev', 'mulitilev_dom') + case('sstdata', 'sst_aquap_file', 'iaf', 'cplhist', 'multilev', 'mulitilev_dom', 'multilev_cplhist') call dshr_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case('som', 'som_aquap') @@ -605,7 +620,7 @@ subroutine docn_comp_run(gcomp, importState, exportState, clock, target_ymd, tar ! Copy all fields from streams to export state as default ! This automatically will update the fields in the export state call ESMF_TraceRegionEnter('docn_dfield_copy') - if(.not. aquaplanet) then + if (.not. aquaplanet) then call dshr_dfield_copy(dfields, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return endif @@ -637,20 +652,23 @@ subroutine docn_comp_run(gcomp, importState, exportState, clock, target_ymd, tar case('multilev_dom') call docn_datamode_multilev_dom_advance(sdat, logunit, mainproc, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('multilev_cplhist') + call docn_datamode_multilev_cplhist_advance(exportState, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return end select ! Write restarts if needed (no restarts for aquaplanet analytic or aquaplanet input file) if (restart_write) then - call shr_get_rpointer_name(gcomp, 'ocn', target_ymd, target_tod, rpfile, 'write', rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return + call shr_get_rpointer_name(gcomp, 'ocn', target_ymd, target_tod, rpfile, 'write', rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return - select case (trim(datamode)) - case('sstdata', 'sst_aquap_file', 'iaf', 'cplhist', 'multilev', 'mulitilev_dom') - call dshr_restart_write(rpfile, case_name, 'docn', inst_suffix, target_ymd, target_tod, logunit, & - my_task, sdat, rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - case('som', 'som_aquap') - call docn_datamode_som_restart_write(rpfile, case_name, inst_suffix, target_ymd, target_tod, & + select case (trim(datamode)) + case('sstdata', 'sst_aquap_file', 'iaf', 'cplhist', 'multilev', 'mulitilev_dom', 'multilev_cplhist') + call dshr_restart_write(rpfile, case_name, 'docn', inst_suffix, target_ymd, target_tod, logunit, & + my_task, sdat, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('som', 'som_aquap') + call docn_datamode_som_restart_write(rpfile, case_name, inst_suffix, target_ymd, target_tod, & logunit, my_task, sdat) case('sst_aquap_analytic', 'sst_aquap_constant') ! Do nothing @@ -658,7 +676,7 @@ subroutine docn_comp_run(gcomp, importState, exportState, clock, target_ymd, tar call shr_log_error(subName//'datamode '//trim(datamode)//' not recognized', rc=rc) return end select - + endif call ESMF_TraceRegionExit('DOCN_RUN') diff --git a/drof/cime_config/config_component.xml b/drof/cime_config/config_component.xml index 1db777be7..285649aa8 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: @@ -21,12 +21,13 @@ COREv2 interannual year forcing: COREv2 interannual year forcing: CPLHIST mode: - JRA55 interannual forcing, v1.4, through 2018 + JRA55 interannual forcing, v1.4, through 2018 JRA55 interannual forcing, v1.4, through 2018, no rofi around AIS JRA55 interannual forcing, v1.4, through 2018, no rofl around AIS JRA55 interannual forcing, v1.4, through 2018, no rofi or rofl around AIS - JRA55 interannual forcing, v1.5, through 2023 - JRA55 interannual forcing + JRA55 interannual forcing, v1.5, through 2023 + JRA55 interannual forcing + JRA55 Repeat Year Forcing v1.3 1961-1962 JRA55 Repeat Year Forcing v1.3 1984-1985 JRA55 Repeat Year Forcing v1.3 1990-1991 JRA55 Repeat Year Forcing v1.3 2003-2004 @@ -43,7 +44,7 @@ char - CPLHIST,DIATREN_ANN_RX1,DIATREN_IAF_RX1,DIATREN_IAF_AIS00_RX1,DIATREN_IAF_AIS45_RX1,DIATREN_IAF_AIS55_RX1,IAF_JRA,IAF_JRA_1p4_2018,IAF_JRA_1p4_2018_AIS0ICE,IAF_JRA_1p4_2018_AIS0LIQ,IAF_JRA_1p4_2018_AIS0ROF,IAF_JRA_1p5_2023,RYF8485_JRA,RYF9091_JRA,RYF0304_JRA,NULL + CPLHIST,DIATREN_ANN_RX1,DIATREN_IAF_RX1,DIATREN_IAF_AIS00_RX1,DIATREN_IAF_AIS45_RX1,DIATREN_IAF_AIS55_RX1,IAF_JRA,IAF_JRA_1p4_2018,IAF_JRA_1p4_2018_AIS0ICE,IAF_JRA_1p4_2018_AIS0LIQ,IAF_JRA_1p4_2018_AIS0ROF,IAF_JRA_1p5_2023,RYF6162_JRA,RYF8485_JRA,RYF9091_JRA,RYF0304_JRA,NULL DIATREN_ANN_RX1 NULL @@ -56,12 +57,13 @@ DIATREN_IAF_AIS45_RX1 DIATREN_IAF_AIS55_RX1 CPLHIST - IAF_JRA - IAF_JRA_1p4_2018 + IAF_JRA + IAF_JRA_1p4_2018 IAF_JRA_1p4_2018_AIS0ICE IAF_JRA_1p4_2018_AIS0LIQ IAF_JRA_1p4_2018_AIS0ROF - IAF_JRA_1p5_2023 + IAF_JRA_1p5_2023 + RYF6162_JRA RYF8485_JRA RYF9091_JRA RYF0304_JRA @@ -79,6 +81,15 @@ default is DIATREN_ANN_RX1. + + char + + UNSET + run_component_drof + env_run.xml + directory for coupler history data mode when DROF_MODE is CPLHIST + + char diff --git a/drof/cime_config/namelist_definition_drof.xml b/drof/cime_config/namelist_definition_drof.xml index ff3d402bb..694c9c401 100644 --- a/drof/cime_config/namelist_definition_drof.xml +++ b/drof/cime_config/namelist_definition_drof.xml @@ -22,6 +22,7 @@ rof.iaf_jra_1p4_2018 rof.iaf_jra_1p5_2023 rof.iaf_jra + rof.ryf6162_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 1c87e690b..d43883ec9 100644 --- a/drof/cime_config/stream_definition_drof.xml +++ b/drof/cime_config/stream_definition_drof.xml @@ -507,6 +507,38 @@ single + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/JRA.v1.4.runoff.1958_ESMFmesh_cdf5_20201020.nc + + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/RAF_6162.JRA.v1.4.runoff.250427.nc + + + rofl Forr_rofl + rofi Forr_rofi + + null + + bilinear + + null + 1 + 1961 + 1961 + 0 + + upper + + + cycle + + + 3.0 + + single + + $DIN_LOC_ROOT/lnd/dlnd7/JRA55/JRA.v1.4.runoff.1958_ESMFmesh_cdf5_20201020.nc @@ -608,7 +640,7 @@ $ROF_DOMAIN_MESH - $DIN_LOC_ROOT/lnd/dlnd7/RX1/runoff.daitren.iaf.20120419.nc + $DROF_CPLHIST_DIR/$DROF_CPLHIST_CASE.cpl.hx.rof.24h.avrg.%ymd-00000.nc rofImp_Forr_rofl Forr_rofl diff --git a/dshr/dshr_dfield_mod.F90 b/dshr/dshr_dfield_mod.F90 index bbd411572..eba63087e 100644 --- a/dshr/dshr_dfield_mod.F90 +++ b/dshr/dshr_dfield_mod.F90 @@ -85,9 +85,9 @@ subroutine dshr_dfield_add_1d(dfields, sdat, state_fld, strm_fld, state, logunit dfield_new%stream_index = iunset dfield_new%fldbun_index = iunset - ! loop over all input streams and ! determine if the strm_fld is in the attribute vector of stream ns + ! loop over all input streams ! if strm_fld is in the field bundle of stream ns, set the field index of the field with the name strm_fld - ! and set the index of the stream + ! colon delimited string and set the index of the stream ! loop over all input streams and ! determine if the strm_fld is in the attribute vector of stream ns do ns = 1, shr_strdata_get_stream_count(sdat) @@ -485,7 +485,10 @@ subroutine dshr_dfield_copy(dfields, sdat, rc) if (ungriddedCount > 0) then call dshr_field_getfldptr(lfield, fldptr2=data2d, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - dfield%state_data2d(:,:) = data2d(:,:) + if (size(dfield%state_data2d,dim=1) == size(data2d,dim=1)) then + ! Only do copy if the ungridded dimension size matches + dfield%state_data2d(:,:) = data2d(:,:) + end if else call dshr_field_getfldptr(lfield, fldptr1=data1d, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return diff --git a/share/CMakeLists.txt b/share/CMakeLists.txt index cee2936d4..c771621b3 100644 --- a/share/CMakeLists.txt +++ b/share/CMakeLists.txt @@ -16,6 +16,7 @@ add_library(cdeps_share ${GenF90_SRCS} shr_const_mod.F90 shr_orb_mod.F90 shr_log_mod.F90 + shr_lnd2rof_tracers_mod.F90 shr_strconvert_mod.F90 shr_precip_mod.F90 shr_string_mod.F90 diff --git a/share/shr_lnd2rof_tracers_mod.F90 b/share/shr_lnd2rof_tracers_mod.F90 new file mode 100644 index 000000000..e673983b7 --- /dev/null +++ b/share/shr_lnd2rof_tracers_mod.F90 @@ -0,0 +1,94 @@ +module shr_lnd2rof_tracers_mod + + !======================================================================== + ! read lnd2rof_tracers_inparm namelist and sets up driver list of fields for + ! lnd -> river communications + !======================================================================== + + use ESMF , only : ESMF_VMGetCurrent, ESMF_VM, ESMF_VMGet, ESMF_VMBroadcast + use ESMF , only : ESMF_LogFoundError, ESMF_LOGERR_PASSTHRU, ESMF_SUCCESS + use shr_sys_mod , only : shr_sys_abort + use shr_log_mod , only : shr_log_getLogUnit + use shr_kind_mod , only : r8 => shr_kind_r8, cs => shr_kind_cs + use shr_nl_mod , only : shr_nl_find_group_name + + implicit none + private + + ! !PUBLIC MEMBER FUNCTIONS + public :: shr_lnd2rof_tracers_readnl ! Read namelist + + character(len=*), parameter :: & + u_FILE_u=__FILE__ + +!==================================================================================== +CONTAINS +!==================================================================================== + + subroutine shr_lnd2rof_tracers_readnl(NLFilename, lnd2rof_tracer_list) + + ! input/output variables + character(len=*), intent(in) :: NLFilename ! Namelist filename + character(len=*), intent(out) :: lnd2rof_tracer_list ! Colon delimited string of liquid lnd2rof tracers + + !----- local ----- + type(ESMF_VM) :: vm + integer :: unitn ! namelist unit number + integer :: ierr ! error code + logical :: exists ! if file exists or not + integer :: rc + integer :: localpet + integer :: mpicom + integer :: logunit + character(len=CS) :: lnd2rof_tracers + character(*),parameter :: subName = '(shr_lnd2rof_tracers_readnl) ' + ! ------------------------------------------------------------------ + + namelist /lnd2rof_tracers_inparm/ lnd2rof_tracers + + !----------------------------------------------------------------------------- + ! Read namelist and figure out the lnd2rof_tracers field list to pass + ! First check if file exists and if not, n_lnd2rof_tracers will be zero + !----------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + !--- Open and read namelist --- + if ( len_trim(NLFilename) == 0 ) then + call shr_sys_abort( subName//'ERROR: nlfilename not set' ) + end if + call shr_log_getLogUnit(logunit) + + lnd2rof_tracers = ' ' + lnd2rof_tracer_list = ' ' + + call ESMF_VMGetCurrent(vm, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + call ESMF_VMGet(vm, localPet=localPet, mpiCommunicator=mpicom, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + if (localpet==0) then + inquire(file=trim(NLFileName), exist=exists) + if ( exists ) then + open(newunit=unitn, file=trim(NLFilename), status='old' ) + call shr_nl_find_group_name(unitn, 'lnd2rof_tracers_inparm', ierr) + if (ierr == 0) then + ! Note that if ierr /= 0, no namelist is present. + read(unitn, lnd2rof_tracers_inparm, iostat=ierr) + if (ierr > 0) then + call shr_sys_abort(trim(subName) //'problem of read of lnd2rof_tracers_inparm ') + endif + endif + close( unitn ) + end if + end if + call ESMF_VMBroadcast(vm, lnd2rof_tracers, CS, 0, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + if (lnd2rof_tracers /= ' ') then + lnd2rof_tracer_list = trim(lnd2rof_tracers) + end if + + end subroutine shr_lnd2rof_tracers_readnl + +end module shr_lnd2rof_tracers_mod diff --git a/streams/dshr_strdata_mod.F90 b/streams/dshr_strdata_mod.F90 index 4f04ab5f5..5c1ba395c 100644 --- a/streams/dshr_strdata_mod.F90 +++ b/streams/dshr_strdata_mod.F90 @@ -45,7 +45,7 @@ module dshr_strdata_mod use dshr_methods_mod , only : dshr_fldbun_getfldptr, dshr_fldbun_getfieldN, dshr_fldbun_fldchk, chkerr use dshr_methods_mod , only : dshr_fldbun_diagnose, dshr_fldbun_regrid, dshr_field_getfldptr use shr_sys_mod , only : shr_sys_abort - + use pio , only : file_desc_t, iosystem_desc_t, io_desc_t, var_desc_t use pio , only : pio_openfile, pio_closefile, pio_nowrite use pio , only : pio_seterrorhandling, pio_initdecomp, pio_freedecomp @@ -139,6 +139,8 @@ module dshr_strdata_mod real(r8), allocatable :: tavCoszen(:) ! cosz t-interp data end type shr_strdata_type + type(ESMF_Field) :: field_vector_dst ! needed for vector fields + real(r8) ,parameter :: deg2rad = SHR_CONST_PI/180.0_r8 character(*) ,parameter :: u_FILE_u = & __FILE__ @@ -880,7 +882,6 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) real(r8) ,pointer :: dataptr2d_lb(:,:)! pointer into field bundle real(r8) ,pointer :: dataptr2d_ub(:,:)! pointer into field bundle real(r8), pointer :: nu_coords(:) ! allocatable local element mesh lat and lons - real(r8), pointer :: nv_coords(:) ! allocatable local element mesh lat and lons real(r8), pointer :: data2d_src(:,:) ! pointer into field bundle real(r8), pointer :: data2d_dst(:,:) ! pointer into field bundle real(r8), pointer :: data_u_src(:) ! pointer into field bundle @@ -913,7 +914,6 @@ subroutine shr_strdata_advance(sdat, ymd, tod, logunit, istr, timers, rc) nullify(dataptr2d_ub) nullify(dataptr2d_lb) nullify(nu_coords) - nullify(nv_coords) nullify(data2d_src) nullify(data2d_dst) nullify(data_u_src) @@ -1459,7 +1459,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & ! local variables integer :: stream_nlev - type(ESMF_Field) :: field_dst, field_vector_dst + type(ESMF_Field) :: field_dst character(CX) :: currfile logical :: fileexists logical :: fileopen @@ -1485,7 +1485,7 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & integer :: lsize, n integer :: spatialDim, numOwnedElements integer :: pio_iovartype - real(r8), pointer :: nv_coords(:), nu_coords(:) + real(r8), pointer :: nu_coords(:) real(r8), pointer :: data_u_dst(:), data_v_dst(:) real(r8) :: lat, lon real(r8) :: sinlat, sinlon @@ -1509,7 +1509,6 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & nullify(dataptr2d) nullify(dataptr2d_src) nullify(dataptr2d_dst) - nullify(nv_coords) nullify(nu_coords) nullify(data_u_dst) nullify(data_v_dst) @@ -1890,10 +1889,6 @@ subroutine shr_strdata_readstrm(sdat, per_stream, stream, fldbun_data, & call ESMF_MeshGet(per_stream%stream_mesh, ownedElemCoords=nu_coords) if (chkerr(rc,__LINE__,u_FILE_u)) return - allocate(nv_coords(spatialDim*numOwnedElements)) - call ESMF_MeshGet(per_stream%stream_mesh, ownedElemCoords=nv_coords) - if (chkerr(rc,__LINE__,u_FILE_u)) return - do i=1,lsize dataptr(i) = dataptr2d_src(1,i) lon = nu_coords(2*i-1) @@ -1903,9 +1898,14 @@ 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 - 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 + + deallocate(nu_coords) + + if (.not. ESMF_FieldIsCreated(field_vector_dst)) then + 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 + end if if (.not. ESMF_FieldIsCreated(per_stream%field_stream_vector)) then call shr_log_error('ERROR: per_stream%field_stream_vector has not been created', rc=rc)