diff --git a/mediator/esmFldsExchange_nems_mod.F90 b/mediator/esmFldsExchange_nems_mod.F90 index 436232652..9fe5b70ba 100644 --- a/mediator/esmFldsExchange_nems_mod.F90 +++ b/mediator/esmFldsExchange_nems_mod.F90 @@ -37,6 +37,7 @@ subroutine esmFldsExchange_nems(gcomp, phase, rc) use esmFlds , only : addmap => med_fldList_AddMap use esmFlds , only : addmrg => med_fldList_AddMrg use esmflds , only : fldListTo, fldListFr, fldListMed_aoflux, fldListMed_ocnalb + use med_internalstate_mod , only : InternalState, mastertask, logunit ! input/output parameters: type(ESMF_GridComp) :: gcomp @@ -132,6 +133,39 @@ subroutine esmFldsExchange_nems(gcomp, phase, rc) deallocate(flds) end if + if (trim(coupling_mode) == 'nems_frac_aoflux' .or. trim(coupling_mode) == 'nems_frac_aoflux_sbs') then + allocate(flds(12)) + flds = (/'Sa_u ', 'Sa_v ', 'Sa_z ', 'Sa_tbot ', 'Sa_pbot ', & + 'Sa_pslv ', 'Sa_shum ', 'Sa_ptem ', 'Sa_dens ', 'Sa_u10m ', & + 'Sa_v10m ', 'Faxa_lwdn'/) + do n = 1,size(flds) + fldname = trim(flds(n)) + if (phase == 'advertise') then + if (is_local%wrap%comp_present(compatm) )then + call addfld(fldListFr(compatm)%flds, trim(fldname)) + end if + else + if ( fldchk(is_local%wrap%FBImp(compatm,compatm), trim(fldname), rc=rc)) then + call addmap(fldListFr(compatm)%flds, trim(fldname), compocn, maptype, 'one', 'unset') + end if + end if + end do + deallocate(flds) + + ! fields returned by the atm/ocn flux computation which are otherwise unadvertised + allocate(flds(13)) + flds = (/'So_tref ', 'So_qref ','So_u10 ', 'So_ustar ','So_ssq ', & + 'So_re ', 'So_duu10n','Faox_lwup', 'Faox_sen ','Faox_lat ', & + 'Faox_evap', 'Faox_taux','Faox_tauy'/) + do n = 1,size(flds) + fldname = trim(flds(n)) + if (phase == 'advertise') then + call addfld(fldListMed_aoflux%flds, trim(fldname)) + end if + end do + deallocate(flds) + end if + ! TODO: unused, but required to maintain B4B repro for mediator restarts; should be removed if (phase == 'advertise') then call addfld(fldListFr(compice)%flds, 'mean_sw_pen_to_ocn') @@ -215,6 +249,35 @@ subroutine esmFldsExchange_nems(gcomp, phase, rc) end if end if + ! to atm: unmerged from mediator, merge will be done under FV3/CCPP composite step + ! - zonal surface stress, meridional surface stress + ! - surface latent heat flux, + ! - surface sensible heat flux + ! - surface upward longwave heat flux + ! - evaporation water flux from water, not in the list do we need to send it to atm? + if (trim(coupling_mode) == 'nems_frac_aoflux') then + if (is_local%wrap%comp_present(compocn) .and. is_local%wrap%comp_present(compatm)) then + allocate(flds(5)) + flds = (/ 'lat ', 'sen ', 'lwup', 'taux', 'tauy' /) + if (phase == 'advertise') then + do n = 1,size(flds) + call addfld(fldListMed_aoflux%flds , 'Faox_'//trim(flds(n))) + call addfld(fldListTo(compatm)%flds, 'Faox_'//trim(flds(n))) + end do + else + do n = 1,size(flds) + if (fldchk(is_local%wrap%FBMed_aoflux_o, 'Faox_'//trim(flds(n)), rc=rc)) then + if (trim(is_local%wrap%aoflux_grid) == 'ogrid') then + call addmap(fldListMed_aoflux%flds, 'Faox_'//trim(flds(n)), compatm, maptype, 'ofrac', 'unset') + end if + call addmrg(fldListTo(compatm)%flds, 'Faox_'//trim(flds(n)), mrg_from=compmed, mrg_fld='Faox_'//trim(flds(n)), mrg_type='copy') + end if + end do + end if + deallocate(flds) + end if + end if + ! to atm: surface roughness length from wav if (phase == 'advertise') then if (is_local%wrap%comp_present(compwav) .and. is_local%wrap%comp_present(compatm)) then @@ -310,7 +373,8 @@ subroutine esmFldsExchange_nems(gcomp, phase, rc) end do deallocate(flds) - if (trim(coupling_mode) == 'nems_orig' .or. trim(coupling_mode) == 'nems_frac') then + if (trim(coupling_mode) == 'nems_orig' .or. trim(coupling_mode) == 'nems_frac' .or. & + trim(coupling_mode) == 'nems_frac_aoflux_sbs') then ! to ocn: merge surface stress (custom merge calculation in med_phases_prep_ocn) allocate(oflds(2)) allocate(aflds(2)) @@ -379,7 +443,7 @@ subroutine esmFldsExchange_nems(gcomp, phase, rc) call addmap(fldListFr(compatm)%flds, 'Faxa_lat', compocn, mapconsf_aofrac, 'aofrac', 'unset') end if end if - else + else if (trim(coupling_mode) == 'nems_orig_data' .or. trim(coupling_mode) == 'nems_frac_aoflux') then ! nems_orig_data ! to ocn: surface stress from mediator and ice stress via auto merge allocate(flds(2)) diff --git a/mediator/med.F90 b/mediator/med.F90 index 92be267e1..ac92f2638 100644 --- a/mediator/med.F90 +++ b/mediator/med.F90 @@ -43,7 +43,7 @@ module MED use med_internalstate_mod , only : med_internalstate_defaultmasks, logunit, mastertask use med_internalstate_mod , only : ncomps, compname use med_internalstate_mod , only : compmed, compatm, compocn, compice, complnd, comprof, compwav, compglc - use med_internalstate_mod , only : coupling_mode + use med_internalstate_mod , only : coupling_mode, aoflux_code, aoflux_ccpp_suite use esmFlds , only : fldListMed_ocnalb use esmFlds , only : med_fldList_GetNumFlds, med_fldList_GetFldNames, med_fldList_GetFldInfo use esmFlds , only : med_fldList_Document_Mapping, med_fldList_Document_Merging @@ -762,6 +762,36 @@ subroutine InitializeIPDv03p1(gcomp, importState, exportState, clock, rc) end if is_local%wrap%aoflux_grid = trim(cvalue) + ! Determine aoflux scheme that will be used to compute atmosphere-ocean fluxes [cesm|ccpp] + ! TODO: If ccpp is not available it will be always run in cesm mode independent from aoflux_code option + call NUOPC_CompAttributeGet(gcomp, name='aoflux_code', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (.not. isPresent .and. .not. isSet) then + cvalue = 'cesm' + end if + aoflux_code = trim(cvalue) + if (mastertask) then + write(logunit,*) '========================================================' + write(logunit,'(a)')trim(subname)//' Mediator aoflux scheme is '//trim(aoflux_code) + write(logunit,*) '========================================================' + end if + + ! Determine CCPP suite if aoflux scheme set to 'ccpp' + if (trim(aoflux_code) == 'ccpp') then + call NUOPC_CompAttributeGet(gcomp, name='aoflux_ccpp_suite', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (.not. isPresent .and. .not. isSet) then + call ESMF_LogWrite("aoflux_ccpp_suite need to be provided when aoflux_code is set to 'ccpp'", ESMF_LOGMSG_INFO) + call ESMF_Finalize(endflag=ESMF_END_ABORT) + end if + aoflux_ccpp_suite = trim(cvalue) + if (mastertask) then + write(logunit,*) '========================================================' + write(logunit,'(a)')trim(subname)//' Mediator aoflux CCPP suite is '//trim(aoflux_ccpp_suite) + write(logunit,*) '========================================================' + end if + end if + !------------------ ! Initialize mediator flds !------------------ diff --git a/mediator/med_fraction_mod.F90 b/mediator/med_fraction_mod.F90 index 5b7944c7d..521ba0007 100644 --- a/mediator/med_fraction_mod.F90 +++ b/mediator/med_fraction_mod.F90 @@ -367,7 +367,10 @@ subroutine med_fraction_init(gcomp, rc) if (chkerr(rc,__LINE__,u_FILE_u)) return ! Set 'aofrac' in FBfrac(compatm) - if (trim(coupling_mode) == 'nems_orig' .or. trim(coupling_mode) == 'nems_frac') then + if (trim(coupling_mode) == 'nems_orig' .or. & + trim(coupling_mode) == 'nems_frac' .or. & + trim(coupling_mode) == 'nems_frac_aoflux' .or. & + trim(coupling_mode) == 'nems_frac_aoflux_sbs') then call fldbun_getdata1d(is_local%wrap%FBImp(compatm,compatm), 'Sa_ofrac', Sa_ofrac, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call fldbun_getdata1d(is_local%wrap%FBFrac(compatm), 'aofrac', aofrac, rc) @@ -789,7 +792,10 @@ subroutine med_fraction_set(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if ! Set 'aofrac' from FBImp(compatm) to FBfrac(compatm) - if (trim(coupling_mode) == 'nems_orig' .or. trim(coupling_mode) == 'nems_frac') then + if (trim(coupling_mode) == 'nems_orig' .or. & + trim(coupling_mode) == 'nems_frac' .or. & + trim(coupling_mode) == 'nems_frac_aoflux' .or. & + trim(coupling_mode) == 'nems_frac_aoflux_sbs') then call fldbun_getdata1d(is_local%wrap%FBImp(compatm,compatm), 'Sa_ofrac', Sa_ofrac, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call fldbun_getdata1d(is_local%wrap%FBFrac(compatm), 'aofrac', aofrac, rc) diff --git a/mediator/med_internalstate_mod.F90 b/mediator/med_internalstate_mod.F90 index b9b61e85e..99baa2fe1 100644 --- a/mediator/med_internalstate_mod.F90 +++ b/mediator/med_internalstate_mod.F90 @@ -5,7 +5,7 @@ module med_internalstate_mod !----------------------------------------------------------------------------- use ESMF , only : ESMF_RouteHandle, ESMF_FieldBundle, ESMF_State, ESMF_Field, ESMF_VM - use ESMF , only : ESMF_GridComp, ESMF_MAXSTR, ESMF_LOGMSG_INFO, ESMF_LOGWRITE + use ESMF , only : ESMF_GridComp, ESMF_Mesh, ESMF_MAXSTR, ESMF_LOGMSG_INFO, ESMF_LOGWRITE use med_kind_mod , only : CX=>SHR_KIND_CX, CS=>SHR_KIND_CS, CL=>SHR_KIND_CL, R8=>SHR_KIND_R8 use med_utils_mod, only : chkerr => med_utils_ChkErr @@ -47,7 +47,13 @@ module med_internalstate_mod character(len=CS), public :: glc_name = '' ! Coupling mode - character(len=CS), public :: coupling_mode ! valid values are [cesm,nems_orig,nems_frac,nems_orig_data,hafs] + character(len=CS), public :: coupling_mode ! valid values are [cesm,nems_orig,nems_frac,nems_orig_data,hafs,nems_frac_aoflux,nems_frac_aoflux_sbs] + + ! Atmosphere-ocean flux algorithm + character(len=CS), public :: aoflux_code ! valid values are [cesm,ccpp] + + ! Atmosphere-ocean CCPP suite name + character(len=CL), public :: aoflux_ccpp_suite ! Default src and destination masks for mapping integer, public, allocatable :: defaultMasks(:,:) @@ -153,6 +159,7 @@ module med_internalstate_mod ! Mediator field bundles and other info for atm/ocn flux computation character(len=CS) :: aoflux_grid ! 'ogrid', 'agrid' or 'xgrid' + type(ESMF_Mesh) :: aoflux_mesh ! Mesh used for atm/ocn flux computation type(ESMF_FieldBundle) :: FBMed_aoflux_a ! Ocn/Atm flux output fields on atm grid type(ESMF_FieldBundle) :: FBMed_aoflux_o ! Ocn/Atm flux output fields on ocn grid type(packed_data_type), pointer :: packed_data_aoflux_o2a(:) ! packed data for mapping ocn->atm diff --git a/mediator/med_io_mod.F90 b/mediator/med_io_mod.F90 index 1a1541475..6d9b8d2f6 100644 --- a/mediator/med_io_mod.F90 +++ b/mediator/med_io_mod.F90 @@ -1111,12 +1111,14 @@ subroutine med_io_write_FB(filename, FB, whead, wdata, nx, ny, nt, & call pio_write_darray(io_file(lfile_ind), varid, iodesc, fldptr2(n,:), rcode, fillval=lfillvalue) end if end do - else if (rank == 1) then + else if (rank == 1 .or. rank == 0) then name1 = trim(lpre)//'_'//trim(itemc) rcode = pio_inq_varid(io_file(lfile_ind), trim(name1), varid) call pio_setframe(io_file(lfile_ind),varid,frame) + ! fix for writing data on exchange grid, which has no data in some PETs + if (rank == 0) nullify(fldptr1) call pio_write_darray(io_file(lfile_ind), varid, iodesc, fldptr1, rcode, fillval=lfillvalue) - end if ! end if rank is 2 or 1 + end if ! end if rank is 2 or 1 or 0 end if ! end if not "hgt" end do ! end loop over fields in FB diff --git a/mediator/med_phases_aofluxes_mod.F90 b/mediator/med_phases_aofluxes_mod.F90 index 794b84293..582a622a4 100644 --- a/mediator/med_phases_aofluxes_mod.F90 +++ b/mediator/med_phases_aofluxes_mod.F90 @@ -11,25 +11,34 @@ module med_phases_aofluxes_mod ! map aoflux_out from xgrid to both atm and ocn grid ! -------------------------------------------------------------------------- - use ESMF , only : ESMF_GridComp, ESMF_GridCompGet + use ESMF , only : operator(/=) + use ESMF , only : ESMF_GridComp, ESMF_GridCompGet, ESMF_CoordSys_Flag use ESMF , only : ESMF_Field, ESMF_FieldGet, ESMF_FieldCreate, ESMF_FieldIsCreated, ESMF_FieldDestroy - use ESMF , only : ESMF_FieldBundle, ESMF_FieldBundleGet + use ESMF , only : ESMF_FieldBundle, ESMF_FieldBundleGet, ESMF_FieldRegridGetArea use ESMF , only : ESMF_FieldBundleCreate, ESMF_FieldBundleAdd use ESMF , only : ESMF_RouteHandle, ESMF_FieldRegrid, ESMF_FieldRegridStore use ESMF , only : ESMF_REGRIDMETHOD_CONSERVE_2ND, ESMF_REGRIDMETHOD_CONSERVE - use ESMF , only : ESMF_REGRIDMETHOD_PATCH, ESMF_REGRIDMETHOD_BILINEAR + use ESMF , only : ESMF_REGRIDMETHOD_PATCH, ESMF_REGRIDMETHOD_BILINEAR, ESMF_COORDSYS_CART use ESMF , only : ESMF_TERMORDER_SRCSEQ, ESMF_REGION_TOTAL, ESMF_MESHLOC_ELEMENT, ESMF_MAXSTR use ESMF , only : ESMF_XGRIDSIDE_B, ESMF_XGRIDSIDE_A, ESMF_END_ABORT, ESMF_LOGERR_PASSTHRU use ESMF , only : ESMF_Mesh, ESMF_MeshGet, ESMF_XGrid, ESMF_XGridCreate, ESMF_TYPEKIND_R8 use ESMF , only : ESMF_LogWrite, ESMF_LOGMSG_INFO, ESMF_SUCCESS, ESMF_LOGMSG_ERROR, ESMF_FAILURE use ESMF , only : ESMF_Finalize, ESMF_LogFoundError + use ESMF , only : ESMF_XGridGet, ESMF_MeshCreate, ESMF_MeshWrite, ESMF_KIND_R8 use med_kind_mod , only : CX=>SHR_KIND_CX, CS=>SHR_KIND_CS, CL=>SHR_KIND_CL, R8=>SHR_KIND_R8 use med_internalstate_mod , only : InternalState, mastertask, logunit - use med_internalstate_mod , only : compatm, compocn, coupling_mode, mapconsd, mapconsf, mapfcopy + use med_internalstate_mod , only : compatm, compocn, coupling_mode, aoflux_code, mapconsd, mapconsf, mapfcopy use med_constants_mod , only : dbug_flag => med_constants_dbug_flag use med_utils_mod , only : memcheck => med_memcheck use med_utils_mod , only : chkerr => med_utils_chkerr use perf_mod , only : t_startf, t_stopf +#ifndef CESMCOUPLED + use ufs_const_mod , only : rearth => SHR_CONST_REARTH + use ufs_const_mod , only : pi => SHR_CONST_PI +#else + use shr_const_mod , only : rearth => SHR_CONST_REARTH + use shr_const_mod , only : pi => SHR_CONST_PI +#endif implicit none private @@ -105,18 +114,23 @@ module med_phases_aofluxes_mod real(R8) , pointer :: zbot (:) => null() ! atm level height real(R8) , pointer :: ubot (:) => null() ! atm velocity, zonal real(R8) , pointer :: vbot (:) => null() ! atm velocity, meridional + real(R8) , pointer :: usfc (:) => null() ! atm surface velocity, zonal + real(R8) , pointer :: vsfc (:) => null() ! atm surface velocity, meridional real(R8) , pointer :: thbot (:) => null() ! atm potential T real(R8) , pointer :: shum (:) => null() ! atm specific humidity real(R8) , pointer :: pbot (:) => null() ! atm bottom pressure + real(R8) , pointer :: psfc (:) => null() ! atm surface pressure real(R8) , pointer :: dens (:) => null() ! atm bottom density real(R8) , pointer :: tbot (:) => null() ! atm bottom surface T real(R8) , pointer :: shum_16O (:) => null() ! atm H2O tracer real(R8) , pointer :: shum_HDO (:) => null() ! atm HDO tracer real(R8) , pointer :: shum_18O (:) => null() ! atm H218O tracer - ! local size and computational mask: on aoflux grid + real(R8) , pointer :: lwdn (:) => null() ! atm downward longwave heat flux + ! local size and computational mask and area: on aoflux grid integer :: lsize ! local size integer , pointer :: mask (:) => null() ! integer ocn domain mask: 0 <=> inactive cell real(R8) , pointer :: rmask (:) => null() ! real ocn domain mask: 0 <=> inactive cell + real(R8) , pointer :: garea (:) => null() ! atm grid area end type aoflux_in_type type aoflux_out_type @@ -284,6 +298,7 @@ subroutine med_phases_aofluxes_run(gcomp, rc) else aoflux_created = .false. end if + ! Now set first_call to .false. first_call = .false. end if @@ -480,6 +495,10 @@ subroutine med_aofluxes_init_ogrid(gcomp, aoflux_in, aoflux_out, rc) character(len=CX) :: tmpstr integer :: lsize integer :: fieldcount + type(ESMF_Field) :: lfield + type(ESMF_Mesh) :: lmesh + real(R8), pointer :: garea(:) => null() + type(ESMF_CoordSys_Flag) :: coordSys character(len=*),parameter :: subname=' (med_aofluxes_init_ocngrid) ' !----------------------------------------------------------------------- @@ -515,6 +534,27 @@ subroutine med_aofluxes_init_ogrid(gcomp, aoflux_in, aoflux_out, rc) write(tmpstr,'(i12,g22.12,i12)') lsize,sum(aoflux_in%rmask),sum(aoflux_in%mask) call ESMF_LogWrite(trim(subname)//" : maskB= "//trim(tmpstr), ESMF_LOGMSG_INFO) + ! ------------------------ + ! setup grid area + ! ------------------------ + + call ESMF_FieldBundleGet(is_local%wrap%FBArea(compocn), 'area', field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(aoflux_in%garea(lsize)) + call ESMF_FieldGet(lfield, farrayPtr=garea, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(lfield, mesh=lmesh, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + is_local%wrap%aoflux_mesh = ESMF_MeshCreate(lmesh, rc=rc) + call ESMF_MeshGet(lmesh, coordSys=coordSys, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (coordSys /= ESMF_COORDSYS_CART) then + ! Convert square radians to square meters + aoflux_in%garea(:) = garea(:)*(rearth**2) + else + aoflux_in%garea(:) = garea(:) + end if + ! ------------------------ ! create packed mapping from ocn->atm if aoflux_grid is ocn ! ------------------------ @@ -565,6 +605,10 @@ subroutine med_aofluxes_init_agrid(gcomp, aoflux_in, aoflux_out, rc) type(ESMF_Mesh) :: mesh_src type(ESMF_Mesh) :: mesh_dst integer :: maptype + type(ESMF_Field) :: lfield + type(ESMF_Mesh) :: lmesh + real(R8), pointer :: garea(:) => null() + type(ESMF_CoordSys_Flag) :: coordSys character(len=*),parameter :: subname=' (med_aofluxes_init_atmgrid) ' !----------------------------------------------------------------------- @@ -641,6 +685,27 @@ subroutine med_aofluxes_init_agrid(gcomp, aoflux_in, aoflux_out, rc) end if enddo + ! ------------------------ + ! setup grid area + ! ------------------------ + + call ESMF_FieldBundleGet(is_local%wrap%FBArea(compatm), 'area', field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + allocate(aoflux_in%garea(lsize)) + call ESMF_FieldGet(lfield, farrayPtr=garea, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldGet(lfield, mesh=lmesh, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + is_local%wrap%aoflux_mesh = ESMF_MeshCreate(lmesh, rc=rc) + call ESMF_MeshGet(lmesh, coordSys=coordSys, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (coordSys /= ESMF_COORDSYS_CART) then + ! Convert square radians to square meters + aoflux_in%garea(:) = garea(:)*(rearth**2) + else + aoflux_in%garea(:) = garea(:) + end if + ! ------------------------ ! set one normalization for ocn-atm mapping if needed ! ------------------------ @@ -695,11 +760,14 @@ subroutine med_aofluxes_init_xgrid(gcomp, aoflux_in, aoflux_out, rc) type(ESMF_Field) :: field_a type(ESMF_Field) :: field_o type(ESMF_Field) :: lfield - integer :: elementCount + type(ESMF_Mesh) :: lmesh type(ESMF_Mesh) :: ocn_mesh type(ESMF_Mesh) :: atm_mesh + type(ESMF_Mesh) :: xch_mesh real(r8), pointer :: dataptr(:) integer :: fieldcount + type(ESMF_CoordSys_Flag) :: coordSys + real(ESMF_KIND_R8) ,allocatable :: garea(:) character(ESMF_MAXSTR),allocatable :: fieldNameList(:) character(len=*),parameter :: subname=' (med_aofluxes_init_xgrid) ' !----------------------------------------------------------------------- @@ -732,6 +800,17 @@ subroutine med_aofluxes_init_xgrid(gcomp, aoflux_in, aoflux_out, rc) storeOverlay=.true., rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return + ! write meshes for debug purpose + if (dbug_flag > 20) then + call ESMF_MeshWrite(atm_mesh, filename="atm_mesh", rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_MeshWrite(ocn_mesh, filename="ocn_mesh", rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_XGridGet(xgrid, mesh=xch_mesh, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_MeshWrite(xch_mesh, filename="xch_mesh", rc=rc) + end if + ! create module field on exchange grid and set its initial value to 1 field_x = ESMF_FieldCreate(xgrid, typekind=ESMF_TYPEKIND_R8, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return @@ -789,12 +868,14 @@ subroutine med_aofluxes_init_xgrid(gcomp, aoflux_in, aoflux_out, rc) call ESMF_FieldRegridStore(xgrid, field_a, field_x, routehandle=rh_agrid2xgrid_2ndord, & regridmethod=ESMF_REGRIDMETHOD_CONSERVE_2ND, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_FieldRegridStore(field_a, field_x, routehandle=rh_agrid2xgrid_bilinr, & - regridmethod=ESMF_REGRIDMETHOD_BILINEAR, dstMaskValues=(/0/), rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return - call ESMF_FieldRegridStore(field_a, field_x, routehandle=rh_agrid2xgrid_patch, & - regridmethod=ESMF_REGRIDMETHOD_PATCH, dstMaskValues=(/0/), rc=rc) - if (chkerr(rc,__LINE__,u_FILE_u)) return + if (trim(coupling_mode) == 'cesm') then + call ESMF_FieldRegridStore(field_a, field_x, routehandle=rh_agrid2xgrid_bilinr, & + regridmethod=ESMF_REGRIDMETHOD_BILINEAR, dstMaskValues=(/0/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldRegridStore(field_a, field_x, routehandle=rh_agrid2xgrid_patch, & + regridmethod=ESMF_REGRIDMETHOD_PATCH, dstMaskValues=(/0/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if ! create xgrid->zgrid route handle call ESMF_FieldRegridStore(xgrid, field_x, field_a, routehandle=rh_xgrid2agrid, rc=rc) @@ -832,6 +913,23 @@ subroutine med_aofluxes_init_xgrid(gcomp, aoflux_in, aoflux_out, rc) allocate(aoflux_in%mask(lsize)) aoflux_in%mask(:) = 1 + ! ------------------------ + ! setup grid area + ! ------------------------ + + allocate(garea(lsize)) + allocate(aoflux_in%garea(lsize)) + call ESMF_XGridGet(xgrid, mesh=lmesh, coordSys=coordSys, area=garea, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + is_local%wrap%aoflux_mesh = ESMF_MeshCreate(lmesh, rc=rc) + if (coordSys /= ESMF_COORDSYS_CART) then + ! Convert square radians to square meters + aoflux_in%garea(:) = garea(:)*(rearth**2) + else + aoflux_in%garea(:) = garea(:) + end if + deallocate(garea) + end subroutine med_aofluxes_init_xgrid !=============================================================================== @@ -854,6 +952,9 @@ subroutine med_aofluxes_update(gcomp, aoflux_in, aoflux_out, rc) #else use flux_atmocn_mod, only : flux_atmocn #endif +#ifdef UFS_AOFLUX + use flux_atmocn_ccpp_mod, only : flux_atmocn_ccpp +#endif ! Arguments type(ESMF_GridComp) :: gcomp @@ -862,13 +963,18 @@ subroutine med_aofluxes_update(gcomp, aoflux_in, aoflux_out, rc) integer , intent(out) :: rc ! ! Local variables - type(InternalState) :: is_local - type(ESMF_Field) :: field_src - type(ESMF_Field) :: field_dst - integer :: n,i,nf ! indices - real(r8), pointer :: data_normdst(:) - real(r8), pointer :: data_dst(:) - character(*),parameter :: subName = '(med_aofluxes_update) ' + type(InternalState) :: is_local + type(ESMF_Field) :: field_src + type(ESMF_Field) :: field_dst + integer :: n,i,nf ! indices + real(r8), pointer :: data_normdst(:) + real(r8), pointer :: data_dst(:) + integer :: maptype + real(r8), parameter :: qmin = 1.0e-8_r8 + real(r8), parameter :: p0 = 100000.0_r8 ! reference pressure in Pa + real(r8), parameter :: rcp = 0.286_r8 ! gas constant of air / specific heat capacity at a constant pressure + real(r8), parameter :: rdair = 287.058_r8 ! dry air gas constant in J/K/kg + character(*),parameter :: subName = '(med_aofluxes_update) ' !----------------------------------------------------------------------- rc = ESMF_SUCCESS @@ -908,15 +1014,29 @@ subroutine med_aofluxes_update(gcomp, aoflux_in, aoflux_out, rc) ! Note pbot, tbot and shum have already been mapped or are available on the aoflux grid if (compute_atm_thbot) then do n = 1,aoflux_in%lsize - if (aoflux_in%mask(n) /= 0._r8) then - aoflux_in%thbot(n) = aoflux_in%tbot(n)*((100000._R8/aoflux_in%pbot(n))**0.286_R8) + if (aoflux_in%mask(n) /= 0.0_r8) then + aoflux_in%thbot(n) = aoflux_in%tbot(n)*((p0/aoflux_in%pbot(n))**rcp) end if end do end if if (compute_atm_dens) then + if (trim(aoflux_code) == 'ccpp' .and. & + (trim(coupling_mode) == 'nems_frac_aoflux' .or. trim(coupling_mode) == 'nems_frac_aoflux_sbs')) then + ! Add limiting factor to humidity to be consistent with UFS aoflux calculation + do n = 1,aoflux_in%lsize + if (aoflux_in%mask(n) /= 0.0_r8) then + aoflux_in%shum(n) = max(aoflux_in%shum(n), qmin) + end if + end do + ! Use pbot as psfc for the initial pass since psfc provided by UFS atm is zero + if (maxval(aoflux_in%psfc, mask=(aoflux_in%mask/= 0.0_r8)) < 100.0_r8) then + aoflux_in%psfc(:) = aoflux_in%pbot(:) + call ESMF_LogWrite(trim(subname)//" : using pbot as psfc for initial pass!", ESMF_LOGMSG_INFO) + end if + end if do n = 1,aoflux_in%lsize - if (aoflux_in%mask(n) /= 0._r8) then - aoflux_in%dens(n) = aoflux_in%pbot(n)/(287.058_R8*(1._R8 + 0.608_R8*aoflux_in%shum(n))*aoflux_in%tbot(n)) + if (aoflux_in%mask(n) /= 0.0_r8) then + aoflux_in%dens(n) = aoflux_in%pbot(n)/(rdair*(1.0_r8 + 0.608_r8*aoflux_in%shum(n))*aoflux_in%tbot(n)) end if end do end if @@ -926,7 +1046,6 @@ subroutine med_aofluxes_update(gcomp, aoflux_in, aoflux_out, rc) !---------------------------------- #ifdef CESMCOUPLED - call flux_atmocn (logunit=logunit, & nMax=aoflux_in%lsize, & zbot=aoflux_in%zbot, ubot=aoflux_in%ubot, vbot=aoflux_in%vbot, thbot=aoflux_in%thbot, qbot=aoflux_in%shum, & @@ -942,15 +1061,30 @@ subroutine med_aofluxes_update(gcomp, aoflux_in, aoflux_out, rc) missval=0.0_r8) #else - - call flux_atmocn (logunit=logunit, & - nMax=aoflux_in%lsize, mask=aoflux_in%mask, & - zbot=aoflux_in%zbot, ubot=aoflux_in%ubot, vbot=aoflux_in%vbot, thbot=aoflux_in%thbot, qbot=aoflux_in%shum, & - rbot=aoflux_in%dens, tbot=aoflux_in%tbot, us=aoflux_in%uocn, vs=aoflux_in%vocn, ts=aoflux_in%tocn, & - ocn_surface_flux_scheme=ocn_surface_flux_scheme, & - sen=aoflux_out%sen, lat=aoflux_out%lat, lwup=aoflux_out%lwup, evap=aoflux_out%evap, & - taux=aoflux_out%taux, tauy=aoflux_out%tauy, tref=aoflux_out%tref, qref=aoflux_out%qref, & - duu10n=aoflux_out%duu10n, missval=0.0_r8) +#ifdef UFS_AOFLUX + if (trim(aoflux_code) == 'ccpp') then + call flux_atmocn_ccpp(gcomp=gcomp, mastertask=mastertask, logunit=logunit, & + nMax=aoflux_in%lsize, psfc=aoflux_in%psfc, & + pbot=aoflux_in%pbot, tbot=aoflux_in%tbot, qbot=aoflux_in%shum, lwdn=aoflux_in%lwdn, & + zbot=aoflux_in%zbot, garea=aoflux_in%garea, ubot=aoflux_in%ubot, usfc=aoflux_in%usfc, vbot=aoflux_in%vbot, & + vsfc=aoflux_in%vsfc, rbot=aoflux_in%dens, ts=aoflux_in%tocn, mask=aoflux_in%mask, & + sen=aoflux_out%sen, lat=aoflux_out%lat, lwup=aoflux_out%lwup, evp=aoflux_out%evap, & + taux=aoflux_out%taux, tauy=aoflux_out%tauy, tref=aoflux_out%tref, qref=aoflux_out%qref, & + duu10n=aoflux_out%duu10n, ustar_sv=aoflux_out%ustar, re_sv=aoflux_out%re, ssq_sv=aoflux_out%ssq, & + missval=0.0_r8) + else +#endif + call flux_atmocn (logunit=logunit, & + nMax=aoflux_in%lsize, mask=aoflux_in%mask, & + zbot=aoflux_in%zbot, ubot=aoflux_in%ubot, vbot=aoflux_in%vbot, thbot=aoflux_in%thbot, qbot=aoflux_in%shum, & + rbot=aoflux_in%dens, tbot=aoflux_in%tbot, us=aoflux_in%uocn, vs=aoflux_in%vocn, ts=aoflux_in%tocn, & + ocn_surface_flux_scheme=ocn_surface_flux_scheme, & + sen=aoflux_out%sen, lat=aoflux_out%lat, lwup=aoflux_out%lwup, evap=aoflux_out%evap, & + taux=aoflux_out%taux, tauy=aoflux_out%tauy, tref=aoflux_out%tref, qref=aoflux_out%qref, & + duu10n=aoflux_out%duu10n, missval=0.0_r8) +#ifdef UFS_AOFLUX + end if +#endif #endif @@ -1008,7 +1142,7 @@ subroutine med_aofluxes_map_ogrid2agrid_input(gcomp, rc) real(r8), pointer :: data_dst(:) integer :: nf,n integer :: maptype - character(*),parameter :: subName = '(med_aofluxes_map_ogrid2agrid_output) ' + character(*),parameter :: subName = '(med_aofluxes_map_ogrid2agrid_input) ' !----------------------------------------------------------------------- rc = ESMF_SUCCESS @@ -1043,6 +1177,7 @@ subroutine med_aofluxes_map_ogrid2agrid_input(gcomp, rc) ! Map ocn->atm conservatively without fractions call ESMF_FieldRegrid(field_src, field_dst, routehandle=is_local%wrap%RH(compocn,compatm, maptype), & termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return ! Normalization of map by 'one' if (maptype /= mapfcopy) then @@ -1076,7 +1211,7 @@ subroutine med_aofluxes_map_agrid2xgrid_input(gcomp, rc) type(ESMF_Field) :: field_src type(ESMF_Field) :: field_dst integer :: nf - character(*),parameter :: subName = '(med_aofluxes_map_ogrid2agrid_output) ' + character(*),parameter :: subName = '(med_aofluxes_map_agrid2xgrid_input) ' !----------------------------------------------------------------------- rc = ESMF_SUCCESS @@ -1096,11 +1231,23 @@ subroutine med_aofluxes_map_agrid2xgrid_input(gcomp, rc) ! Map atm->xgrid if (trim(fldnames_atm_in(nf)) == 'Sa_u' .or. (trim(fldnames_atm_in(nf)) == 'Sa_v')) then - call ESMF_FieldRegrid(field_src, field_dst, routehandle=rh_agrid2xgrid_patch, & - termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + if (trim(coupling_mode) == 'cesm') then + call ESMF_FieldRegrid(field_src, field_dst, routehandle=rh_agrid2xgrid_patch, & + termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + else + call ESMF_FieldRegrid(field_src, field_dst, routehandle=rh_agrid2xgrid_2ndord, & + termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + end if + if (chkerr(rc,__LINE__,u_FILE_u)) return else - call ESMF_FieldRegrid(field_src, field_dst, routehandle=rh_agrid2xgrid_bilinr, & - termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + if (trim(coupling_mode) == 'cesm') then + call ESMF_FieldRegrid(field_src, field_dst, routehandle=rh_agrid2xgrid_bilinr, & + termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + else + call ESMF_FieldRegrid(field_src, field_dst, routehandle=rh_agrid2xgrid, & + termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + end if + if (chkerr(rc,__LINE__,u_FILE_u)) return end if if (chkerr(rc,__LINE__,u_FILE_u)) return end do @@ -1121,7 +1268,7 @@ subroutine med_aofluxes_map_ogrid2xgrid_input(gcomp, rc) type(ESMF_Field) :: field_src type(ESMF_Field) :: field_dst integer :: nf - character(*),parameter :: subName = '(med_aofluxes_map_ogrid2agrid_output) ' + character(*),parameter :: subName = '(med_aofluxes_map_ogrid2xgrid_input) ' !----------------------------------------------------------------------- rc = ESMF_SUCCESS @@ -1402,6 +1549,16 @@ subroutine set_aoflux_in_pointers(fldbun_a, fldbun_o, aoflux_in, lsize, xgrid, r if (chkerr(rc,__LINE__,u_FILE_u)) return end if + ! extra fields for nems_frac_aoflux + if (trim(coupling_mode) == 'nems_frac_aoflux' .or. trim(coupling_mode) == 'nems_frac_aoflux_sbs') then + call fldbun_getfldptr(fldbun_a, 'Sa_u10m', aoflux_in%usfc, xgrid=xgrid, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call fldbun_getfldptr(fldbun_a, 'Sa_v10m', aoflux_in%vsfc, xgrid=xgrid, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call fldbun_getfldptr(fldbun_a, 'Faxa_lwdn', aoflux_in%lwdn, xgrid=xgrid, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if + ! bottom level potential temperature will need to be computed if not received from the atm if (compute_atm_thbot) then allocate(aoflux_in%thbot(lsize)) @@ -1422,6 +1579,10 @@ subroutine set_aoflux_in_pointers(fldbun_a, fldbun_o, aoflux_in, lsize, xgrid, r if (compute_atm_dens .or. compute_atm_thbot) then call fldbun_getfldptr(fldbun_a, 'Sa_pbot', aoflux_in%pbot, xgrid=xgrid, rc=rc) if (chkerr(rc,__LINE__,u_FILE_u)) return + if (trim(coupling_mode) == 'nems_frac_aoflux' .or. trim(coupling_mode) == 'nems_frac_aoflux_sbs') then + call fldbun_getfldptr(fldbun_a, 'Sa_pslv', aoflux_in%psfc, xgrid=xgrid, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end if end if if (flds_wiso) then diff --git a/mediator/med_phases_prep_atm_mod.F90 b/mediator/med_phases_prep_atm_mod.F90 index 485cdaf9b..8d41adbb8 100644 --- a/mediator/med_phases_prep_atm_mod.F90 +++ b/mediator/med_phases_prep_atm_mod.F90 @@ -113,7 +113,10 @@ subroutine med_phases_prep_atm(gcomp, rc) !--------------------------------------- !--- map atm/ocn fluxes from ocn to atm grid if appropriate !--------------------------------------- - if (trim(coupling_mode) == 'cesm' .or. trim(coupling_mode) == 'hafs') then + if (trim(coupling_mode) == 'cesm' .or. & + trim(coupling_mode) == 'hafs' .or. & + trim(coupling_mode) == 'nems_frac_aoflux' .or. & + trim(coupling_mode) == 'nems_frac_aoflux_sbs') then if (is_local%wrap%aoflux_grid == 'ogrid') then call med_aofluxes_map_ogrid2agrid_output(gcomp, rc) if (chkerr(rc,__LINE__,u_FILE_u)) return @@ -128,7 +131,9 @@ subroutine med_phases_prep_atm(gcomp, rc) !--------------------------------------- !--- merge all fields to atm !--------------------------------------- - if (trim(coupling_mode) == 'cesm' .or. trim(coupling_mode) == 'hafs') then + if (trim(coupling_mode) == 'cesm' .or. & + trim(coupling_mode) == 'nems_frac_aoflux' .or. & + trim(coupling_mode) == 'hafs') then call med_merge_auto(& is_local%wrap%med_coupling_active(:,compatm), & is_local%wrap%FBExp(compatm), & @@ -138,7 +143,9 @@ subroutine med_phases_prep_atm(gcomp, rc) FBMed1=is_local%wrap%FBMed_ocnalb_a, & FBMed2=is_local%wrap%FBMed_aoflux_a, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - else if (trim(coupling_mode) == 'nems_frac' .or. trim(coupling_mode) == 'nems_orig') then + else if (trim(coupling_mode) == 'nems_frac' .or. & + trim(coupling_mode) == 'nems_orig' .or. & + trim(coupling_mode) == 'nems_frac_aoflux_sbs') then call med_merge_auto(& is_local%wrap%med_coupling_active(:,compatm), & is_local%wrap%FBExp(compatm), & diff --git a/mediator/med_phases_prep_ocn_mod.F90 b/mediator/med_phases_prep_ocn_mod.F90 index de4599ffb..35208a109 100644 --- a/mediator/med_phases_prep_ocn_mod.F90 +++ b/mediator/med_phases_prep_ocn_mod.F90 @@ -117,6 +117,7 @@ subroutine med_phases_prep_ocn_accum(gcomp, rc) ! auto merges to ocn if ( trim(coupling_mode) == 'cesm' .or. & trim(coupling_mode) == 'nems_orig_data' .or. & + trim(coupling_mode) == 'nems_frac_aoflux' .or. & trim(coupling_mode) == 'hafs') then call med_merge_auto(& is_local%wrap%med_coupling_active(:,compocn), & @@ -126,7 +127,9 @@ subroutine med_phases_prep_ocn_accum(gcomp, rc) fldListTo(compocn), & FBMed1=is_local%wrap%FBMed_aoflux_o, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - else if (trim(coupling_mode) == 'nems_frac' .or. trim(coupling_mode) == 'nems_orig') then + else if (trim(coupling_mode) == 'nems_frac' .or. & + trim(coupling_mode) == 'nems_orig' .or. & + trim(coupling_mode) == 'nems_frac_aoflux_sbs') then call med_merge_auto(& is_local%wrap%med_coupling_active(:,compocn), & is_local%wrap%FBExp(compocn), & @@ -653,7 +656,9 @@ subroutine med_phases_prep_ocn_custom_nems(gcomp, rc) lsize = size(ofrac) allocate(customwgt(lsize)) - if (trim(coupling_mode) == 'nems_orig' .or. trim(coupling_mode) == 'nems_frac') then + if (trim(coupling_mode) == 'nems_orig' .or. & + trim(coupling_mode) == 'nems_frac' .or. & + trim(coupling_mode) == 'nems_frac_aoflux_sbs') then customwgt(:) = -ofrac(:) / const_lhvap call med_merge_field(is_local%wrap%FBExp(compocn), 'Faxa_evap', & FBinA=is_local%wrap%FBImp(compatm,compocn), fnameA='Faxa_lat' , wgtA=customwgt, rc=rc) @@ -665,13 +670,13 @@ subroutine med_phases_prep_ocn_custom_nems(gcomp, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return customwgt(:) = -ofrac(:) - call med_merge_field(is_local%wrap%FBExp(compocn), 'Foxx_taux', & - FBinA=is_local%wrap%FBImp(compice,compocn), fnameA='Fioi_taux' , wgtA=ifrac, & - FBinB=is_local%wrap%FBImp(compatm,compocn), fnameB='Faxa_taux' , wgtB=customwgt, rc=rc) + call med_merge_field(is_local%wrap%FBExp(compocn), 'Foxx_taux', & + FBinA=is_local%wrap%FBImp(compice,compocn), fnameA='Fioi_taux', wgtA=ifrac, & + FBinB=is_local%wrap%FBImp(compatm,compocn), fnameB='Faxa_taux', wgtB=customwgt, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call med_merge_field(is_local%wrap%FBExp(compocn), 'Foxx_tauy', & - FBinA=is_local%wrap%FBImp(compice,compocn), fnameA='Fioi_tauy' , wgtA=ifrac, & - FBinB=is_local%wrap%FBImp(compatm,compocn), fnameB='Faxa_tauy' , wgtB=customwgt, rc=rc) + call med_merge_field(is_local%wrap%FBExp(compocn), 'Foxx_tauy', & + FBinA=is_local%wrap%FBImp(compice,compocn), fnameA='Fioi_tauy', wgtA=ifrac, & + FBinB=is_local%wrap%FBImp(compatm,compocn), fnameB='Faxa_tauy', wgtB=customwgt, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return end if diff --git a/ufs/ccpp/config/ccpp_prebuild_config.py b/ufs/ccpp/config/ccpp_prebuild_config.py new file mode 100755 index 000000000..d2872972e --- /dev/null +++ b/ufs/ccpp/config/ccpp_prebuild_config.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python + +############################################################################### +# Used modules # +############################################################################### + +import os + +############################################################################### +# Query required information/s # +############################################################################### + +fv3_path = os.environ['FV3_PATH'] + +############################################################################### +# Definitions # +############################################################################### + +HOST_MODEL_IDENTIFIER = "CMEPS" + +# Add all files with metadata tables on the host model side and in CCPP, +# relative to basedir = top-level directory of host model. This includes +# kind and type definitions used in CCPP physics. Also add any internal +# dependencies of these files to the list. +VARIABLE_DEFINITION_FILES = [ + # actual variable definition files + '{}/ccpp/framework/src/ccpp_types.F90'.format(fv3_path), + '{}/ccpp/physics/physics/machine.F'.format(fv3_path), + 'CMEPS/ufs/ccpp/data/MED_typedefs.F90', + 'CMEPS/ufs/ccpp/data/MED_data.F90' + ] + +TYPEDEFS_NEW_METADATA = { + 'ccpp_types' : { + 'ccpp_t' : 'cdata', + 'ccpp_types' : '', + }, + 'machine' : { + 'machine' : '', + }, + 'MED_typedefs' : { + 'MED_init_type' : 'physics%init', + 'MED_statein_type' : 'physics%Statein', + 'MED_stateout_type' : 'physics%Stateout', + 'MED_interstitial_type' : 'physics%Interstitial', + 'MED_control_type' : 'physics%Model', + 'MED_coupling_type' : 'physics%Coupling', + 'MED_grid_type' : 'physics%Grid', + 'MED_sfcprop_type' : 'physics%Sfcprop', + 'MED_diag_type' : 'physics%Diag', + 'MED_typedefs' : '', + }, + 'MED_data' : { + 'MED_data' : '', + 'physics_type' : 'physics', + } + } + +# Add all physics scheme files relative to basedir +SCHEME_FILES = [ + '{}/ccpp/physics/physics/sfc_ocean.F'.format(fv3_path), + '{}/ccpp/physics/physics/sfc_diff.f'.format(fv3_path), + '{}/ccpp/physics/physics/GFS_surface_loop_control_part1.F90'.format(fv3_path), + '{}/ccpp/physics/physics/GFS_surface_loop_control_part2.F90'.format(fv3_path), + '{}/ccpp/physics/physics/GFS_surface_composites_pre.F90'.format(fv3_path), + '{}/ccpp/physics/physics/GFS_surface_composites_post.F90'.format(fv3_path), + '{}/ccpp/physics/physics/sfc_diag.f'.format(fv3_path) + ] + +# Default build dir, relative to current working directory, +# if not specified as command-line argument +DEFAULT_BUILD_DIR = 'CMEPS' + +# Auto-generated makefile/cmakefile snippets that contain all type definitions +TYPEDEFS_MAKEFILE = '{build_dir}/physics/CCPP_TYPEDEFS.mk' +TYPEDEFS_CMAKEFILE = '{build_dir}/physics/CCPP_TYPEDEFS.cmake' +TYPEDEFS_SOURCEFILE = '{build_dir}/physics/CCPP_TYPEDEFS.sh' + +# Auto-generated makefile/cmakefile snippets that contain all schemes +SCHEMES_MAKEFILE = '{build_dir}/physics/CCPP_SCHEMES.mk' +SCHEMES_CMAKEFILE = '{build_dir}/physics/CCPP_SCHEMES.cmake' +SCHEMES_SOURCEFILE = '{build_dir}/physics/CCPP_SCHEMES.sh' + +# Auto-generated makefile/cmakefile snippets that contain all caps +CAPS_MAKEFILE = '{build_dir}/physics/CCPP_CAPS.mk' +CAPS_CMAKEFILE = '{build_dir}/physics/CCPP_CAPS.cmake' +CAPS_SOURCEFILE = '{build_dir}/physics/CCPP_CAPS.sh' + +# Directory where to put all auto-generated physics caps +CAPS_DIR = '{build_dir}/physics' + +# Directory where the suite definition files are stored +SUITES_DIR = 'CMEPS/ufs/ccpp/suites' + +# Directory where to write static API to +STATIC_API_DIR = '{build_dir}/physics' +STATIC_API_CMAKEFILE = '{build_dir}/physics/CCPP_STATIC_API.cmake' +STATIC_API_SOURCEFILE = '{build_dir}/physics/CCPP_STATIC_API.sh' + +# Directory for writing HTML pages generated from metadata files +METADATA_HTML_OUTPUT_DIR = '{build_dir}/physics/physics/docs' + +# HTML document containing the model-defined CCPP variables +HTML_VARTABLE_FILE = '{build_dir}/physics/CCPP_VARIABLES_CMEPS.html' + +# LaTeX document containing the provided vs requested CCPP variables +LATEX_VARTABLE_FILE = '{build_dir}/framework/doc/DevelopersGuide/CCPP_VARIABLES_CMEPS.tex' diff --git a/ufs/ccpp/data/MED_data.F90 b/ufs/ccpp/data/MED_data.F90 new file mode 100644 index 000000000..edaf9dffa --- /dev/null +++ b/ufs/ccpp/data/MED_data.F90 @@ -0,0 +1,45 @@ +!> \file MED_data.F90 +!! Contains type definitions for CMEPS-related and physics-related variables + +module MED_data + +!> \section arg_table_MED_data +!! \htmlinclude MED_data.html +!! + + use MED_typedefs, only: MED_statein_type + use MED_typedefs, only: MED_stateout_type + use MED_typedefs, only: MED_init_type + use MED_typedefs, only: MED_interstitial_type + use MED_typedefs, only: MED_control_type + use MED_typedefs, only: MED_coupling_type + use MED_typedefs, only: MED_grid_type + use MED_typedefs, only: MED_sfcprop_type + use MED_typedefs, only: MED_diag_type + use ccpp_types, only: ccpp_t + + implicit none + + public physics + +!! \section arg_table_physics_type +!! \htmlinclude physics_type.html +!! + type physics_type + type(MED_init_type) :: init + type(MED_statein_type) :: statein + type(MED_stateout_type) :: stateout + type(MED_interstitial_type) :: interstitial + type(MED_control_type) :: model + type(MED_coupling_type) :: coupling + type(MED_grid_type) :: grid + type(MED_sfcprop_type) :: sfcprop + type(MED_diag_type) :: diag + end type physics_type + + type(physics_type), save, target :: physics + type(ccpp_t), save, target :: cdata + +contains + +end module MED_data diff --git a/ufs/ccpp/data/MED_data.meta b/ufs/ccpp/data/MED_data.meta new file mode 100644 index 000000000..91148f4f8 --- /dev/null +++ b/ufs/ccpp/data/MED_data.meta @@ -0,0 +1,84 @@ +[ccpp-table-properties] + name = physics_type + type = ddt + dependencies = MED_typedefs.F90 + +[ccpp-arg-table] + name = physics_type + type = ddt +[Init] + standard_name = MED_init_type_instance + long_name = instance of derived type MED_init_type + units = DDT + dimensions = () + type = MED_init_type +[Statein] + standard_name = MED_statein_type_instance + long_name = instance of derived type MED_statein_type + units = DDT + dimensions = () + type = MED_statein_type +[Interstitial] + standard_name = MED_interstitial_type_instance + long_name = instance of derived type MED_interstitial_type + units = DDT + dimensions = () + type = MED_interstitial_type +[Model] + standard_name = MED_control_type_instance + long_name = instance of derived type MED_control_type + units = DDT + dimensions = () + type = MED_control_type +[Coupling] + standard_name = MED_coupling_type_instance + long_name = instance of derived type MED_coupling_type + units = DDT + dimensions = () + type = MED_coupling_type +[Grid] + standard_name = MED_grid_type_instance + long_name = instance of derived type MED_grid_type + units = DDT + dimensions = () + type = MED_grid_type +[Sfcprop] + standard_name = MED_sfcprop_type_instance + long_name = instance of derived type MED_sfcprop_type + units = DDT + dimensions = () + type = MED_sfcprop_type +[Diag] + standard_name = MED_diag_type_instance + long_name = fields targeted for diagnostic output + units = DDT + dimensions = () + type = MED_diag_type + +######################################################################## +[ccpp-table-properties] + name = MED_data + type = module + dependencies = MED_typedefs.F90 + +[ccpp-arg-table] + name = MED_data + type = module +[physics_type] + standard_name = physics_type + long_name = definition of type physics_type + units = DDT + dimensions = () + type = physics_type +[physics] + standard_name = physics_type_instance + long_name = instance of derived data type physics_type + units = DDT + dimensions = () + type = physics_type +[cdata] + standard_name = ccpp_t_instance + long_name = instance of derived data type ccpp_t + units = DDT + dimensions = () + type = ccpp_t diff --git a/ufs/ccpp/data/MED_typedefs.F90 b/ufs/ccpp/data/MED_typedefs.F90 new file mode 100644 index 000000000..1b2ce51c5 --- /dev/null +++ b/ufs/ccpp/data/MED_typedefs.F90 @@ -0,0 +1,751 @@ +module MED_typedefs + +!> \section arg_table_MED_typedefs +!! \htmlinclude MED_typedefs.html +!! + use machine, only: kind_phys + use physcons, only: con_hvap, con_cp, con_rd, con_eps + use physcons, only: con_epsm1, con_fvirt, con_g + use physcons, only: con_tice + + implicit none + + !--- parameter constants used for default initializations + real(kind=kind_phys), parameter :: zero = 0.0_kind_phys + real(kind=kind_phys), parameter :: clear_val = zero + real(kind=kind_phys), parameter :: huge = 9.9692099683868690E36 + + !--- data containers + +!! \section arg_table_MED_init_type +!! \htmlinclude MED_init_type.html +!! + type MED_init_type + integer :: im !< horizontal loop extent + end type MED_init_type + +!! \section arg_table_MED_statein_type +!! \htmlinclude MED_statein_type.html +!! + type MED_statein_type + real(kind=kind_phys), pointer :: pgr(:) => null() !< surface pressure (Pa) + real(kind=kind_phys), pointer :: ugrs(:) => null() !< u component of layer wind (m/s) + real(kind=kind_phys), pointer :: vgrs(:) => null() !< v component of layer wind (m/s) + real(kind=kind_phys), pointer :: tgrs(:) => null() !< model layer mean temperature (K) + real(kind=kind_phys), pointer :: qgrs(:) => null() !< layer mean tracer concentration (kg/kg) + real(kind=kind_phys), pointer :: prsl(:) => null() !< model layer mean pressure (Pa) + real(kind=kind_phys), pointer :: zlvl(:) => null() !< layer 1 height above ground (m) + real(kind=kind_phys), pointer :: prsik(:) => null() !< dimensionless Exner function at lowest model interface + real(kind=kind_phys), pointer :: prslk(:) => null() !< dimensionless Exner function at lowest model layer + real(kind=kind_phys), pointer :: u10m(:) => null() !< 10 meter u wind speed (m/s) + real(kind=kind_phys), pointer :: v10m(:) => null() !< 10 meter v wind speed (m/s) + real(kind=kind_phys), pointer :: stc(:,:) => null() !< soil temperature (K) + contains + procedure :: create => statein_create !< allocate array data + end type MED_statein_type + +!! \section arg_table_MED_stateout_type +!! \htmlinclude MED_stateout_type.html +!! + type MED_stateout_type + real(kind=kind_phys), pointer :: gu0(:) => null() !< updated zonal wind + real(kind=kind_phys), pointer :: gv0(:) => null() !< updated meridional wind + real(kind=kind_phys), pointer :: gt0(:) => null() !< updated temperature + real(kind=kind_phys), pointer :: gq0(:) => null() !< updated tracers + contains + procedure :: create => stateout_create !< allocate array data + end type MED_stateout_type + +!! \section arg_table_MED_interstitial_type +!! \htmlinclude MED_interstitial_type.html +!! + type MED_interstitial_type + ! water + real(kind=kind_phys), pointer :: tsfc_water(:) => null() !< surface skin temperature over water (K) + real(kind=kind_phys), pointer :: cd_water(:) => null() !< surface exchange coeff for momentum over water + real(kind=kind_phys), pointer :: cdq_water(:) => null() !< surface exchange coeff heat surface exchange coeff heat & moisture over ocean moisture over water + real(kind=kind_phys), pointer :: ffmm_water(:) => null() !< Monin-Obukhov similarity function for momentum over water + real(kind=kind_phys), pointer :: fm10_water(:) => null() !< Monin-Obukhov similarity parameter for momentum at 10m over water + real(kind=kind_phys), pointer :: prslki(:) => null() !< Exner function ratio bt midlayer and interface at 1st layer + logical, pointer :: wet(:) => null() !< flag indicating presence of some ocean or lake surface area fraction + logical, pointer :: use_flake(:) => null() !< flag indicating lake points using flake model + real(kind=kind_phys), pointer :: wind(:) => null() !< wind speed at lowest model level (m/s) + logical, pointer :: flag_iter(:) => null() !< flag for iteration + real(kind=kind_phys), pointer :: qss_water(:) => null() !< surface air saturation specific humidity over water (kg/kg) + real(kind=kind_phys), pointer :: cmm_water(:) => null() !< momentum exchange coefficient over water (m/s) + real(kind=kind_phys), pointer :: chh_water(:) => null() !< thermal exchange coefficient over water (kg/m2s) + real(kind=kind_phys), pointer :: gflx_water(:) => null() !< soil heat flux over water (W/m2) + real(kind=kind_phys), pointer :: evap_water(:) => null() !< kinematic surface upward latent heat flux over water (m/s) + real(kind=kind_phys), pointer :: hflx_water(:) => null() !< kinematic surface upward sensible heat flux over water (Km/s) + real(kind=kind_phys), pointer :: ep1d_water(:) => null() !< surface upward potential latent heat flux over water (W/m2) + real(kind=kind_phys), pointer :: tsurf_water(:) => null() !< surface skin temperature after iteration over water (K) + real(kind=kind_phys), pointer :: uustar_water(:) => null() !< surface friction velocity over water (m/s) + real(kind=kind_phys), pointer :: rb_water(:) => null() !< bulk Richardson number at the surface over water + real(kind=kind_phys), pointer :: stress_water(:) => null() !< surface wind stress over water + real(kind=kind_phys), pointer :: ffhh_water(:) => null() !< Monin-Obukhov similarity function for heat over water + real(kind=kind_phys), pointer :: fh2_water(:) => null() !< Monin-Obukhov similarity parameter for heat at 2m over water + real(kind=kind_phys), pointer :: ztmax_water(:) => null() !< bounded surface roughness length for heat over water (m) + logical, pointer :: lake(:) => null() !< flag indicating presence of some lake surface area fraction + real(kind=kind_phys), pointer :: tprcp_water(:) => null() !< total precipitation amount in each time step over water + + ! land, not used to calculate aofluxes + real(kind=kind_phys), pointer :: zvfun(:) => null() !< function of surface roughness length and green vegetation fraction + real(kind=kind_phys), pointer :: sigmaf(:) => null() !< areal fractional cover of green vegetation bounded on the bottom + logical, pointer :: dry(:) => null() !< flag indicating presence of some land surface area fraction + real(kind=kind_phys), pointer :: tsfcl(:) => null() !< surface skin temperature over land (K) + real(kind=kind_phys), pointer :: tsurf_land(:) => null() !< surface skin temperature after iteration over land (K) + real(kind=kind_phys), pointer :: uustar_land(:) => null() !< surface friction velocity over land (m/s) + real(kind=kind_phys), pointer :: cd_land(:) => null() !< surface exchange coeff for momentum over land + real(kind=kind_phys), pointer :: cdq_land(:) => null() !< surface exchange coeff heat surface exchange coeff heat & moisture over ocean moisture over land + real(kind=kind_phys), pointer :: rb_land(:) => null() !< bulk Richardson number at the surface over land + real(kind=kind_phys), pointer :: stress_land(:) => null() !< surface wind stress over land + real(kind=kind_phys), pointer :: ffmm_land(:) => null() !< Monin-Obukhov similarity function for momentum over land + real(kind=kind_phys), pointer :: ffhh_land(:) => null() !< Monin-Obukhov similarity function for heat over land + real(kind=kind_phys), pointer :: fm10_land(:) => null() !< Monin-Obukhov similarity parameter for momentum at 10m over land + real(kind=kind_phys), pointer :: fh2_land(:) => null() !< Monin-Obukhov similarity parameter for heat at 2m over land + real(kind=kind_phys), pointer :: ztmax_land(:) => null() !< bounded surface roughness length for heat over land (m) + real(kind=kind_phys), pointer :: frland(:) => null() !< land area fraction used in microphysics schemes + real(kind=kind_phys), pointer :: tprcp_land(:) => null() !< total precipitation amount in each time step over land + real(kind=kind_phys), pointer :: qss_land(:) => null() !< surface air saturation specific humidity over land (kg/kg) + real(kind=kind_phys), pointer :: evap_land(:) => null() !< kinematic surface upward latent heat flux over land (m/s) + real(kind=kind_phys), pointer :: hflx_land(:) => null() !< kinematic surface upward sensible heat flux over land (Km/s) + real(kind=kind_phys), pointer :: hflxq(:) => null() !< kinematic surface upward sensible heat flux reduced by surface roughness and vegetation + real(kind=kind_phys), pointer :: chh_land(:) => null() !< thermal exchange coefficient over land (kg/m2s) + real(kind=kind_phys), pointer :: cmm_land(:) => null() !< momentum exchange coefficient over land (m/s) + real(kind=kind_phys), pointer :: gflx_land(:) => null() !< soil heat flux over land (W/m2) + real(kind=kind_phys), pointer :: ep1d_land(:) => null() !< surface upward potential latent heat flux over land (W/m2) + + ! ice, not used to calculate aofluxes + logical, pointer :: icy(:) => null() !< flag indicating presence of some sea ice surface area fraction + real(kind=kind_phys), pointer :: tisfc(:) => null() !< surface skin temperature over ice (K) + real(kind=kind_phys), pointer :: tsurf_ice(:) => null() !< surface skin temperature after iteration over ice (K) + real(kind=kind_phys), pointer :: uustar_ice(:) => null() !< surface friction velocity over ice (m/s) + real(kind=kind_phys), pointer :: cd_ice(:) => null() !< surface exchange coeff for momentum over ice + real(kind=kind_phys), pointer :: cdq_ice(:) => null() !< surface exchange coeff heat surface exchange coeff heat & moisture over ocean moisture over ice + real(kind=kind_phys), pointer :: rb_ice(:) => null() !< bulk Richardson number at the surface over ice + real(kind=kind_phys), pointer :: stress_ice(:) => null() !< surface wind stress over ice + real(kind=kind_phys), pointer :: ffmm_ice(:) => null() !< Monin-Obukhov similarity function for momentum over ice + real(kind=kind_phys), pointer :: ffhh_ice(:) => null() !< Monin-Obukhov similarity function for heat over ice + real(kind=kind_phys), pointer :: fm10_ice(:) => null() !< Monin-Obukhov similarity parameter for momentum at 10m over ice + real(kind=kind_phys), pointer :: fh2_ice(:) => null() !< Monin-Obukhov similarity parameter for heat at 2m over ice + real(kind=kind_phys), pointer :: ztmax_ice(:) => null() !< bounded surface roughness length for heat over ice (m) + logical, pointer :: flag_cice(:) => null() !< flag for cice + real(kind=kind_phys), pointer :: tprcp_ice(:) => null() !< total precipitation amount in each time step over ice + integer, pointer :: islmsk(:) => null() !< sea/land/ice mask (=0/1/2) + integer, pointer :: islmsk_cice(:) => null() !< sea/land/ice mask cice (=0/1/2) + real(kind=kind_phys), pointer :: ep1d_ice(:) => null() !< surface upward potential latent heat flux over ice (W/m2) + real(kind=kind_phys), pointer :: gflx_ice(:) => null() !< soil heat flux over ice + real(kind=kind_phys), pointer :: qss_ice(:) => null() !< surface air saturation specific humidity over ice (kg/kg) + real(kind=kind_phys), pointer :: evap_ice(:) => null() !< kinematic surface upward latent heat flux over ice (m/s) + real(kind=kind_phys), pointer :: hflx_ice(:) => null() !< kinematic surface upward sensible heat flux over ice (Km/s) + real(kind=kind_phys), pointer :: chh_ice(:) => null() !< thermal exchange coefficient over ice (kg/m2s) + real(kind=kind_phys), pointer :: cmm_ice(:) => null() !< momentum exchange coefficient over ice (m/s) + + ! others + real(kind=kind_phys), pointer :: z01d(:) => null() !< perturbation of momentum roughness length + real(kind=kind_phys), pointer :: zt1d(:) => null() !< perturbation of heat to momentum roughness length ratio + logical, pointer :: flag_guess(:) => null() !< flag for guess run + real(kind=kind_phys), pointer :: rb(:) => null() !< bulk Richardson number at the surface + real(kind=kind_phys), pointer :: fh2(:) => null() !< Monin-Obukhov similarity parameter for heat at 2m + real(kind=kind_phys), pointer :: fm10(:) => null() !< Monin-Obukhov similarity parameter for momentum at 10m + real(kind=kind_phys), pointer :: cdq(:) => null() !< surface exchange coeff heat & moisture + real(kind=kind_phys), pointer :: cd(:) => null() !< surface exchange coeff for momentum + real(kind=kind_phys), pointer :: hffac(:) => null() !< surface upward sensible heat flux reduction factor from canopy heat storage + real(kind=kind_phys), pointer :: stress(:) => null() !< surface wind stress + real(kind=kind_phys), pointer :: gflx(:) => null() !< soil heat flux + real(kind=kind_phys), pointer :: ep1d(:) => null() !< surface upward potential latent heat flux + contains + procedure :: create => interstitial_create !< allocate array data + procedure :: phys_reset => interstitial_phys_reset !< reset array data for physics + end type MED_interstitial_type + +!! \section arg_table_MED_control_type +!! \htmlinclude MED_control_type.html +!! + type MED_control_type + logical :: lseaspray !< flag for sea spray parameterization + logical :: use_med_flux !< flag for using atmosphere-ocean fluxes form mediator + integer :: ivegsrc !< land use dataset choice 0 => USGS, 1 => IGBP, 2 => UMD + integer :: lsm !< flag for land surface model + integer :: lsm_noahmp !< flag for NOAH MP land surface model + logical :: redrag !< flag for reduced drag coeff. over sea + integer :: sfc_z0_type !< surface roughness options over water + logical :: thsfc_loc !< flag for reference pressure in theta calculation + integer :: nstf_name(5) !< NSSTM flag: off/uncoupled/coupled=0/1/2 + integer :: lkm !< flag for flake model + logical :: first_time_step !< flag signaling first time step for time integration routine + logical :: frac_grid !< flag for fractional grid + logical :: cplwav2atm !< default no wav->atm coupling + logical :: restart !< flag whether this is a coldstart (.false.) or a warmstart/restart (.true.) + logical :: cplice !< default no cplice collection (used together with cplflx) + logical :: cplflx !< flag controlling cplflx collection (default off) + integer :: kdt !< current forecast iteration + real(kind=kind_phys) :: min_lakeice !< minimum lake ice value + real(kind=kind_phys) :: min_seaice !< minimum sea ice value + real(kind=kind_phys) :: huge !< definition of NetCDF float FillValue + logical :: lheatstrg !< flag for canopy heat storage parameterization + real(kind=kind_phys) :: h0facu !< canopy heat storage factor for sensible heat flux in unstable surface layer + real(kind=kind_phys) :: h0facs !< canopy heat storage factor for sensible heat flux in stable surface layer + integer :: lsoil !< number of soil layers + integer :: kice !< vertical loop extent for ice levels, start at 1 + integer :: lsm_ruc !< flag for RUC land surface model + contains + procedure :: init => control_initialize + end type MED_control_type + +!! \section arg_table_MED_coupling_type +!! \htmlinclude MED_coupling_type.html +!! + type MED_coupling_type + real(kind=kind_phys), pointer :: dtsfcin_med(:) => null() !< sfc latent heat flux over ocean + real(kind=kind_phys), pointer :: dqsfcin_med(:) => null() !< sfc sensible heat flux over ocean + contains + procedure :: create => coupling_create !< allocate array data + end type MED_coupling_type + +!! \section arg_table_MED_grid_type +!! \htmlinclude MED_grid_type.html +!! + type MED_grid_type + real(kind=kind_phys), pointer :: area(:) => null() !< area of the grid cell + contains + procedure :: create => grid_create !< allocate array data + end type MED_grid_type + +!! \section arg_table_MED_sfcprop_type +!! \htmlinclude MED_sfcprop_type.html +!! + type MED_sfcprop_type + real(kind=kind_phys), pointer :: zorlw(:) => null() !< surface roughness length over water (cm) + integer, pointer :: vtype(:) => null() !< vegetation type + real(kind=kind_phys), pointer :: shdmax(:) => null() !< max fractional coverage of green vegetation + real(kind=kind_phys), pointer :: zorll(:) => null() !< surface roughness length over land (cm) + real(kind=kind_phys), pointer :: zorli(:) => null() !< surface roughness length over ice (cm) + real(kind=kind_phys), pointer :: zorlwav(:) => null() !< surface roughness length from wave model (cm) + real(kind=kind_phys), pointer :: zorl(:) => null() !< surface roughness length (cm) + real(kind=kind_phys), pointer :: slmsk(:) => null() !< sea/land mask array (sea:0,land:1,sea-ice:2) + real(kind=kind_phys), pointer :: lakefrac(:) => null() !< lake fraction [0:1] + real(kind=kind_phys), pointer :: lakedepth(:) => null() !< lake depth (m) + real(kind=kind_phys), pointer :: landfrac(:) => null() !< fraction of horizontal grid area occupied by land + real(kind=kind_phys), pointer :: snowd(:) => null() !< snow depth water equivalent in mm ; same as snwdph + real(kind=kind_phys), pointer :: weasd(:) => null() !< water equiv of acc snow depth over land and sea ice + real(kind=kind_phys), pointer :: tprcp(:) => null() !< total precipitation amount in each time step + real(kind=kind_phys), pointer :: oceanfrac(:) => null() !< ocean fraction [0:1] + real(kind=kind_phys), pointer :: fice(:) => null() !< ice fraction over open water + real(kind=kind_phys), pointer :: hice(:) => null() !< sea ice thickness (m) + real(kind=kind_phys), pointer :: tsfco(:) => null() !< sea surface temperature + real(kind=kind_phys), pointer :: uustar(:) => null() !< boundary layer parameter + real(kind=kind_phys), pointer :: tsfc(:) => null() !< surface skin temperature + real(kind=kind_phys), pointer :: snodi(:) => null() !< water equivalent snow depth over ice (mm) + real(kind=kind_phys), pointer :: snodl(:) => null() !< water equivalent snow depth over land (mm) + real(kind=kind_phys), pointer :: qss(:) => null() !< surface air saturation specific humidity (kg/kg) + real(kind=kind_phys), pointer :: weasdi(:) => null() !< water equiv of acc snow depth over ice (mm) + real(kind=kind_phys), pointer :: weasdl(:) => null() !< water equiv of acc snow depth over land (mm) + real(kind=kind_phys), pointer :: ffhh(:) => null() !< Monin-Obukhov similarity function for heat + real(kind=kind_phys), pointer :: ffmm(:) => null() !< Monin-Obukhov similarity function for momentum + real(kind=kind_phys), pointer :: evap(:) => null() !< kinematic surface upward latent heat flux (kg kg-1 m s-1) + real(kind=kind_phys), pointer :: hflx(:) => null() !< kinematic surface upward sensible heat flux (K m/s) + real(kind=kind_phys), pointer :: tiice(:,:) => null() !< sea ice internal temperature + real(kind=kind_phys), pointer :: t2m(:) => null() !< temperature at 2 m + real(kind=kind_phys), pointer :: q2m(:) => null() !< specific humidity at 2 m + real(kind=kind_phys), pointer :: f10m(:) => null() !< ratio of sigma level 1 wind and 10m wind + contains + procedure :: create => sfcprop_create !< allocate array data + end type MED_sfcprop_type + +!! \section arg_table_MED_diag_type +!! \htmlinclude MED_diag_type.html +!! + type MED_diag_type + real(kind=kind_phys), pointer :: chh(:) => null() !< thermal exchange coefficient (kg m-2 s-1) + real(kind=kind_phys), pointer :: cmm(:) => null() !< momentum exchange coefficient (m/s) + contains + procedure :: create => diag_create !< allocate array data + end type MED_diag_type + + public MED_init_type + public MED_statein_type + public MED_coupling_type + public MED_control_type + public MED_interstitial_type + public MED_grid_type + public MED_sfcprop_type + public MED_diag_type + + contains + + subroutine statein_create(statein, im, model) + implicit none + class(MED_statein_type) :: statein + integer, intent(in) :: im + type(MED_control_type), intent(in) :: model + + allocate(statein%pgr(im)) + statein%pgr = clear_val + allocate(statein%ugrs(im)) + statein%ugrs = clear_val + allocate(statein%vgrs(im)) + statein%vgrs = clear_val + allocate(statein%tgrs(im)) + statein%tgrs = clear_val + allocate(statein%qgrs(im)) + statein%qgrs = clear_val + allocate(statein%prsl(im)) + statein%prsl = clear_val + allocate(statein%zlvl(im)) + statein%zlvl = clear_val + allocate(statein%prsik(im)) + statein%prsik = clear_val + allocate(statein%prslk(im)) + statein%prslk = clear_val + allocate(statein%u10m(im)) + statein%u10m = clear_val + allocate(statein%v10m(im)) + statein%v10m = clear_val + allocate(statein%stc(im,model%lsoil)) + statein%stc = clear_val + + end subroutine statein_create + + subroutine stateout_create(stateout, im) + implicit none + class(MED_stateout_type) :: stateout + integer, intent(in) :: im + + allocate(stateout%gu0(im)) + stateout%gu0 = clear_val + allocate(stateout%gv0(im)) + stateout%gv0 = clear_val + allocate(stateout%gt0(im)) + stateout%gt0 = clear_val + allocate(stateout%gq0(im)) + stateout%gq0 = clear_val + + end subroutine stateout_create + + subroutine interstitial_create(interstitial, im) + implicit none + class(MED_interstitial_type) :: interstitial + integer, intent(in) :: im + + ! water + allocate(interstitial%tsfc_water(im)) + interstitial%tsfc_water = huge + allocate(interstitial%cd_water(im)) + interstitial%cd_water = huge + allocate(interstitial%cdq_water(im)) + interstitial%cdq_water = huge + allocate(interstitial%ffmm_water(im)) + interstitial%ffmm_water = huge + allocate(interstitial%fm10_water(im)) + interstitial%fm10_water = huge + allocate(interstitial%prslki(im)) + interstitial%prslki = clear_val + allocate(interstitial%wet(im)) + interstitial%wet = .false. + allocate(interstitial%use_flake(im)) + interstitial%use_flake = .false. + allocate(interstitial%wind(im)) + interstitial%wind = huge + allocate(interstitial%flag_iter(im)) + interstitial%flag_iter = .true. + allocate(interstitial%qss_water(im)) + interstitial%qss_water = huge + allocate(interstitial%cmm_ice(im)) + interstitial%cmm_ice = huge + allocate(interstitial%cmm_land(im)) + interstitial%cmm_land = huge + allocate(interstitial%cmm_water(im)) + interstitial%cmm_water = huge + allocate(interstitial%chh_ice(im)) + interstitial%chh_ice = huge + allocate(interstitial%chh_land(im)) + interstitial%chh_land = huge + allocate(interstitial%chh_water(im)) + interstitial%chh_water = huge + allocate(interstitial%gflx_water(im)) + interstitial%gflx_water = clear_val + allocate(interstitial%evap_water(im)) + interstitial%evap_water = huge + allocate(interstitial%hflx_water(im)) + interstitial%hflx_water = huge + allocate(interstitial%hflx_land(im)) + interstitial%hflx_land = huge + allocate(interstitial%hflx_ice(im)) + interstitial%hflx_ice = huge + allocate(interstitial%ep1d_water(im)) + interstitial%ep1d_water = huge + allocate(interstitial%tsurf_water(im)) + interstitial%tsurf_water = huge + allocate(interstitial%uustar_water(im)) + interstitial%uustar_water = huge + allocate(interstitial%rb_water(im)) + interstitial%rb_water = huge + allocate(interstitial%stress_water(im)) + interstitial%stress_water = huge + allocate(interstitial%ffhh_water(im)) + interstitial%ffhh_water = huge + allocate(interstitial%fh2_water(im)) + interstitial%fh2_water = huge + allocate(interstitial%ztmax_water(im)) + interstitial%ztmax_water = clear_val + allocate(interstitial%lake(im)) + interstitial%lake = .false. + allocate(interstitial%tprcp_water(im)) + interstitial%tprcp_water = huge + + ! land + allocate(interstitial%zvfun(im)) + interstitial%zvfun = clear_val + allocate(interstitial%sigmaf(im)) + interstitial%sigmaf = clear_val + allocate(interstitial%dry(im)) + interstitial%dry = .false. + allocate(interstitial%tsfcl(im)) + interstitial%tsfcl = clear_val + allocate(interstitial%tsurf_land(im)) + interstitial%tsurf_land = huge + allocate(interstitial%uustar_land(im)) + interstitial%uustar_land = huge + allocate(interstitial%cd_land(im)) + interstitial%cd_land = huge + allocate(interstitial%cdq_land(im)) + interstitial%cdq_land = huge + allocate(interstitial%rb_land(im)) + interstitial%rb_land = huge + allocate(interstitial%stress_land(im)) + interstitial%stress_land = huge + allocate(interstitial%ffmm_land(im)) + interstitial%ffmm_land = huge + allocate(interstitial%ffhh_land(im)) + interstitial%ffhh_land = huge + allocate(interstitial%fm10_land(im)) + interstitial%fm10_land = huge + allocate(interstitial%fh2_land(im)) + interstitial%fh2_land = huge + allocate(interstitial%ztmax_land(im)) + interstitial%ztmax_land = clear_val + allocate(interstitial%frland(im)) + interstitial%frland = clear_val + allocate(interstitial%tprcp_land(im)) + interstitial%tprcp_land = huge + allocate(interstitial%qss_land(im)) + interstitial%qss_land = huge + allocate(interstitial%evap_land(im)) + interstitial%evap_land = huge + allocate(interstitial%hflxq(im)) + interstitial%hflxq = clear_val + allocate(interstitial%ep1d_land(im)) + interstitial%ep1d_land = huge + allocate(interstitial%gflx_land(im)) + interstitial%gflx_land = clear_val + + ! ice + allocate(interstitial%icy(im)) + interstitial%icy = .false. + allocate(interstitial%tisfc(im)) + interstitial%tisfc = clear_val + allocate(interstitial%tsurf_ice(im)) + interstitial%tsurf_ice = huge + allocate(interstitial%uustar_ice(im)) + interstitial%uustar_ice = huge + allocate(interstitial%cd_ice(im)) + interstitial%cd_ice = huge + allocate(interstitial%cdq_ice(im)) + interstitial%cdq_ice = huge + allocate(interstitial%rb_ice(im)) + interstitial%rb_ice = huge + allocate(interstitial%stress_ice(im)) + interstitial%stress_ice = huge + allocate(interstitial%ffmm_ice(im)) + interstitial%ffmm_ice = huge + allocate(interstitial%ffhh_ice(im)) + interstitial%ffhh_ice = huge + allocate(interstitial%fm10_ice(im)) + interstitial%fm10_ice = huge + allocate(interstitial%fh2_ice(im)) + interstitial%fh2_ice = huge + allocate(interstitial%ztmax_ice(im)) + interstitial%ztmax_ice = clear_val + allocate(interstitial%flag_cice(im)) + interstitial%flag_cice = .false. + allocate(interstitial%tprcp_ice(im)) + interstitial%tprcp_ice = huge + allocate(interstitial%islmsk(im)) + interstitial%islmsk = 0 + allocate(interstitial%islmsk_cice(im)) + interstitial%islmsk_cice = 0 + allocate(interstitial%qss_ice(im)) + interstitial%qss_ice = huge + allocate(interstitial%ep1d_ice(im)) + interstitial%ep1d_ice = huge + allocate(interstitial%gflx_ice(im)) + interstitial%gflx_ice = clear_val + allocate(interstitial%evap_ice(im)) + interstitial%evap_ice = huge + + ! others + allocate(interstitial%z01d(im)) + interstitial%z01d = clear_val + allocate(interstitial%zt1d(im)) + interstitial%zt1d = clear_val + allocate(interstitial%flag_guess(im)) + interstitial%flag_guess = .false. + allocate(interstitial%rb(im)) + interstitial%rb = clear_val + allocate(interstitial%fh2(im)) + interstitial%fh2 = clear_val + allocate(interstitial%fm10(im)) + interstitial%fm10 = clear_val + allocate(interstitial%cdq(im)) + interstitial%cdq_water = clear_val + allocate(interstitial%cd(im)) + interstitial%cd = clear_val + allocate(interstitial%ep1d(im)) + interstitial%ep1d = clear_val + allocate(interstitial%hffac(im)) + interstitial%hffac = clear_val + allocate(interstitial%stress(im)) + interstitial%stress = clear_val + allocate(interstitial%gflx(im)) + interstitial%gflx = clear_val + + end subroutine interstitial_create + + subroutine interstitial_phys_reset(interstitial) + implicit none + class(MED_interstitial_type) :: interstitial + + interstitial%cd = clear_val + interstitial%cd_ice = huge + interstitial%cd_land = huge + interstitial%cd_water = huge + interstitial%cdq = clear_val + interstitial%cdq_ice = huge + interstitial%cdq_land = huge + interstitial%cdq_water = huge + interstitial%chh_ice = huge + interstitial%chh_land = huge + interstitial%chh_water = huge + interstitial%cmm_ice = huge + interstitial%cmm_land = huge + interstitial%cmm_water = huge + interstitial%dry = .false. + interstitial%ep1d = clear_val + interstitial%ep1d_ice = huge + interstitial%ep1d_land = huge + interstitial%ep1d_water = huge + interstitial%evap_water = huge + interstitial%evap_land = huge + interstitial%evap_ice = huge + interstitial%ffhh_ice = huge + interstitial%ffhh_land = huge + interstitial%ffhh_water = huge + interstitial%ffmm_ice = huge + interstitial%ffmm_land = huge + interstitial%ffmm_water = huge + Interstitial%fh2 = clear_val + interstitial%fh2_ice = huge + interstitial%fh2_land = huge + interstitial%fh2_water = huge + Interstitial%fm10 = clear_val + interstitial%flag_cice = .false. + interstitial%flag_guess = .false. + interstitial%flag_iter = .true. + interstitial%fm10_ice = huge + interstitial%fm10_land = huge + interstitial%fm10_water = huge + interstitial%frland = clear_val + interstitial%gflx = clear_val + interstitial%gflx_ice = clear_val + interstitial%gflx_land = clear_val + interstitial%gflx_water = clear_val + interstitial%hffac = clear_val + interstitial%hflx_ice = huge + interstitial%hflx_land = huge + interstitial%hflx_water = huge + interstitial%hflxq = clear_val + interstitial%icy = .false. + interstitial%islmsk = 0 + interstitial%islmsk_cice = 0 + interstitial%lake = .false. + interstitial%prslki = clear_val + interstitial%rb = clear_val + interstitial%qss_ice = huge + interstitial%qss_land = huge + interstitial%qss_water = huge + interstitial%rb_ice = huge + interstitial%rb_land = huge + interstitial%rb_water = huge + interstitial%sigmaf = clear_val + interstitial%stress = clear_val + interstitial%stress_ice = huge + interstitial%stress_land = huge + interstitial%stress_water = huge + interstitial%tisfc = clear_val + interstitial%tprcp_water = huge + interstitial%tprcp_land = huge + interstitial%tprcp_ice = huge + interstitial%tsfc_water = huge + interstitial%tsfcl = clear_val + interstitial%tsurf_ice = huge + interstitial%tsurf_land = huge + interstitial%tsurf_water = huge + interstitial%use_flake = .false. + interstitial%uustar_ice = huge + interstitial%uustar_land = huge + interstitial%uustar_water = huge + interstitial%wet = .false. + interstitial%wind = huge + interstitial%z01d = clear_val + interstitial%zt1d = clear_val + interstitial%ztmax_ice = clear_val + interstitial%ztmax_land = clear_val + interstitial%ztmax_water = clear_val + interstitial%zvfun = clear_val + + end subroutine interstitial_phys_reset + + subroutine control_initialize(model) + implicit none + class(MED_control_type) :: model + + model%lseaspray = .false. + model%use_med_flux = .false. + model%ivegsrc = 2 + model%redrag = .false. + model%sfc_z0_type = 0 + model%thsfc_loc = .true. + model%lsm = 1 + model%lsm_noahmp = 2 + model%nstf_name = (/0,0,1,0,5/) + model%lkm = 0 + model%first_time_step = .true. + model%frac_grid = .false. + model%cplwav2atm = .false. + model%restart = .false. + model%cplice = .false. + model%cplflx = .false. + model%kdt = 0 ! nint(Model%fhour*con_hr/Model%dtp) + model%min_lakeice = 0.15d0 + model%min_seaice = 1.0d-11 + model%huge = 9.9692099683868690e36 + model%lheatstrg = .false. + model%h0facu = 0.25 + model%h0facs = 1.0 + model%lsoil = 4 + model%kice = 2 + model%lsm_ruc = 3 + + end subroutine control_initialize + + subroutine coupling_create(coupling, im) + implicit none + class(MED_coupling_type) :: coupling + integer, intent(in) :: im + + allocate(coupling%dtsfcin_med(im)) + coupling%dtsfcin_med = clear_val + allocate(coupling%dqsfcin_med(im)) + coupling%dqsfcin_med = clear_val + + end subroutine coupling_create + + subroutine grid_create(grid, im) + implicit none + class(MED_grid_type) :: grid + integer, intent(in) :: im + + allocate(grid%area(im)) + grid%area = clear_val + + end subroutine grid_create + + subroutine sfcprop_create(sfcprop, im, model) + implicit none + class(MED_sfcprop_type) :: sfcprop + integer, intent(in) :: im + type(MED_control_type), intent(in) :: model + + allocate(sfcprop%vtype(im)) + sfcprop%vtype = zero + allocate(sfcprop%shdmax(im)) + sfcprop%shdmax = clear_val + allocate(sfcprop%zorl(im)) + sfcprop%zorl = clear_val + allocate(sfcprop%zorlw(im)) + sfcprop%zorlw = clear_val + allocate(sfcprop%zorll(im)) + sfcprop%zorll = clear_val + allocate(sfcprop%zorli(im)) + sfcprop%zorli = clear_val + allocate(sfcprop%zorlwav(im)) + sfcprop%zorlwav = clear_val + allocate(sfcprop%slmsk(im)) + sfcprop%slmsk = clear_val + allocate(sfcprop%lakefrac(im)) + sfcprop%lakefrac = clear_val + allocate(sfcprop%lakedepth(im)) + sfcprop%lakedepth = clear_val + allocate(sfcprop%landfrac(im)) + sfcprop%landfrac = clear_val + allocate(sfcprop%snowd(im)) + sfcprop%snowd = clear_val + allocate(sfcprop%weasd(im)) + sfcprop%weasd = clear_val + allocate(sfcprop%tprcp(im)) + sfcprop%tprcp = clear_val + allocate(sfcprop%oceanfrac(im)) + sfcprop%oceanfrac = clear_val + allocate(sfcprop%fice(im)) + sfcprop%fice = clear_val + allocate(sfcprop%hice(im)) + sfcprop%hice = clear_val + allocate(sfcprop%tsfco(im)) + sfcprop%tsfco = clear_val + allocate(sfcprop%uustar(im)) + sfcprop%uustar = clear_val + allocate(sfcprop%tsfc(im)) + sfcprop%tsfc = clear_val + allocate(sfcprop%snodi(im)) + sfcprop%snodi = clear_val + allocate(sfcprop%snodl(im)) + sfcprop%snodl = clear_val + allocate(sfcprop%qss(im)) + sfcprop%qss = clear_val + allocate(sfcprop%weasdi(im)) + sfcprop%weasdi = clear_val + allocate(sfcprop%weasdl(im)) + sfcprop%weasdl = clear_val + allocate(sfcprop%ffhh(im)) + sfcprop%ffhh = clear_val + allocate(sfcprop%ffmm(im)) + sfcprop%ffmm = clear_val + allocate(sfcprop%evap(im)) + sfcprop%evap = clear_val + allocate(sfcprop%hflx(im)) + sfcprop%hflx = clear_val + allocate(sfcprop%tiice(im,model%kice)) + sfcprop%tiice = clear_val + allocate(sfcprop%t2m(im)) + sfcprop%t2m = clear_val + allocate(sfcprop%q2m(im)) + sfcprop%q2m = clear_val + allocate(sfcprop%f10m(im)) + sfcprop%f10m = clear_val + + end subroutine sfcprop_create + + subroutine diag_create(diag, im) + implicit none + class(MED_diag_type) :: diag + integer, intent(in) :: im + + allocate(diag%chh(im)) + diag%chh = clear_val + allocate(diag%cmm(im)) + diag%cmm = clear_val + + end subroutine diag_create + +end module MED_typedefs diff --git a/ufs/ccpp/data/MED_typedefs.meta b/ufs/ccpp/data/MED_typedefs.meta new file mode 100644 index 000000000..6204c6a21 --- /dev/null +++ b/ufs/ccpp/data/MED_typedefs.meta @@ -0,0 +1,1345 @@ +[ccpp-table-properties] + name = MED_init_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_init_type + type = ddt +[im] + standard_name = horizontal_loop_extent + long_name = horizontal loop extent + units = count + dimensions = () + type = integer + +######################################################################## +[ccpp-table-properties] + name = MED_statein_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_statein_type + type = ddt +[pgr] + standard_name = surface_air_pressure + long_name = surface pressure + units = Pa + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ugrs] + standard_name = x_wind_at_surface_adjacent_layer + long_name = zonal wind at lowest model layer + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[vgrs] + standard_name = y_wind_at_surface_adjacent_layer + long_name = meridional wind at lowest model layer + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tgrs] + standard_name = air_temperature_at_surface_adjacent_layer + long_name = mean temperature at lowest model layer + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[qgrs] + standard_name = specific_humidity_at_surface_adjacent_layer + long_name = water vapor specific humidity at lowest model layer + units = kg kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[prsl] + standard_name = air_pressure_at_surface_adjacent_layer + long_name = mean pressure at lowest model layer + units = Pa + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zlvl] + standard_name = height_above_ground_at_lowest_model_layer + long_name = layer 1 height above ground (not MSL) + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[prsik] + standard_name = surface_dimensionless_exner_function + long_name = dimensionless Exner function at lowest model interface + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[prslk] + standard_name = dimensionless_exner_function_at_surface_adjacent_layer + long_name = dimensionless Exner function at lowest model layer + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[u10m] + standard_name = x_wind_at_10m + long_name = 10 meter u wind speed + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[v10m] + standard_name = y_wind_at_10m + long_name = 10 meter v wind speed + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[stc] + standard_name = soil_temperature + long_name = soil temperature + units = K + dimensions = (horizontal_loop_extent,vertical_dimension_of_soil) + type = real + kind = kind_phys + +######################################################################## +[ccpp-table-properties] + name = MED_stateout_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_stateout_type + type = ddt +[gu0] + standard_name = x_wind_of_new_state_at_surface_adjacent_layer + long_name = zonal wind at lowest model layer updated by physics + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[gv0] + standard_name = y_wind_of_new_state_at_surface_adjacent_layer + long_name = meridional wind at lowest model layer updated by physics + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[gt0] + standard_name = air_temperature_of_new_state_at_surface_adjacent_layer + long_name = temperature at lowest model layer updated by physics + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[gq0] + standard_name = specific_humidity_of_new_state_at_surface_adjacent_layer + long_name = water vapor specific humidity at lowest model layer updated by physics + units = kg kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + +######################################################################## +[ccpp-table-properties] + name = MED_interstitial_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_interstitial_type + type = ddt +[tsfc_water] + standard_name = surface_skin_temperature_over_water + long_name = surface skin temperature over water + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cd_water] + standard_name = surface_drag_coefficient_for_momentum_in_air_over_water + long_name = surface exchange coeff for momentum over water + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cdq_water] + standard_name = surface_drag_coefficient_for_heat_and_moisture_in_air_over_water + long_name = surface exchange coeff heat surface exchange coeff heat & moisture over ocean moisture over water + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffmm_water] + standard_name = Monin_Obukhov_similarity_function_for_momentum_over_water + long_name = Monin-Obukhov similarity function for momentum over water + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fm10_water] + standard_name = Monin_Obukhov_similarity_function_for_momentum_at_10m_over_water + long_name = Monin-Obukhov similarity parameter for momentum at 10m over water + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[prslki] + standard_name = ratio_of_exner_function_between_midlayer_and_interface_at_lowest_model_layer + long_name = Exner function ratio bt midlayer and interface at 1st layer + units = ratio + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[wet] + standard_name = flag_nonzero_wet_surface_fraction + long_name = flag indicating presence of some ocean or lake surface area fraction + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[use_flake] + standard_name = flag_for_using_flake + long_name = flag indicating lake points using flake model + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[wind] + standard_name = wind_speed_at_lowest_model_layer + long_name = wind speed at lowest model level + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[flag_iter] + standard_name = flag_for_iteration + long_name = flag for iteration + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[qss_water] + standard_name = surface_specific_humidity_over_water + long_name = surface air saturation specific humidity over water + units = kg kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cmm_water] + standard_name = surface_drag_wind_speed_for_momentum_in_air_over_water + long_name = momentum exchange coefficient over water + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[chh_water] + standard_name = surface_drag_mass_flux_for_heat_and_moisture_in_air_over_water + long_name = thermal exchange coefficient over water + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[gflx_water] + standard_name = upward_heat_flux_in_soil_over_water + long_name = soil heat flux over water + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[evap_water] + standard_name = kinematic_surface_upward_latent_heat_flux_over_water + long_name = kinematic surface upward latent heat flux over water + units = kg kg-1 m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[evap_land] + standard_name = kinematic_surface_upward_latent_heat_flux_over_land + long_name = kinematic surface upward latent heat flux over land + units = kg kg-1 m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[evap_ice] + standard_name = kinematic_surface_upward_latent_heat_flux_over_ice + long_name = kinematic surface upward latent heat flux over ice + units = kg kg-1 m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[hflx_water] + standard_name = kinematic_surface_upward_sensible_heat_flux_over_water + long_name = kinematic surface upward sensible heat flux over water + units = K m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[hflx_land] + standard_name = kinematic_surface_upward_sensible_heat_flux_over_land + long_name = kinematic surface upward sensible heat flux over land + units = K m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[hflx_ice] + standard_name = kinematic_surface_upward_sensible_heat_flux_over_ice + long_name = kinematic surface upward sensible heat flux over ice + units = K m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ep1d_water] + standard_name = surface_upward_potential_latent_heat_flux_over_water + long_name = surface upward potential latent heat flux over water + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zvfun] + standard_name = function_of_surface_roughness_length_and_green_vegetation_fraction + long_name = function of surface roughness length and green vegetation fraction + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[sigmaf] + standard_name = bounded_vegetation_area_fraction + long_name = areal fractional cover of green vegetation bounded on the bottom + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[z01d] + standard_name = perturbation_of_momentum_roughness_length + long_name = perturbation of momentum roughness length + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zt1d] + standard_name = perturbation_of_heat_to_momentum_roughness_length_ratio + long_name = perturbation of heat to momentum roughness length ratio + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[dry] + standard_name = flag_nonzero_land_surface_fraction + long_name = flag indicating presence of some land surface area fraction + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[icy] + standard_name = flag_nonzero_sea_ice_surface_fraction + long_name = flag indicating presence of some sea ice surface area fraction + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[tsfcl] + standard_name = surface_skin_temperature_over_land + long_name = surface skin temperature over land + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tisfc] + standard_name = surface_skin_temperature_over_ice + long_name = surface skin temperature over ice + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tsurf_water] + standard_name = surface_skin_temperature_after_iteration_over_water + long_name = surface skin temperature after iteration over water + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tsurf_land] + standard_name = surface_skin_temperature_after_iteration_over_land + long_name = surface skin temperature after iteration over land + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tsurf_ice] + standard_name = surface_skin_temperature_after_iteration_over_ice + long_name = surface skin temperature after iteration over ice + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[uustar_water] + standard_name = surface_friction_velocity_over_water + long_name = surface friction velocity over water + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[uustar_land] + standard_name = surface_friction_velocity_over_land + long_name = surface friction velocity over land + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[uustar_ice] + standard_name = surface_friction_velocity_over_ice + long_name = surface friction velocity over ice + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cd] + standard_name = surface_drag_coefficient_for_momentum_in_air + long_name = surface exchange coeff for momentum + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cd_land] + standard_name = surface_drag_coefficient_for_momentum_in_air_over_land + long_name = surface exchange coeff for momentum over land + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cd_ice] + standard_name = surface_drag_coefficient_for_momentum_in_air_over_ice + long_name = surface exchange coeff for momentum over ice + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cdq] + standard_name = surface_drag_coefficient_for_heat_and_moisture_in_air + long_name = surface exchange coeff heat & moisture + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cdq_land] + standard_name = surface_drag_coefficient_for_heat_and_moisture_in_air_over_land + long_name = surface exchange coeff heat & moisture over land + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cdq_ice] + standard_name = surface_drag_coefficient_for_heat_and_moisture_in_air_over_ice + long_name = surface exchange coeff heat & moisture over ice + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[rb_water] + standard_name = bulk_richardson_number_at_lowest_model_level_over_water + long_name = bulk Richardson number at the surface over water + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[rb_land] + standard_name = bulk_richardson_number_at_lowest_model_level_over_land + long_name = bulk Richardson number at the surface over land + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[rb_ice] + standard_name = bulk_richardson_number_at_lowest_model_level_over_ice + long_name = bulk Richardson number at the surface over ice + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[stress_water] + standard_name = surface_wind_stress_over_water + long_name = surface wind stress over water + units = m2 s-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[stress_land] + standard_name = surface_wind_stress_over_land + long_name = surface wind stress over land + units = m2 s-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[stress_ice] + standard_name = surface_wind_stress_over_ice + long_name = surface wind stress over ice + units = m2 s-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffmm_land] + standard_name = Monin_Obukhov_similarity_function_for_momentum_over_land + long_name = Monin-Obukhov similarity function for momentum over land + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffmm_ice] + standard_name = Monin_Obukhov_similarity_function_for_momentum_over_ice + long_name = Monin-Obukhov similarity function for momentum over ice + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffhh_water] + standard_name = Monin_Obukhov_similarity_function_for_heat_over_water + long_name = Monin-Obukhov similarity function for heat over water + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffhh_land] + standard_name = Monin_Obukhov_similarity_function_for_heat_over_land + long_name = Monin-Obukhov similarity function for heat over land + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffhh_ice] + standard_name = Monin_Obukhov_similarity_function_for_heat_over_ice + long_name = Monin-Obukhov similarity function for heat over ice + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fm10_land] + standard_name = Monin_Obukhov_similarity_function_for_momentum_at_10m_over_land + long_name = Monin-Obukhov similarity parameter for momentum at 10m over land + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fm10_ice] + standard_name = Monin_Obukhov_similarity_function_for_momentum_at_10m_over_ice + long_name = Monin-Obukhov similarity parameter for momentum at 10m over ice + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fh2_water] + standard_name = Monin_Obukhov_similarity_function_for_heat_at_2m_over_water + long_name = Monin-Obukhov similarity parameter for heat at 2m over water + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fh2_land] + standard_name = Monin_Obukhov_similarity_function_for_heat_at_2m_over_land + long_name = Monin-Obukhov similarity parameter for heat at 2m over land + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fh2_ice] + standard_name = Monin_Obukhov_similarity_function_for_heat_at_2m_over_ice + long_name = Monin-Obukhov similarity parameter for heat at 2m over ice + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ztmax_water] + standard_name = bounded_surface_roughness_length_for_heat_over_water + long_name = bounded surface roughness length for heat over water + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ztmax_land] + standard_name = bounded_surface_roughness_length_for_heat_over_land + long_name = bounded surface roughness length for heat over land + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ztmax_ice] + standard_name = bounded_surface_roughness_length_for_heat_over_ice + long_name = bounded surface roughness length for heat over ice + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[flag_guess] + standard_name = flag_for_guess_run + long_name = flag for guess run + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[flag_cice] + standard_name = flag_for_cice + long_name = flag for cice + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[lake] + standard_name = flag_nonzero_lake_surface_fraction + long_name = flag indicating presence of some lake surface area fraction + units = flag + dimensions = (horizontal_loop_extent) + type = logical +[frland] + standard_name = land_area_fraction_for_microphysics + long_name = land area fraction used in microphysics schemes + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tprcp_water] + standard_name = nonnegative_lwe_thickness_of_precipitation_amount_on_dynamics_timestep_over_water + long_name = total precipitation amount in each time step over water + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tprcp_land] + standard_name = nonnegative_lwe_thickness_of_precipitation_amount_on_dynamics_timestep_over_land + long_name = total precipitation amount in each time step over land + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tprcp_ice] + standard_name = nonnegative_lwe_thickness_of_precipitation_amount_on_dynamics_timestep_over_ice + long_name = total precipitation amount in each time step over ice + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[islmsk] + standard_name = sea_land_ice_mask + long_name = sea/land/ice mask (=0/1/2) + units = flag + dimensions = (horizontal_loop_extent) + type = integer +[islmsk_cice] + standard_name = sea_land_ice_mask_cice + long_name = sea/land/ice mask cice (=0/1/2) + units = flag + dimensions = (horizontal_loop_extent) + type = integer +[qss_land] + standard_name = surface_specific_humidity_over_land + long_name = surface air saturation specific humidity over land + units = kg kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[qss_ice] + standard_name = surface_specific_humidity_over_ice + long_name = surface air saturation specific humidity over ice + units = kg kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ep1d_ice] + standard_name = surface_upward_potential_latent_heat_flux_over_ice + long_name = surface upward potential latent heat flux over ice + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[gflx_ice] + standard_name = upward_heat_flux_in_soil_over_ice + long_name = soil heat flux over ice + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[rb] + standard_name = bulk_richardson_number_at_lowest_model_level + long_name = bulk Richardson number at the surface + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[hflxq] + standard_name = kinematic_surface_upward_sensible_heat_flux_reduced_by_surface_roughness_and_vegetation + long_name = kinematic surface upward sensible heat flux reduced by surface roughness and vegetation + units = K m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fh2] + standard_name = Monin_Obukhov_similarity_function_for_heat_at_2m + long_name = Monin-Obukhov similarity parameter for heat at 2m + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fm10] + standard_name = Monin_Obukhov_similarity_function_for_momentum_at_10m + long_name = Monin-Obukhov similarity parameter for momentum at 10m + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[chh_land] + standard_name = surface_drag_mass_flux_for_heat_and_moisture_in_air_over_land + long_name = thermal exchange coefficient over land + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[chh_ice] + standard_name = surface_drag_mass_flux_for_heat_and_moisture_in_air_over_ice + long_name = thermal exchange coefficient over ice + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cmm_land] + standard_name = surface_drag_wind_speed_for_momentum_in_air_over_land + long_name = momentum exchange coefficient over land + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cmm_ice] + standard_name = surface_drag_wind_speed_for_momentum_in_air_over_ice + long_name = momentum exchange coefficient over ice + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ep1d] + standard_name = surface_upward_potential_latent_heat_flux + long_name = surface upward potential latent heat flux + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ep1d_land] + standard_name = surface_upward_potential_latent_heat_flux_over_land + long_name = surface upward potential latent heat flux over land + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[hffac] + standard_name = surface_upward_sensible_heat_flux_reduction_factor + long_name = surface upward sensible heat flux reduction factor from canopy heat storage + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[stress] + standard_name = surface_wind_stress + long_name = surface wind stress + units = m2 s-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[gflx] + standard_name = upward_heat_flux_in_soil + long_name = soil heat flux + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[gflx_land] + standard_name = upward_heat_flux_in_soil_over_land + long_name = soil heat flux over land + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + +######################################################################## +[ccpp-table-properties] + name = MED_control_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_control_type + type = ddt +[lseaspray] + standard_name = flag_for_sea_spray + long_name = flag for sea spray parameterization + units = flag + dimensions = () + type = logical +[use_med_flux] + standard_name = do_mediator_atmosphere_ocean_fluxes + long_name = flag for using atmosphere-ocean fluxes form mediator (default false) + units = flag + dimensions = () + type = logical +[ivegsrc] + standard_name = control_for_vegetation_dataset + long_name = land use dataset choice + units = index + dimensions = () + type = integer +[redrag] + standard_name = flag_for_limited_surface_roughness_length_over_ocean + long_name = flag for reduced drag coeff. over sea + units = flag + dimensions = () + type = logical +[sfc_z0_type] + standard_name = flag_for_surface_roughness_option_over_water + long_name = surface roughness options over water + units = flag + dimensions = () + type = integer +[thsfc_loc] + standard_name = flag_for_reference_pressure_theta + long_name = flag for reference pressure in theta calculation + units = flag + dimensions = () + type = logical +[lsm] + standard_name = control_for_land_surface_scheme + long_name = flag for land surface model + units = flag + dimensions = () + type = integer +[lsm_noahmp] + standard_name = identifier_for_noahmp_land_surface_scheme + long_name = flag for NOAH MP land surface model + units = flag + dimensions = () + type = integer +[nstf_name(1)] + standard_name = control_for_nsstm + long_name = NSSTM flag: off/uncoupled/coupled=0/1/2 + units = flag + dimensions = () + type = integer +[lkm] + standard_name = control_for_lake_surface_scheme + long_name = flag for lake surface model + units = flag + dimensions = () + type = integer +[first_time_step] + standard_name = flag_for_first_timestep + long_name = flag for first time step for time integration loop (cold/warmstart) + units = flag + dimensions = () + type = logical +[frac_grid] + standard_name = flag_for_fractional_landmask + long_name = flag for fractional grid + units = flag + dimensions = () + type = logical +[cplwav2atm] + standard_name = flag_for_one_way_ocean_wave_coupling_to_atmosphere + long_name = flag controlling ocean wave coupling to the atmosphere (default off) + units = flag + dimensions = () + type = logical +[restart] + standard_name = flag_for_restart + long_name = flag for restart (warmstart) or coldstart + units = flag + dimensions = () + type = logical +[cplice] + standard_name = flag_for_sea_ice_coupling + long_name = flag controlling cplice collection (default on) + units = flag + dimensions = () + type = logical +[cplflx] + standard_name = flag_for_surface_flux_coupling + long_name = flag controlling cplflx collection (default off) + units = flag + dimensions = () + type = logical +[kdt] + standard_name = index_of_timestep + long_name = current forecast iteration + units = index + dimensions = () + type = integer +[min_lakeice] + standard_name = min_lake_ice_area_fraction + long_name = minimum lake ice value + units = frac + dimensions = () + type = real + kind = kind_phys +[min_seaice] + standard_name = min_sea_ice_area_fraction + long_name = minimum sea ice value + units = frac + dimensions = () + type = real + kind = kind_phys +[huge] + standard_name = netcdf_float_fillvalue + long_name = definition of NetCDF float FillValue + units = none + dimensions = () + type = real + kind = kind_phys +[lheatstrg] + standard_name = flag_for_canopy_heat_storage_in_land_surface_scheme + long_name = flag for canopy heat storage parameterization + units = flag + dimensions = () + type = logical +[h0facu] + standard_name = multiplicative_tuning_parameter_for_reduced_surface_heat_fluxes_due_to_canopy_heat_storage + long_name = canopy heat storage factor for sensible heat flux in unstable surface layer + units = none + dimensions = () + type = real + kind = kind_phys +[h0facs] + standard_name = multiplicative_tuning_parameter_for_reduced_latent_heat_flux_due_to_canopy_heat_storage + long_name = canopy heat storage factor for sensible heat flux in stable surface layer + units = none + dimensions = () + type = real + kind = kind_phys +[lsoil] + standard_name = vertical_dimension_of_soil + long_name = number of soil layers + units = count + dimensions = () + type = integer +[kice] + standard_name = vertical_dimension_of_sea_ice + long_name = vertical loop extent for ice levels, start at 1 + units = count + dimensions = () + type = integer +[lsm_ruc] + standard_name = identifier_for_ruc_land_surface_scheme + long_name = flag for RUC land surface model + units = flag + dimensions = () + type = integer + +######################################################################## +[ccpp-table-properties] + name = MED_coupling_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_coupling_type + type = ddt +[dtsfcin_med] + standard_name = surface_upward_sensible_heat_flux_over_ocean_from_mediator + long_name = sfc sensible heat flux input over ocean for coupling + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[dqsfcin_med] + standard_name = surface_upward_latent_heat_flux_over_ocean_from_mediator + long_name = sfc latent heat flux input over ocean for coupling + units = W m-2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + +######################################################################## +[ccpp-table-properties] + name = MED_grid_type + type = ddt + dependencies = +[ccpp-arg-table] + name = MED_grid_type + type = ddt +[area] + standard_name = cell_area + long_name = area of the grid cell + units = m2 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + +######################################################################## +[ccpp-table-properties] + name = MED_sfcprop_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_sfcprop_type + type = ddt +[vtype] + standard_name = vegetation_type_classification + long_name = vegetation type for lsm + units = index + dimensions = (horizontal_loop_extent) + type = integer +[shdmax] + standard_name = max_vegetation_area_fraction + long_name = max fractional coverage of green vegetation + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zorlw] + standard_name = surface_roughness_length_over_water + long_name = surface roughness length over water + units = cm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zorll] + standard_name = surface_roughness_length_over_land + long_name = surface roughness length over land + units = cm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zorli] + standard_name = surface_roughness_length_over_ice + long_name = surface roughness length over ice + units = cm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zorlwav] + standard_name = surface_roughness_length_from_wave_model + long_name = surface roughness length from wave model + units = cm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[slmsk] + standard_name = area_type + long_name = landmask: sea/land/ice=0/1/2 + units = flag + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[lakefrac] + standard_name = lake_area_fraction + long_name = fraction of horizontal grid area occupied by lake + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[lakedepth] + standard_name = lake_depth + long_name = lake depth + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[landfrac] + standard_name = land_area_fraction + long_name = fraction of horizontal grid area occupied by land + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tprcp] + standard_name = nonnegative_lwe_thickness_of_precipitation_amount_on_dynamics_timestep + long_name = total precipitation amount in each time step + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[oceanfrac] + standard_name = sea_area_fraction + long_name = fraction of horizontal grid area occupied by ocean + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[fice] + standard_name = sea_ice_area_fraction_of_sea_area_fraction + long_name = ice fraction over open water + units = frac + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[hice] + standard_name = sea_ice_thickness + long_name = sea ice thickness + units = m + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tsfco] + standard_name = sea_surface_temperature + long_name = sea surface temperature + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[uustar] + standard_name = surface_friction_velocity + long_name = boundary layer parameter + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tsfc] + standard_name = surface_skin_temperature + long_name = surface skin temperature + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[snodi] + standard_name = surface_snow_thickness_water_equivalent_over_ice + long_name = water equivalent snow depth over ice + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[snodl] + standard_name = surface_snow_thickness_water_equivalent_over_land + long_name = water equivalent snow depth over land + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[qss] + standard_name = surface_specific_humidity + long_name = surface air saturation specific humidity + units = kg kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[weasdi] + standard_name = water_equivalent_accumulated_snow_depth_over_ice + long_name = water equiv of acc snow depth over land + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[weasdl] + standard_name = water_equivalent_accumulated_snow_depth_over_land + long_name = water equiv of acc snow depth over land + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[snowd] + standard_name = lwe_surface_snow + long_name = water equivalent snow depth + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[weasd] + standard_name = lwe_thickness_of_surface_snow_amount + long_name = water equiv of acc snow depth over land and sea ice + units = mm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffhh] + standard_name = Monin_Obukhov_similarity_function_for_heat + long_name = Monin-Obukhov similarity function for heat + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[ffmm] + standard_name = Monin_Obukhov_similarity_function_for_momentum + long_name = Monin-Obukhov similarity function for momentum + units = none + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[zorl] + standard_name = surface_roughness_length + long_name = surface roughness length + units = cm + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[evap] + standard_name = surface_upward_specific_humidity_flux + long_name = kinematic surface upward latent heat flux + units = kg kg-1 m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[hflx] + standard_name = surface_upward_temperature_flux + long_name = kinematic surface upward sensible heat flux + units = K m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[tiice] + standard_name = temperature_in_ice_layer + long_name = sea ice internal temperature + units = K + dimensions = (horizontal_loop_extent,vertical_dimension_of_sea_ice) + type = real + kind = kind_phys +[t2m] + standard_name = air_temperature_at_2m + long_name = 2 meter temperature + units = K + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[q2m] + standard_name = specific_humidity_at_2m + long_name = 2 meter specific humidity + units = kg kg-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[f10m] + standard_name = ratio_of_wind_at_surface_adjacent_layer_to_wind_at_10m + long_name = ratio of sigma level 1 wind and 10m wind + units = ratio + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + +######################################################################## +[ccpp-table-properties] + name = MED_diag_type + type = ddt + dependencies = + +[ccpp-arg-table] + name = MED_diag_type + type = ddt +[chh] + standard_name = surface_drag_mass_flux_for_heat_and_moisture_in_air + long_name = thermal exchange coefficient + units = kg m-2 s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys +[cmm] + standard_name = surface_drag_wind_speed_for_momentum_in_air + long_name = momentum exchange coefficient + units = m s-1 + dimensions = (horizontal_loop_extent) + type = real + kind = kind_phys + +######################################################################## +[ccpp-table-properties] + name = MED_typedefs + type = module + relative_path = ../../../../../FV3/ccpp/physics/physics + dependencies = machine.F,physcons.F90,physparam.f + +[ccpp-arg-table] + name = MED_typedefs + type = module +[MED_init_type] + standard_name = MED_init_type + long_name = definition of type MED_init_type + units = DDT + dimensions = () + type = MED_init_type +[MED_statein_type] + standard_name = MED_statein_type + long_name = definition of type MED_statein_type + units = DDT + dimensions = () + type = MED_statein_type +[MED_interstitial_type] + standard_name = MED_interstitial_type + long_name = definition of type MED_interstitial_type + units = DDT + dimensions = () + type = MED_interstitial_type +[MED_control_type] + standard_name = MED_control_type + long_name = definition of type MED_control_type + units = DDT + dimensions = () + type = MED_control_type +[MED_coupling_type] + standard_name = MED_coupling_type + long_name = definition of type MED_coupling_type + units = DDT + dimensions = () + type = MED_coupling_type +[MED_grid_type] + standard_name = MED_grid_type + long_name = definition of type MED_grid_type + units = DDT + dimensions = () + type = MED_grid_type +[MED_sfcprop_type] + standard_name = MED_sfcprop_type + long_name = definition of type MED_sfcprop_type + units = DDT + dimensions = () + type = MED_sfcprop_type +[MED_diag_type] + standard_name = MED_diag_type + long_name = definition of type MED_diag_type + units = DDT + dimensions = () + type = MED_diag_type +[con_hvap] + standard_name = latent_heat_of_vaporization_of_water_at_0C + long_name = latent heat of evaporation/sublimation + units = J kg-1 + dimensions = () + type = real + kind = kind_phys +[con_cp] + standard_name = specific_heat_of_dry_air_at_constant_pressure + long_name = specific heat of dry air at constant pressure + units = J kg-1 K-1 + dimensions = () + type = real + kind = kind_phys +[con_rd] + standard_name = gas_constant_of_dry_air + long_name = ideal gas constant for dry air + units = J kg-1 K-1 + dimensions = () + type = real + kind = kind_phys +[con_eps] + standard_name = ratio_of_dry_air_to_water_vapor_gas_constants + long_name = rd/rv + units = none + dimensions = () + type = real + kind = kind_phys +[con_epsm1] + standard_name = ratio_of_dry_air_to_water_vapor_gas_constants_minus_one + long_name = (rd/rv) - 1 + units = none + dimensions = () + type = real + kind = kind_phys +[con_fvirt] + standard_name = ratio_of_vapor_to_dry_air_gas_constants_minus_one + long_name = (rv/rd) - 1 (rv = ideal gas constant for water vapor) + units = none + dimensions = () + type = real + kind = kind_phys +[con_g] + standard_name = gravitational_acceleration + long_name = gravitational acceleration + units = m s-2 + dimensions = () + type = real + kind = kind_phys +[con_tice] + standard_name = freezing_point_temperature_of_seawater + long_name = freezing point temperature of seawater + units = K + dimensions = () + type = real + kind = kind_phys diff --git a/ufs/ccpp/driver/med_ccpp_driver.F90 b/ufs/ccpp/driver/med_ccpp_driver.F90 new file mode 100644 index 000000000..8a867e1cd --- /dev/null +++ b/ufs/ccpp/driver/med_ccpp_driver.F90 @@ -0,0 +1,91 @@ +module med_ccpp_driver + + use ccpp_types, only: ccpp_t + use ccpp_static_api_med, only: ccpp_physics_init + use ccpp_static_api_med, only: ccpp_physics_run + use ccpp_static_api_med, only: ccpp_physics_finalize + + use MED_data, only: physics, cdata + + implicit none + + private ! default private + + public :: med_ccpp_driver_init + public :: med_ccpp_driver_run + public :: med_ccpp_driver_finalize + +!=============================================================================== +contains +!=============================================================================== + + subroutine med_ccpp_driver_init(ccpp_suite) + implicit none + + !--- input arguments -------------------------------- + character(len=*), intent(in) :: ccpp_suite + + !--- local variables -------------------------------- + integer :: ierr + + ! for physics running over the entire domain, block and thread + ! number are not used; set to safe values + cdata%blk_no = 1 + cdata%thrd_no = 1 + + ! initialize CCPP physics (run all _init routines) + call ccpp_physics_init(cdata, suite_name=trim(ccpp_suite), ierr=ierr) + if (ierr /= 0) then + write(0,'(a)') "An error occurred in ccpp_physics_init" + write(0,'(a)') trim(cdata%errmsg) + return + end if + + end subroutine med_ccpp_driver_init + + !============================================================================= + subroutine med_ccpp_driver_run(ccpp_suite, group) + implicit none + + !--- input arguments -------------------------------- + character(len=*), intent(in) :: ccpp_suite + character(len=*), optional, intent(in) :: group + + !--- local variables -------------------------------- + integer :: ierr + + ! run CCPP physics (run all _run routines) + if (present(group)) then + call ccpp_physics_run(cdata, suite_name=trim(ccpp_suite), group_name=trim(group), ierr=ierr) + else + call ccpp_physics_run(cdata, suite_name=trim(ccpp_suite), ierr=ierr) + end if + if (ierr /= 0) then + write(0,'(a)') "An error occurred in ccpp_physics_run" + write(0,'(a)') trim(cdata%errmsg) + return + end if + + end subroutine med_ccpp_driver_run + + !============================================================================= + subroutine med_ccpp_driver_finalize(ccpp_suite) + implicit none + + !--- input arguments -------------------------------- + character(len=*), intent(in) :: ccpp_suite + + !--- local variables -------------------------------- + integer :: ierr + + ! finalize CCPP physics (run all _finalize routines) + call ccpp_physics_finalize(cdata, suite_name=trim(ccpp_suite), ierr=ierr) + if (ierr /= 0) then + write(0,'(a)') "An error occurred in ccpp_physics_finalize" + write(0,'(a)') trim(cdata%errmsg) + return + end if + + end subroutine med_ccpp_driver_finalize + +end module med_ccpp_driver diff --git a/ufs/ccpp/suites/suite_FV3_sfc_ocean.xml b/ufs/ccpp/suites/suite_FV3_sfc_ocean.xml new file mode 100644 index 000000000..5017d407e --- /dev/null +++ b/ufs/ccpp/suites/suite_FV3_sfc_ocean.xml @@ -0,0 +1,19 @@ + + + + + + GFS_surface_composites_pre + + + sfc_diff + GFS_surface_loop_control_part1 + sfc_ocean + GFS_surface_loop_control_part2 + + + GFS_surface_composites_post + sfc_diag + + + diff --git a/ufs/flux_atmocn_ccpp_mod.F90 b/ufs/flux_atmocn_ccpp_mod.F90 new file mode 100644 index 000000000..9dafda8eb --- /dev/null +++ b/ufs/flux_atmocn_ccpp_mod.F90 @@ -0,0 +1,556 @@ +module flux_atmocn_ccpp_mod + + use ESMF, only : operator(-), operator(/) + use ESMF, only : ESMF_GridComp, ESMF_Time, ESMF_SUCCESS, ESMF_FAILURE + use ESMF, only : ESMF_Clock, ESMF_TimeInterval, ESMF_ClockGet + use ESMF, only : ESMF_GridCompGetInternalState, ESMF_LOGMSG_INFO + use ESMF, only : ESMF_LogWrite + use NUOPC, only : NUOPC_CompAttributeGet + use NUOPC_Mediator, only : NUOPC_MediatorGet + + use physcons, only : p0 => con_p0 + use physcons, only : cappa => con_rocp + use physcons, only : cp => con_cp + use physcons, only : hvap => con_hvap + use physcons, only : sbc => con_sbc + + use MED_data, only : physics + use med_ccpp_driver, only : med_ccpp_driver_init + use med_ccpp_driver, only : med_ccpp_driver_run + use med_ccpp_driver, only : med_ccpp_driver_finalize + + use ufs_const_mod + use ufs_io_mod, only : read_initial, read_restart, write_restart + use med_kind_mod, only : R8=>SHR_KIND_R8, CS=>SHR_KIND_CS + use med_kind_mod, only : CL=>SHR_KIND_CL + use med_utils_mod, only : chkerr => med_utils_chkerr + use med_internalstate_mod, only : aoflux_ccpp_suite, logunit + use med_internalstate_mod, only : InternalState, mastertask + use med_constants_mod, only : dbug_flag => med_constants_dbug_flag + + implicit none + + private ! default private + + public :: flux_atmOcn_ccpp ! computes atm/ocn fluxes + + integer, save :: restart_freq + integer :: layout(2) + real(r8), save :: semis_water + character(len=cs), save :: starttype + character(len=cl), save :: ini_file + character(len=cl), save :: rst_file + character(len=cl), save :: mosaic_file + character(len=cl), save :: input_dir + character(len=1) , save :: listDel = "," + logical , save :: ini_read + + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine flux_atmOcn_ccpp(gcomp, mastertask, logunit, nMax, mask, psfc, pbot, & + tbot, qbot, zbot, garea, ubot, usfc, vbot, vsfc, rbot, ts, lwdn, sen, lat, & + lwup, evp, taux, tauy, tref, qref, duu10n, ustar_sv, re_sv, ssq_sv, missval) + + implicit none + + !--- input arguments -------------------------------- + type(ESMF_GridComp), intent(in) :: gcomp ! gridded component + logical , intent(in) :: mastertask ! master task + integer , intent(in) :: logunit ! log file unit number + integer , intent(in) :: nMax ! data vector length + integer , intent(in) :: mask (nMax) ! ocn domain mask + real(r8), intent(in) :: psfc(nMax) ! atm P (surface) (Pa) + real(r8), intent(in) :: pbot(nMax) ! atm P (bottom) (Pa) + real(r8), intent(in) :: tbot(nMax) ! atm T (bottom) (K) + real(r8), intent(in) :: qbot(nMax) ! atm specific humidity (bottom) (kg/kg) + real(r8), intent(in) :: zbot(nMax) ! atm level height (m) + real(r8), intent(in) :: garea(nMax) ! grid area (m^2) + real(r8), intent(in) :: ubot(nMax) ! atm u wind (bottom) (m/s) + real(r8), intent(in) :: usfc(nMax) ! atm u wind (surface) (m/s) + real(r8), intent(in) :: vbot(nMax) ! atm v wind (bottom) (m/s) + real(r8), intent(in) :: vsfc(nMax) ! atm v wind (surface) (m/s) + real(r8), intent(in) :: rbot(nMax) ! atm density (kg/m^3) + real(r8), intent(in) :: lwdn(nMax) ! atm lw downward (W/m^2) + real(r8), intent(in) :: ts(nMax) ! ocn surface temperature (K) + real(r8), intent(in), optional :: missval ! masked value + + !--- output arguments ------------------------------- + real(r8), intent(out) :: sen(nMax) ! heat flux: sensible (W/m^2) + real(r8), intent(out) :: lat(nMax) ! heat flux: latent (W/m^2) + real(r8), intent(out) :: lwup(nMax) ! heat flux: lw upward (W/m^2) + real(r8), intent(out) :: evp(nMax) ! heat flux: evap ((kg/s)/m^2) + real(r8), intent(out) :: taux(nMax) ! surface stress, zonal (N) + real(r8), intent(out) :: tauy(nMax) ! surface stress, maridional (N) + real(r8), intent(out) :: tref (nMax) ! diag: 2m ref height T (K) + real(r8), intent(out) :: qref(nMax) ! diag: 2m ref humidity (kg/kg) + real(r8), intent(out) :: duu10n(nMax) ! diag: 10m wind speed squared (m/s)^2 + real(r8), intent(out) :: ustar_sv(nMax) ! diag: ustar + real(r8), intent(out) :: re_sv (nMax) ! diag: sqrt of exchange coefficient (water) + real(r8), intent(out) :: ssq_sv(nMax) ! diag: sea surface humidity (kg/kg) + + !--- local variables -------------------------------- + type(ESMF_Clock) :: mclock + type(ESMF_Time) :: currtime, starttime + type(ESMF_TimeInterval) :: timeStep + type(InternalState) :: is_local + integer :: n, rc + real(r8) :: spval + logical :: isPresent, isSet + character(len=cs) :: cvalue, cname + logical, save :: first_call = .true. + character(len=*), parameter :: subname=' (flux_atmOcn_ccpp) ' + !--------------------------------------- + + rc = ESMF_SUCCESS + + nullify(is_local%wrap) + call ESMF_GridCompGetInternalState(gcomp, is_local, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! missing value + if (present(missval)) then + spval = missval + else + spval = shr_const_spval + endif + + !---------------------- + ! Determine clock, starttime and currtime + !---------------------- + + call NUOPC_MediatorGet(gcomp, mediatorClock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGet(mclock, currtime=currTime, starttime=startTime, timeStep=timeStep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! init CCPP and setup/allocate variables + if (first_call) then + ! initalize model related parameters + call physics%model%init() + + ! allocate and initalize data structures + call physics%statein%create(nMax,physics%model) + call physics%stateout%create(nMax) + call physics%interstitial%create(nMax) + call physics%coupling%create(nMax) + call physics%grid%create(nMax) + call physics%sfcprop%create(nMax,physics%model) + call physics%diag%create(nMax) + + ! initalize dimension + physics%init%im = nMax + + ! determine CCPP/physics specific options + ! semis_water, surface emissivity for lw radiation + ! semis_wat is constant and set to 0.97 in setemis() call + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_semis_water", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + semis_water = 0.97 + if (isPresent .and. isSet) then + read(cvalue,*) semis_water + end if + + ! lseaspray + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_lseaspray", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%lseaspray = .true. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.false.' .or. trim(cvalue) .eq. 'false') physics%model%lseaspray = .false. + end if + + ! ivegsrc + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_ivegsrc", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%ivegsrc = 1 + if (isPresent .and. isSet) then + read(cvalue,*) physics%model%ivegsrc + end if + + ! redrag + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_redrag", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%redrag = .true. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.false.' .or. trim(cvalue) .eq. 'false') physics%model%redrag = .false. + end if + + ! lsm + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_lsm", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%lsm = 1 + if (isPresent .and. isSet) then + read(cvalue,*) physics%model%lsm + end if + + ! frac_grid + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_frac_grid", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%frac_grid = .true. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.false.' .or. trim(cvalue) .eq. 'false') physics%model%frac_grid = .false. + end if + + ! restart + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_restart", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%restart = .false. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.true.' .or. trim(cvalue) .eq. 'true') physics%model%restart = .true. + end if + + ! cplice + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_cplice", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%cplice = .true. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.false.' .or. trim(cvalue) .eq. 'false') physics%model%cplice = .false. + end if + + ! cplflx + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_cplflx", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%cplflx = .true. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.false.' .or. trim(cvalue) .eq. 'false') physics%model%cplflx = .false. + end if + + ! lheatstrg + call NUOPC_CompAttributeGet(gcomp, name="ccpp_phy_lheatstrg", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + physics%model%lheatstrg = .true. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.false.' .or. trim(cvalue) .eq. 'false') physics%model%lheatstrg = .false. + end if + + ! determine CCPP/host model specific options + ! restart interval, set it to < 0 for no restart + call NUOPC_CompAttributeGet(gcomp, name="ccpp_restart_interval", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + read(cvalue,*) restart_freq + else + restart_freq = 3600 ! write restart file every hour + end if + + ! file name for restart + call NUOPC_CompAttributeGet(gcomp, name='ccpp_restart_file', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + rst_file = trim(cvalue) + else + rst_file = 'unset' + end if + + ! file name for initial conditions + call NUOPC_CompAttributeGet(gcomp, name='ccpp_ini_file_prefix', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + ini_file = trim(cvalue) + else + ini_file = 'INPUT/sfc_data.tile' + end if + + ! name of mosaic file that will be used to read tiled files + call NUOPC_CompAttributeGet(gcomp, name='ccpp_ini_mosaic_file', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (isPresent .and. isSet) then + mosaic_file = trim(cvalue) + else + if (trim(rst_file) == 'unset') then + call ESMF_LogWrite(trim(subname)//': ccpp_ini_mosaic_file is required to read tiled initial condition!', ESMF_LOGMSG_INFO) + rc = ESMF_FAILURE + return + end if + end if + + ! input directory for tiled CS grid files + call NUOPC_CompAttributeGet(gcomp, name='ccpp_input_dir', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (isPresent .and. isSet) then + input_dir = trim(cvalue) + else + input_dir = "INPUT/" + end if + + ! layout to read tiled CS grid files + call NUOPC_CompAttributeGet(gcomp, name='ccpp_ini_layout', value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (isPresent .and. isSet) then + do n = 1, 2 + call string_listGetName(cvalue, n, cname, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + if (rc == ESMF_FAILURE) return + read(cname,*) layout(n) + end do + else + layout(:) = -1 + end if + + ! flag for reading initial conditions + call NUOPC_CompAttributeGet(gcomp, name="ccpp_ini_read", value=cvalue, isPresent=isPresent, isSet=isSet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ini_read = .false. + if (isPresent .and. isSet) then + if (trim(cvalue) .eq. '.true.' .or. trim(cvalue) .eq. 'true') ini_read = .true. + end if + + if (mastertask) then + write(logunit,*) '========================================================' + write(logunit,'(a,f5.2)') trim(subname)//' ccpp_phy_semis_water = ', semis_water + write(logunit,'(a,l)') trim(subname)//' ccpp_phy_lseaspray = ', physics%model%lseaspray + write(logunit,'(a,i2)') trim(subname)//' ccpp_phy_ivegsrc = ', physics%model%ivegsrc + write(logunit,'(a,l)') trim(subname)//' ccpp_phy_redrag = ', physics%model%redrag + write(logunit,'(a,i2)') trim(subname)//' ccpp_phy_lsm = ', physics%model%lsm + write(logunit,'(a,l)') trim(subname)//' ccpp_phy_frac_grid = ', physics%model%frac_grid + write(logunit,'(a,l)') trim(subname)//' ccpp_phy_restart = ', physics%model%restart + write(logunit,'(a,l)') trim(subname)//' ccpp_phy_cplice = ', physics%model%cplice + write(logunit,'(a,l)') trim(subname)//' ccpp_phy_cplflx = ', physics%model%cplflx + write(logunit,'(a,l)') trim(subname)//' ccpp_phy_lheatstrg = ', physics%model%lheatstrg + write(logunit,'(a,i5)') trim(subname)//' ccpp_restart_interval = ', restart_freq + write(logunit,'(a)') trim(subname)//' ccpp_ini_file_prefix = '//trim(ini_file) + write(logunit,'(a)') trim(subname)//' ccpp_ini_mosaic_file = '//trim(mosaic_file) + write(logunit,'(a)') trim(subname)//' ccpp_input_dir = '//trim(input_dir) + write(logunit,'(a)') trim(subname)//' ccpp_restart_file = '//trim(rst_file) + write(logunit,*) '========================================================' + end if + + ! read restart + call NUOPC_CompAttributeGet(gcomp, name='start_type', value=cvalue, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + read(cvalue,*) starttype + if (trim(starttype) == trim('startup')) then + ! TODO: this is just extra leyer of protection since reading of initial condition is not stable yet + if (ini_read) call read_initial(gcomp, ini_file, mosaic_file, input_dir, layout, rc) + else + call read_restart(gcomp, rst_file, rc) + end if + + ! run CCPP init + ! TODO: suite name need to be provided by ESMF config file + call med_ccpp_driver_init(trim(aoflux_ccpp_suite)) + end if + + ! fill in atmospheric forcing + physics%statein%pgr(:) = psfc(:) + physics%statein%ugrs(:) = ubot(:) + physics%statein%vgrs(:) = vbot(:) + physics%statein%tgrs(:) = tbot(:) + physics%statein%qgrs(:) = qbot(:) + physics%statein%prsl(:) = pbot(:) + physics%statein%zlvl(:) = zbot(:) + physics%statein%prsik(:) = (psfc(:)/p0)**cappa + physics%statein%prslk(:) = (pbot(:)/p0)**cappa + physics%statein%u10m(:) = usfc(:) + physics%statein%v10m(:) = vsfc(:) + + ! fill in updated states by physics, currently set to statein + physics%stateout%gu0(:) = ubot(:) + physics%stateout%gv0(:) = vbot(:) + physics%stateout%gt0(:) = tbot(:) + physics%stateout%gq0(:) = qbot(:) + + ! fill in grid related variables + physics%grid%area(:) = garea(:) + + ! set counter + physics%model%kdt = ((currTime-StartTime)/timeStep)+1 + if (mastertask .and. dbug_flag > 5) then + write(logunit,'(a,i5)') 'kdt = ', physics%model%kdt + end if + + ! reset physics variables, mimic GFS_suite_interstitial_phys_reset + call physics%interstitial%phys_reset() + + ! init required variables to mimic GFS_surface_generic_pre + ! TODO: the wind calculation in GFS_surface_generic_pre has cnvwind adjustment + physics%interstitial%wind = sqrt(ubot(:)*ubot(:)+vbot(:)*vbot(:)) + physics%interstitial%prslki = physics%statein%prsik(:)/physics%statein%prslk(:) + + ! init required variables to mimic GFS_surface_composites_pre (assumes no ice) + physics%interstitial%uustar_water(:) = physics%sfcprop%uustar(:) + physics%sfcprop%tsfco(:) = ts(:) + physics%sfcprop%tsfc(:) = ts(:) + physics%interstitial%tsfc_water(:) = physics%sfcprop%tsfc(:) + physics%interstitial%tsurf_water(:) = physics%sfcprop%tsfc(:) + physics%sfcprop%zorlw(:) = physics%sfcprop%zorl(:) + do n = 1, nMax + physics%sfcprop%zorlw(n) = max(1.0e-5, min(1.0d0, physics%sfcprop%zorlw(n))) + end do + + ! init other variables + if (first_call .and. trim(starttype) == trim('continue')) then + physics%interstitial%qss_water(:) = physics%sfcprop%qss(:) + else + physics%sfcprop%qss(:) = qbot(:) + physics%interstitial%qss_water(:) = qbot(:) + end if + + ! calculate wet flag and ocean fraction based on masking, assumes full oceean + where (mask(:) /= 0) + physics%interstitial%wet = .true. + physics%sfcprop%oceanfrac = 1.0d0 + elsewhere + physics%sfcprop%oceanfrac = 0.0d0 + end where + + ! run CCPP physics + ! TODO: suite name need to be provided by ESMF config file + call med_ccpp_driver_run(trim(aoflux_ccpp_suite), 'physics') + + ! unit and sign conversion to be consistent with other flux scheme (CESM) + do n = 1, nMax + if (mask(n) /= 0) then + sen(n) = -1.0_r8*physics%interstitial%hflx_water(n)*rbot(n)*cp + lat(n) = -1.0_r8*physics%interstitial%evap_water(n)*rbot(n)*hvap + lwup(n) = -1.0_r8*(semis_water*sbc*ts(n)**4+(1.0_r8-semis_water)*lwdn(n)) + evp(n) = lat(n)/hvap + taux(n) = rbot(n)*physics%interstitial%stress_water(n)*ubot(n)/physics%interstitial%wind(n) + tauy(n) = rbot(n)*physics%interstitial%stress_water(n)*vbot(n)/physics%interstitial%wind(n) + tref(n) = physics%sfcprop%t2m(n) + qref(n) = physics%sfcprop%q2m(n) + duu10n(n) = physics%interstitial%wind(n)*physics%interstitial%wind(n) + ustar_sv(n) = physics%interstitial%uustar_water(n) + re_sv(n) = physics%interstitial%cmm_water(n) + ssq_sv(n) = physics%interstitial%qss_water(n) + else + sen(n) = spval + lat(n) = spval + lwup(n) = spval + evp(n) = spval + taux(n) = spval + tauy(n) = spval + tref(n) = spval + qref(n) = spval + duu10n(n) = spval + ustar_sv(n) = spval + re_sv(n) = spval + ssq_sv(n) = spval + end if + end do + + ! write restart file + call write_restart(gcomp, restart_freq, rc) + + ! set first call flag + first_call = .false. + + end subroutine flux_atmOcn_ccpp + + !=============================================================================== + subroutine string_listGetName(list, k, name, rc) + + ! ---------------------------------------------- + ! Get name of k-th field in list + ! It is adapted from CDEPS, shr_string_listGetName + ! ---------------------------------------------- + + implicit none + + ! input/output variables + character(*) , intent(in) :: list ! list/string + integer , intent(in) :: k ! index of field + character(*) , intent(out) :: name ! k-th name in list + integer , intent(out) :: rc + + ! local variables + integer :: i,n ! generic indecies + integer :: kFlds ! number of fields in list + integer :: i0,i1 ! name = list(i0:i1) + character(*), parameter :: subName = '(shr_string_listGetName)' + ! ---------------------------------------------- + + rc = ESMF_SUCCESS + + !--- check that this is a valid index --- + kFlds = string_listGetNum(list) + if (k < 1 .or. kFlds < k) then + call ESMF_LogWrite(trim(subname)//": ERROR invalid index ", ESMF_LOGMSG_INFO) + rc = ESMF_FAILURE + end if + + !--- start with whole list, then remove fields before and after desired + !field --- + i0 = 1 + i1 = len_trim(list) + + !--- remove field names before desired field --- + do n=2,k + i = index(list(i0:i1),listDel) + i0 = i0 + i + end do + + !--- remove field names after desired field --- + if ( k < kFlds ) then + i = index(list(i0:i1),listDel) + i1 = i0 + i - 2 + end if + + !--- copy result into output variable --- + name = list(i0:i1)//" " + + end subroutine string_listGetName + + !=============================================================================== + integer function string_listGetNum(str) + + ! ---------------------------------------------- + ! Get number of fields in a string list + ! It is adapted from CDEPS, string_listGetNum + ! ---------------------------------------------- + + implicit none + + ! input/output variables + character(*), intent(in) :: str ! string to search + + ! local variables + integer :: count ! counts occurances of char + character(*), parameter :: subName = '(string_listGetNum)' + ! ---------------------------------------------- + + string_listGetNum = 0 + + if (len_trim(str) > 0) then + count = string_countChar(str,listDel) + string_listGetNum = count + 1 + endif + + end function string_listGetNum + + !=============================================================================== + integer function string_countChar(str,char,rc) + + ! ---------------------------------------------- + ! Count number of occurances of a character + ! It is adapted from CDEPS, string_countChar + ! ---------------------------------------------- + + implicit none + + ! input/output variables + character(*), intent(in) :: str ! string to search + character(1), intent(in) :: char ! char to search for + integer, intent(out), optional :: rc ! return code + + ! local variables + integer :: count ! counts occurances of char + integer :: n ! generic index + character(*), parameter :: subName = '(string_countChar)' + ! ---------------------------------------------- + + count = 0 + do n = 1, len_trim(str) + if (str(n:n) == char) count = count + 1 + end do + string_countChar = count + + end function string_countChar + +end module flux_atmocn_ccpp_mod diff --git a/ufs/ufs_io_mod.F90 b/ufs/ufs_io_mod.F90 new file mode 100644 index 000000000..ee85fa183 --- /dev/null +++ b/ufs/ufs_io_mod.F90 @@ -0,0 +1,882 @@ + module ufs_io_mod + + use ESMF, only : operator(-) + use ESMF, only : ESMF_VM, ESMF_VMGet, ESMF_VMGetCurrent, ESMF_LogWrite + use ESMF, only : ESMF_GridComp, ESMF_GridCompGet, ESMF_SUCCESS, ESMF_FAILURE + use ESMF, only : ESMF_Field, ESMF_LOGMSG_INFO, ESMF_LOGMSG_ERROR + use ESMF, only : ESMF_Grid, ESMF_Decomp_Flag, ESMF_DECOMP_SYMMEDGEMAX + use ESMF, only : ESMF_GridCreateMosaic, ESMF_INDEX_GLOBAL, ESMF_TYPEKIND_R8 + use ESMF, only : ESMF_STAGGERLOC_CENTER, ESMF_STAGGERLOC_CORNER + use ESMF, only : ESMF_GridCompGetInternalState, ESMF_KIND_R8 + use ESMF, only : ESMF_ArraySpec, ESMF_ArraySpecSet, ESMF_MESHLOC_ELEMENT + use ESMF, only : ESMF_FieldCreate, ESMF_FieldGet, ESMF_FieldDestroy + use ESMF, only : ESMF_RouteHandle, ESMF_RouteHandleIsCreated, ESMF_FieldRedist + use ESMF, only : ESMF_MeshGet, ESMF_FieldRegrid, ESMF_FieldRegridStore + use ESMF, only : ESMF_FieldBundle, ESMF_FieldBundleCreate, ESMF_FieldBundleAdd + use ESMF, only : ESMF_FieldWriteVTK, ESMF_VMAllFullReduce, ESMF_REDUCE_SUM + use ESMF, only : ESMF_Mesh, ESMF_Calendar, ESMF_Clock, ESMF_ClockGet + use ESMF, only : ESMF_ClockGetNextTime, ESMF_TimeIntervalGet + use ESMF, only : ESMF_Time, ESMF_TimeGet, ESMF_TimeInterval + use ESMF, only : ESMF_FieldBundleIsCreated, ESMF_FieldBundleGet + use ESMF, only : ESMF_FieldBundleRemove, ESMF_FieldBundleDestroy + use ESMF, only : ESMF_FieldWrite, ESMF_FieldBundleRead, ESMF_FieldBundleWrite + use ESMF, only : ESMF_REGRIDMETHOD_CONSERVE_2ND, ESMF_MeshCreate + use ESMF, only : ESMF_TERMORDER_SRCSEQ, ESMF_REGION_TOTAL + use NUOPC, only : NUOPC_CompAttributeGet + use NUOPC_Mediator, only : NUOPC_MediatorGet + + use fms_mod, only : fms_init + use fms2_io_mod, only : open_file, FmsNetcdfFile_t + use mosaic2_mod, only : get_mosaic_ntiles, get_mosaic_grid_sizes + use mosaic2_mod, only : get_mosaic_contact, get_mosaic_ncontacts + use mpp_mod, only : mpp_pe, mpp_root_pe, mpp_error, FATAL + use mpp_domains_mod, only : mpp_define_layout, mpp_get_compute_domain + use mpp_domains_mod, only : mpp_domains_init, mpp_define_mosaic, domain2d + use mpp_io_mod, only : MPP_RDONLY, MPP_NETCDF, MPP_SINGLE, MPP_MULTI + use mpp_io_mod, only : mpp_get_info, mpp_get_fields, mpp_get_atts + use mpp_io_mod, only : mpp_open, mpp_read, fieldtype + + use med_kind_mod, only : r8=>SHR_KIND_R8, cs=>SHR_KIND_CS, cl=>SHR_KIND_CL + use med_utils_mod, only : chkerr => med_utils_chkerr + use med_constants_mod, only : dbug_flag => med_constants_dbug_flag + use med_internalstate_mod, only : InternalState, mastertask, logunit + use med_internalstate_mod, only : compatm, compocn, mapconsf + use med_io_mod, only : med_io_date2yyyymmdd, med_io_sec2hms, med_io_ymd2date + use ufs_const_mod, only : shr_const_cday + use med_methods_mod, only : fldbun_getdata1d => med_methods_FB_getdata1d + use med_methods_mod, only : fldbun_diagnose => med_methods_FB_diagnose + use med_methods_mod, only : FB_fldchk => med_methods_FB_FldChk + use med_methods_mod, only : FB_getfldptr => med_methods_FB_GetFldPtr + + use MED_data, only : physics + + implicit none + + private ! default private + + public read_initial + public read_restart + public write_restart + + type domain_type + type(ESMF_Grid) :: grid ! ESMF grid object from mosaic file + type(ESMF_Mesh) :: mesh ! ESMF mesh object from CS grid + type(ESMF_RouteHandle) :: rh ! ESMF routehandle object to redist data from CS grid to mesh + type(domain2d) :: mosaic_domain ! domain object created by FMS + integer :: layout(2) ! layout for domain decomposition + integer, allocatable :: nit(:) ! size of tile in i direction + integer, allocatable :: njt(:) ! size of tile in j direction + integer :: ntiles ! number of tiles in case of having CS grid + integer :: ncontacts ! number of contacts in case of having CS grid + integer, allocatable :: tile1(:) ! list of tile numbers in tile 1 of each contact + integer, allocatable :: tile2(:) ! list of tile numbers in tile 2 of each contact + integer, allocatable :: istart1(:) ! list of starting i-index in tile 1 of each contact + integer, allocatable :: iend1(:) ! list of ending i-index in tile 1 of each contact + integer, allocatable :: jstart1(:) ! list of starting j-index in tile 1 of each contact + integer, allocatable :: jend1(:) ! list of ending j-index in tile 1 of each contact + integer, allocatable :: istart2(:) ! list of starting i-index in tile 2 of each contact + integer, allocatable :: iend2(:) ! list of ending i-index in tile 2 of each contact + integer, allocatable :: jstart2(:) ! list of starting j-index in tile 2 of each contact + integer, allocatable :: jend2(:) ! list of ending j-index in tile 2 of each contact + end type domain_type + + character(cl) :: case_name = 'unset' ! case name + + character(*), parameter :: modName = "(ufs_io_mod)" + character(*), parameter :: u_FILE_u = & + __FILE__ + +!=============================================================================== +contains +!=============================================================================== + + subroutine read_initial(gcomp, ini_file, mosaic_file, input_dir, layout, rc) + + implicit none + + ! input/output variables + type(ESMF_GridComp), intent(in) :: gcomp + character(len=cl), intent(in) :: ini_file + character(len=cl), intent(in) :: mosaic_file + character(len=cl), intent(in) :: input_dir + integer :: layout(2) + integer, intent(inout) :: rc + + ! local variables + type(domain_type) :: domain + type(InternalState) :: is_local + type(ESMF_RouteHandle) :: rh + type(ESMF_Field) :: lfield, field, field_dst + real(ESMF_KIND_R8), pointer :: ptr(:) + integer :: n + character(len=cs), allocatable :: flds(:) + character(len=*), parameter :: subname = trim(modName)//': (read_initial) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + nullify(is_local%wrap) + call ESMF_GridCompGetInternalState(gcomp, is_local, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! --------------------- + ! Create domain + ! --------------------- + + call create_fms_domain(gcomp, domain, mosaic_file, layout, rc) + + ! --------------------- + ! Create grid + ! --------------------- + + call create_grid(gcomp, domain, mosaic_file, input_dir, rc) + + !---------------------- + ! Read data + !---------------------- + + allocate(flds(2)) + flds = (/ 'zorl ', & + 'uustar' /) + do n = 1,size(flds) + ! read from tiled file + call read_tiled_file(gcomp, ini_file, trim(flds(n)), domain, field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! create destination field + field_dst = ESMF_FieldCreate(is_local%wrap%aoflux_mesh, ESMF_TYPEKIND_R8, & + name=trim(flds(n)), meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! create rh + call ESMF_FieldRegridStore(field, field_dst, routehandle=rh, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! map field + if (is_local%wrap%aoflux_grid == 'agrid') then + ! do nothing, just redist in case of haning different decomp. in here and aoflux mesh + call ESMF_FieldRedist(field, field_dst, rh, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + else + ! remap from atm to ocn or exchange grid + call ESMF_FieldRegrid(field, field_dst, rh, termorderflag=ESMF_TERMORDER_SRCSEQ, zeroregion=ESMF_REGION_TOTAL, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! debug + if (dbug_flag > 5) then + call ESMF_FieldWriteVTK(field_dst, 'ini_'//trim(flds(n))//'_'//trim(is_local%wrap%aoflux_grid), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! return pointer and fill variable + call ESMF_FieldGet(field_dst, localDe=0, farrayPtr=ptr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + if (mastertask) write(logunit,'(a)') 'Reading: '//trim(flds(n)) + if (trim(flds(n)) == 'zorl' ) physics%sfcprop%zorl(:) = ptr(:) + if (trim(flds(n)) == 'uustar') physics%sfcprop%uustar(:)= ptr(:) + nullify(ptr) + + ! free memory + call ESMF_FieldDestroy(field_dst, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end do + + ! free memory + if (allocated(flds)) deallocate(flds) + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine read_initial + + !=============================================================================== + subroutine read_restart(gcomp, rst_file, rc) + implicit none + + ! input/output variables + type(ESMF_GridComp), intent(in) :: gcomp ! gridded component + character(len=cl), intent(inout):: rst_file ! restart file + integer, intent(inout) :: rc ! return code + + ! local variables + type(ESMF_Field) :: field, lfield + type(ESMF_Clock) :: mclock + type(ESMF_Time) :: currtime + type(ESMF_TimeInterval) :: timeStep + type(ESMF_FieldBundle), save :: FBin + type(InternalState) :: is_local + integer :: n, yr, mon, day, sec + real(r8), pointer :: ptr(:) + character(len=cl) :: currtime_str + character(len=cs), allocatable :: flds(:) + character(len=*), parameter :: subname=trim(modName)//': (read_restart) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + nullify(is_local%wrap) + call ESMF_GridCompGetInternalState(gcomp, is_local, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Set restart file name + !---------------------- + + if (trim(case_name) == 'unset') then + call NUOPC_CompAttributeGet(gcomp, name='case_name', value=case_name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (trim(rst_file) == 'unset') then + call NUOPC_MediatorGet(gcomp, mediatorClock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_ClockGet(mclock, currTime=currTime, timeStep=timeStep, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_TimeGet(currTime, yy=yr, mm=mon, dd=day, s=sec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(currtime_str,'(i4.4,a,i2.2,a,i2.2,a,i5.5)') yr,'-',mon,'-',day,'-',sec + rst_file = trim(case_name)//'.cpl.ccpp.'//trim(currtime_str)//'.nc' + end if + + !---------------------- + ! Now read in the restart file + !---------------------- + + if (mastertask) then + write(logunit,'(a)') 'Reading CCPP restart file: '//trim(rst_file) + end if + + ! create FB + FBin = ESMF_FieldBundleCreate(rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! add fields + allocate(flds(3)) + flds = (/ 'zorl ', & + 'uustar', & + 'qss ' /) + do n = 1,size(flds) + field = ESMF_FieldCreate(is_local%wrap%aoflux_mesh, ESMF_TYPEKIND_R8, & + name=trim(flds(n)), meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + call ESMF_FieldGet(field, farrayptr=ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + ptr(:) = 0.0_r8 + nullify(ptr) + call ESMF_FieldBundleAdd(FBin, (/field/), rc=rc) + end do + + ! read file to FB + call ESMF_FieldBundleRead(FBin, trim(rst_file), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! debug + if (dbug_flag > 1) then + call ESMF_LogWrite(trim(subname)//' diagnose at '//trim(currtime_str), ESMF_LOGMSG_INFO) + call fldbun_diagnose(FBin, string=trim(subname)//' CCPP FBin ', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + !---------------------- + ! Fill internal data structures + !---------------------- + + do n = 1,size(flds) + if (FB_FldChk(FBin, trim(flds(n)), rc=rc)) then + call FB_getfldptr(FBin, trim(flds(n)), ptr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (mastertask) write(logunit,'(a)') 'Reading: '//trim(flds(n)) + if (trim(flds(n)) == 'zorl' ) physics%sfcprop%zorl(:) = ptr(:) + if (trim(flds(n)) == 'uustar') physics%sfcprop%uustar(:)= ptr(:) + if (trim(flds(n)) == 'qss' ) physics%sfcprop%qss(:) = ptr(:) + + nullify(ptr) + + ! debug + if (dbug_flag > 5) then + call ESMF_FieldBundleGet(FBin, fieldName=trim(flds(n)), field=lfield, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_FieldWriteVTK(lfield, 'rst_'//trim(flds(n))//'_'//trim(is_local%wrap%aoflux_grid), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + end if + end do + + !---------------------- + ! Free memory + !---------------------- + + do n = 1,size(flds) + if (FB_FldChk(FBin, trim(flds(n)), rc=rc)) then + ! get field from FB + call ESMF_FieldBundleGet(FBin, trim(flds(n)), field=field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! remove field from FB + call ESMF_FieldBundleRemove(FBin, (/ trim(flds(n)) /), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ! remove field + call ESMF_FieldDestroy(field, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + end do + deallocate(flds) + + ! remove FB + call ESMF_FieldBundleDestroy(FBin, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine read_restart + + !=============================================================================== + subroutine create_fms_domain(gcomp, domain, mosaic_file, layout, rc) + implicit none + + ! input/output variables + type(ESMF_GridComp), intent(in) :: gcomp + type(domain_type), intent(inout) :: domain + character(len=cl), intent(in) :: mosaic_file + integer :: layout(2) + integer, intent(inout) :: rc + + ! local variables + type(ESMF_VM) :: vm + type(FmsNetcdfFile_t) :: mosaic_fileobj + integer :: mpicomm, npes_per_tile + integer :: n, ntiles, npet + integer :: halo = 0 + integer :: global_indices(4,6) + integer :: layout2d(2,6) + integer, allocatable :: pe_start(:), pe_end(:) + character(len=cl) :: msg + character(len=*), parameter :: subname = trim(modName)//': (create_fms_domain) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + ! --------------------- + ! Initialize FMS + ! --------------------- + + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_VMGet(vm=vm, mpiCommunicator=mpicomm, petCount=npet, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call fms_init(mpicomm) + + ! --------------------- + ! Open mosaic file and query some information + ! --------------------- + + if (.not. open_file(mosaic_fileobj, trim(mosaic_file), 'read')) then + call ESMF_LogWrite(trim(subname)//'error in opening file '//trim(mosaic_file), ESMF_LOGMSG_ERROR) + rc = ESMF_FAILURE + return + end if + + ! query number of tiles + domain%ntiles = get_mosaic_ntiles(mosaic_fileobj) + + ! query domain sizes for each tile + if (.not. allocated(domain%nit)) allocate(domain%nit(domain%ntiles)) + if (.not. allocated(domain%njt)) allocate(domain%njt(domain%ntiles)) + call get_mosaic_grid_sizes(mosaic_fileobj, domain%nit, domain%njt) + + ! query number of contacts + domain%ncontacts = get_mosaic_ncontacts(mosaic_fileobj) + + ! allocate required arrays to create FMS domain from mosaic file + if (.not. allocated(domain%tile1)) allocate(domain%tile1(domain%ncontacts)) + if (.not. allocated(domain%tile2)) allocate(domain%tile2(domain%ncontacts)) + if (.not. allocated(domain%istart1)) allocate(domain%istart1(domain%ncontacts)) + if (.not. allocated(domain%iend1)) allocate(domain%iend1(domain%ncontacts)) + if (.not. allocated(domain%jstart1)) allocate(domain%jstart1(domain%ncontacts)) + if (.not. allocated(domain%jend1)) allocate(domain%jend1(domain%ncontacts)) + if (.not. allocated(domain%istart2)) allocate(domain%istart2(domain%ncontacts)) + if (.not. allocated(domain%iend2)) allocate(domain%iend2(domain%ncontacts)) + if (.not. allocated(domain%jstart2)) allocate(domain%jstart2(domain%ncontacts)) + if (.not. allocated(domain%jend2)) allocate(domain%jend2(domain%ncontacts)) + + ! query information about contacts + call get_mosaic_contact(mosaic_fileobj, domain%tile1, domain%tile2, & + domain%istart1, domain%iend1, domain%jstart1, domain%jend1, & + domain%istart2, domain%iend2, domain%jstart2, domain%jend2) + + ! print out debug information + if (dbug_flag > 2) then + do n = 1, domain%ncontacts + write(msg, fmt='(A,I2,A,2I5)') trim(subname)//' : tile1, tile2 (', n ,') = ', domain%tile1(n), domain%tile2(n) + call ESMF_LogWrite(trim(msg), ESMF_LOGMSG_INFO) + write(msg, fmt='(A,I2,A,4I5)') trim(subname)//' : istart1, iend1, jstart1, jend1 (', n ,') = ', & + domain%istart1(n), domain%iend1(n), domain%jstart1(n), domain%jend1(n) + call ESMF_LogWrite(trim(msg), ESMF_LOGMSG_INFO) + write(msg, fmt='(A,I2,A,4I5)') trim(subname)//' : istart2, iend2, jstart2, jend2 (', n ,') = ', & + domain%istart2(n), domain%iend2(n), domain%jstart2(n), domain%jend2(n) + call ESMF_LogWrite(trim(msg), ESMF_LOGMSG_INFO) + end do + end if + + !---------------------- + ! Initialize domain + !---------------------- + + call mpp_domains_init() + + !---------------------- + ! Find out layout that will be used to read the data + !---------------------- + + ! setup global indices + do n = 1, domain%ntiles + global_indices(1,n) = 1 + global_indices(2,n) = domain%nit(n) + global_indices(3,n) = 1 + global_indices(4,n) = domain%njt(n) + end do + + ! check total number of PETs + if (mod(npet, domain%ntiles) /= 0) then + write(msg, fmt='(A,I5)') trim(subname)//' : nPet should be multiple of 6 to read initial conditions but it is ', npet + call ESMF_LogWrite(trim(msg), ESMF_LOGMSG_ERROR) + rc = ESMF_FAILURE + return + end if + + ! calculate layout if it is not provided as configuration option + if (layout(1) < 0 .and. layout(2) < 0) then + npes_per_tile = npet/domain%ntiles + call mpp_define_layout(global_indices(:,1), npes_per_tile, domain%layout) + else + domain%layout(:) = layout(:) + end if + + ! set layout and print out debug information + do n = 1, domain%ntiles + layout2d(:,n) = domain%layout(:) + if (dbug_flag > 2) then + write(msg, fmt='(A,I2,A,2I5)') trim(subname)//' layout (', n ,') = ', layout2d(1,n), layout2d(2,n) + call ESMF_LogWrite(trim(msg), ESMF_LOGMSG_INFO) + write(msg, fmt='(A,I2,A,4I5)') trim(subname)//' global_indices (', n,') = ', & + global_indices(1,n), global_indices(2,n), global_indices(3,n), global_indices(4,n) + call ESMF_LogWrite(trim(msg), ESMF_LOGMSG_INFO) + end if + enddo + + !---------------------- + ! Set pe_start, pe_end + !---------------------- + + allocate(pe_start(domain%ntiles)) + allocate(pe_end(domain%ntiles)) + do n = 1, domain%ntiles + pe_start(n) = mpp_root_pe()+(n-1)*domain%layout(1)*domain%layout(2) + pe_end(n) = mpp_root_pe()+n*domain%layout(1)*domain%layout(2)-1 + if (dbug_flag > 2) then + write(msg, fmt='(A,I2,A,2I5)') trim(subname)//' pe_start, pe_end (', n ,') = ', pe_start(n), pe_end(n) + call ESMF_LogWrite(trim(msg), ESMF_LOGMSG_INFO) + end if + enddo + + !---------------------- + ! Create FMS domain object + !---------------------- + + call mpp_define_mosaic(global_indices, layout2d, domain%mosaic_domain, & + domain%ntiles, domain%ncontacts, domain%tile1, domain%tile2, & + domain%istart1, domain%iend1, domain%jstart1, domain%jend1, & + domain%istart2, domain%iend2, domain%jstart2, domain%jend2, & + pe_start, pe_end, symmetry=.true., & + whalo=halo, ehalo=halo, shalo=halo, nhalo=halo, & + name='atm domain') + + !---------------------- + ! Deallocate temporary arrays + !---------------------- + + deallocate(pe_start) + deallocate(pe_end) + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine create_fms_domain + + !=============================================================================== + subroutine create_grid(gcomp, domain, mosaic_file, input_dir, rc) + implicit none + + ! input/output variables + type(ESMF_GridComp), intent(in) :: gcomp + type(domain_type), intent(inout) :: domain + character(len=cl), intent(in) :: mosaic_file + character(len=cl), intent(in) :: input_dir + integer, intent(inout) :: rc + + ! local variables + type(ESMF_Decomp_Flag) :: decompflagPTile(2,6) + integer :: n + integer :: decomptile(2,6) + character(len=*), parameter :: subname = trim(modName)//': (create_grid) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' called', ESMF_LOGMSG_INFO) + + ! TODO: currently this is only tested with global application + ! set decomposition + do n = 1, domain%ntiles + decomptile(1,n) = domain%layout(1) + decomptile(2,n) = domain%layout(2) + decompflagPTile(:,n) = (/ ESMF_DECOMP_SYMMEDGEMAX, ESMF_DECOMP_SYMMEDGEMAX /) + end do + + ! create grid + domain%grid = ESMF_GridCreateMosaic(filename=trim(mosaic_file), & + regDecompPTile=decomptile, tileFilePath=trim(input_dir), decompflagPTile=decompflagPTile, & + staggerlocList=(/ESMF_STAGGERLOC_CENTER, ESMF_STAGGERLOC_CORNER/), & + indexflag=ESMF_INDEX_GLOBAL, name='input_grid', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! create mesh + domain%mesh = ESMF_MeshCreate(domain%grid, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call ESMF_LogWrite(subname//' done', ESMF_LOGMSG_INFO) + + end subroutine create_grid + + !=============================================================================== + subroutine read_tiled_file(gcomp, filename, varname, domain, field_dst, rc) + implicit none + + ! input/output variables + type(ESMF_GridComp), intent(in) :: gcomp + character(len=*), intent(in) :: filename + character(len=*), intent(in) :: varname + type(domain_type), intent(inout) :: domain + type(ESMF_Field), intent(inout) :: field_dst + integer, intent(inout), optional :: rc + + ! local variables + type(ESMF_Field) :: field_src, field_tmp + type(ESMF_ArraySpec) :: arraySpec + type(InternalState) :: is_local + type(fieldtype), allocatable:: vars(:) + integer :: funit, my_tile + integer :: i, j, n + integer :: isc, iec, jsc, jec + integer :: ndim, nvar, natt, ntime + logical :: not_found, is_root_pe + real(ESMF_KIND_R8), pointer :: ptr2d(:,:) + real(r8), allocatable :: rdata(:,:) + character(len=cl) :: cname + character(len=*), parameter :: subname=trim(modName)//': (read_tiled_file) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + call ESMF_LogWrite(subname//' reading '//trim(varname), ESMF_LOGMSG_INFO) + + !---------------------- + ! Get the internal state from the mediator component + !---------------------- + + nullify(is_local%wrap) + call ESMF_GridCompGetInternalState(gcomp, is_local, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Set tile + !---------------------- + my_tile = int(mpp_pe()/(domain%layout(1)*domain%layout(2)))+1 + + is_root_pe = .false. + if (mpp_pe() == (my_tile-1)*(domain%layout(1)*domain%layout(2))) is_root_pe = .true. + + !---------------------- + ! Open file and query file attributes + !---------------------- + + write(cname, fmt='(A,I1,A)') trim(filename), my_tile, '.nc' + call mpp_open(funit, trim(cname), action=MPP_RDONLY, form=MPP_NETCDF, threading=MPP_MULTI, fileset=MPP_SINGLE, is_root_pe=is_root_pe) + call mpp_get_info(funit, ndim, nvar, natt, ntime) + allocate(vars(nvar)) + call mpp_get_fields(funit, vars(:)) + + !---------------------- + ! Find and read requested variable + !---------------------- + + not_found = .true. + do n = 1, nvar + ! get variable name + call mpp_get_atts(vars(n), name=cname) + + ! check variable name + if (trim(cname) == trim(varname)) then + ! get array bounds or domain + call mpp_get_compute_domain(domain%mosaic_domain, isc, iec, jsc, jec) + + ! allocate data array and set initial value + allocate(rdata(isc:iec,jsc:jec)) + rdata(:,:) = 0.0_r8 + + ! read data + call mpp_read(funit, vars(n), domain%mosaic_domain, rdata, 1) + + ! set missing values to zero + where (rdata == 1.0e20) + rdata(:,:) = 0.0_r8 + end where + end if + + not_found = .false. + end do + + if (not_found) then + call mpp_error(FATAL, 'File being read is not the expected one. '//trim(varname)//' is not found.') + end if + + !---------------------- + ! Move data from grid to mesh + !---------------------- + + ! set type and rank for ESMF arrayspec + call ESMF_ArraySpecSet(arraySpec, typekind=ESMF_TYPEKIND_R8, rank=2, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! create source field + field_src = ESMF_FieldCreate(domain%grid, arraySpec, staggerloc=ESMF_STAGGERLOC_CENTER, & + indexflag=ESMF_INDEX_GLOBAL, name=trim(varname), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get pointer and fill it + call ESMF_FieldGet(field_src, localDe=0, farrayPtr=ptr2d, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + ptr2d(:,:) = rdata(:,:) + nullify(ptr2d) + if (allocated(rdata)) deallocate(rdata) + + ! create destination field + field_dst = ESMF_FieldCreate(domain%mesh, ESMF_TYPEKIND_R8, name=trim(varname), & + meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! create routehandle from grid to mesh + if (.not. ESMF_RouteHandleIsCreated(domain%rh, rc=rc)) then + call ESMF_FieldRegridStore(field_src, field_dst, routehandle=domain%rh, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! redist field from ESMF Grid to Mesh + call ESMF_FieldRedist(field_src, field_dst, domain%rh, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Output result field for debugging purpose + !---------------------- + + if (dbug_flag > 2) then + call ESMF_FieldWrite(field_dst, trim(varname)//'_agrid.nc', variableName=trim(varname), overwrite=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (dbug_flag > 5) then + call ESMF_FieldWriteVTK(field_dst, trim(varname)//'_agrid', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! clean memory + call ESMF_FieldDestroy(field_src, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine read_tiled_file + + !=============================================================================== + subroutine write_restart(gcomp, restart_freq, rc) + implicit none + + ! input/output variableswrite_restart + type(ESMF_GridComp), intent(in) :: gcomp ! gridded component + integer, intent(in) :: restart_freq ! restart interval in hours + integer, intent(inout) :: rc ! return code + + ! local variables + type(ESMF_VM) :: vm + type(ESMF_Field) :: field + type(ESMF_Clock) :: mclock + type(ESMF_Calendar) :: calendar + type(ESMF_Time) :: currtime, starttime, nexttime + type(ESMF_TimeInterval) :: timediff(2) + type(ESMF_FieldBundle), save :: FBout + type(InternalState) :: is_local + integer :: yr, mon, day, sec + integer :: n, m, ns, start_ymd + character(cl) :: time_units + real(r8) :: time_val + real(r8) :: time_bnds(2) + real(r8), pointer :: ptr(:) + character(len=cl) :: tmpstr + character(len=cl) :: rst_file + character(len=cl) :: nexttime_str + integer, save :: ns_total + logical, save :: first_call = .true. + character(len=cs), allocatable :: flds(:) + character(len=*), parameter :: subname=trim(modName)//': (write_restart) ' + !------------------------------------------------------------------------------- + + rc = ESMF_SUCCESS + + nullify(is_local%wrap) + call ESMF_GridCompGetInternalState(gcomp, is_local, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Determine clock, starttime, currtime and nexttime + !---------------------- + + call NUOPC_MediatorGet(gcomp, mediatorClock=mclock, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGet(mclock, currtime=currtime, starttime=starttime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_ClockGetNextTime(mclock, nextTime=nexttime, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Determine time units + !---------------------- + + call ESMF_TimeGet(starttime, yy=yr, mm=mon, dd=day, s=sec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call med_io_ymd2date(yr, mon, day, start_ymd) + time_units = 'days since '//trim(med_io_date2yyyymmdd(start_ymd))//' '//med_io_sec2hms(sec, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Determine restart file name + !---------------------- + + if (trim(case_name) == 'unset') then + call NUOPC_CompAttributeGet(gcomp, name='case_name', value=case_name, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + call ESMF_TimeGet(nexttime, yy=yr, mm=mon, dd=day, s=sec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + write(nexttime_str,'(i4.4,a,i2.2,a,i2.2,a,i5.5)') yr,'-',mon,'-',day,'-',sec + rst_file = trim(case_name)//'.cpl.ccpp.'//trim(nexttime_str)//'.nc' + + ! return if it is not time to write restart + if (restart_freq < 0) return + if (mod(sec, restart_freq) /= 0) return + + !---------------------- + ! Create restart file + !---------------------- + + call ESMF_GridCompGet(gcomp, vm=vm, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + !---------------------- + ! Define time dimension + !---------------------- + + timediff(1) = nexttime - starttime + call ESMF_TimeIntervalGet(timediff(1), d=day, s=sec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + time_val = day + sec/real(shr_const_cday,r8) + time_bnds(1) = time_val + time_bnds(2) = time_val + + !---------------------- + ! Create FB and add fields to it + !---------------------- + + if (first_call) then + ! create FB + FBout = ESMF_FieldBundleCreate(rc=rc) + + ! get total element count + call ESMF_MeshGet(is_local%wrap%aoflux_mesh, elementCount=ns, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMAllFullReduce(vm, (/ns/), ns_total, 1, ESMF_REDUCE_SUM, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! add fields + allocate(flds(3)) + flds = (/ 'zorl ', & + 'uustar', & + 'qss ' /) + do n = 1,size(flds) + ! create new field on aoflux mesh + field = ESMF_FieldCreate(is_local%wrap%aoflux_mesh, ESMF_TYPEKIND_R8, & + name=trim(flds(n)), meshloc=ESMF_MESHLOC_ELEMENT, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! get pointer out of field + call ESMF_FieldGet(field, farrayptr=ptr, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! fill pointer + if (trim(flds(n)) == 'zorl' ) ptr(:) = physics%sfcprop%zorl(:) + if (trim(flds(n)) == 'uustar') ptr(:) = physics%sfcprop%uustar(:) + if (trim(flds(n)) == 'qss' ) ptr(:) = physics%sfcprop%qss(:) + nullify(ptr) + + ! add field to FB + call ESMF_FieldBundleAdd(FBout, (/field/), rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + end do + else + do n = 1,size(flds) + ! retrieve field pointer from FB + call fldbun_getdata1d(FBout, trim(flds(n)), ptr, rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! fill pointer + if (trim(flds(n)) == 'zorl' ) ptr(:) = physics%sfcprop%zorl(:) + if (trim(flds(n)) == 'uustar') ptr(:) = physics%sfcprop%uustar(:) + if (trim(flds(n)) == 'qss' ) ptr(:) = physics%sfcprop%qss(:) + nullify(ptr) + end do + end if + + ! debug + if (dbug_flag > 1) then + call ESMF_LogWrite(trim(subname)//' diagnose at '//trim(nexttime_str), ESMF_LOGMSG_INFO) + call fldbun_diagnose(FBout, string=trim(subname)//' CCPP FBout ', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! debug + if (dbug_flag > 5) then + do n = 1,size(flds) + ! retrieve field from FB + call ESMF_FieldBundleGet(FBout, fieldName=trim(flds(n)), field=field, rc=rc) + if (chkerr(rc,__LINE__,u_FILE_u)) return + + ! write field in VTK format + call ESMF_FieldWriteVTK(field, 'rst_'//trim(flds(n))//'_'//trim(is_local%wrap%aoflux_grid)//'_'//trim(nexttime_str), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end do + end if + + !---------------------- + ! Write data + !---------------------- + + call ESMF_FieldBundleWrite(FBout, trim(rst_file), overwrite=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (mastertask) then + write(logunit,'(a)') 'CCPP restart file is closed: '//trim(rst_file) + end if + + end subroutine write_restart + + end module ufs_io_mod