diff --git a/.gitignore b/.gitignore index 34b286f3e..625692541 100644 --- a/.gitignore +++ b/.gitignore @@ -31,5 +31,9 @@ *.out *.app +# Externals +fox +share/genf90 + # ignore pycache __pycache__ diff --git a/.gitmodules b/.gitmodules index e5e608420..45cad096c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,16 +1,3 @@ # This is a git-fleximod adapted .gitmodules file. Any field with a name starting in fx is a git-fleximod # specific field. See https://github.com/ESMCI/git-fleximod for details. -[submodule "fox"] -path = fox -url = https://github.com/ESMCI/fox.git -fxtag = 4.1.2.4 -fxrequired = AlwaysRequired -fxDONOTUSEurl = https://github.com/ESMCI/fox.git - -[submodule "genf90"] -path = share/genf90 -url = https://github.com/PARALLELIO/genf90 -fxtag = 4816965 -fxrequired = AlwaysRequired -fxDONOTUSEurl = https://github.com/PARALLELIO/genf90 diff --git a/datm/CMakeLists.txt b/datm/CMakeLists.txt index 8225f5c1f..2951724fa 100644 --- a/datm/CMakeLists.txt +++ b/datm/CMakeLists.txt @@ -12,7 +12,6 @@ set(SRCFILES atm_comp_nuopc.F90 datm_pres_ndep_mod.F90 datm_pres_o3_mod.F90) - foreach(FILE ${SRCFILES}) if(EXISTS "${CASEROOT}/SourceMods/src.datm/${FILE}") list(REMOVE_ITEM SRCFILES ${FILE}) diff --git a/datm/atm_comp_nuopc.F90 b/datm/atm_comp_nuopc.F90 index f49db0ca6..793483474 100644 --- a/datm/atm_comp_nuopc.F90 +++ b/datm/atm_comp_nuopc.F90 @@ -63,6 +63,11 @@ module cdeps_datm_comp use datm_datamode_gefs_mod , only : datm_datamode_gefs_init_pointers use datm_datamode_gefs_mod , only : datm_datamode_gefs_advance + use datm_datamode_ufs_mod , only : datm_datamode_ufs_advertise + use datm_datamode_ufs_mod , only : datm_datamode_ufs_init_pointers + use datm_datamode_ufs_mod , only : datm_datamode_ufs_advance + use datm_datamode_ufs_mod , only : ufs_datamode_state + use datm_datamode_simple_mod , only : datm_datamode_simple_advertise use datm_datamode_simple_mod , only : datm_datamode_simple_init_pointers use datm_datamode_simple_mod , only : datm_datamode_simple_advance @@ -115,6 +120,7 @@ module cdeps_datm_comp logical :: restart_read ! start from restart character(CL) :: case_name ! case name character(len=*) , parameter :: nullstr = 'null' + type(ufs_datamode_state) :: ufs_state ! datm_in namelist input character(CX) :: nlfilename = nullstr ! filename to obtain namelist info from @@ -141,6 +147,8 @@ module cdeps_datm_comp logical :: skip_restart_read = .false. ! true => skip restart read in continuation run logical :: export_all = .false. ! true => export all fields, do not check connected or not logical :: first_call = .true. + + character(CX) :: calc_opts = nullstr ! derived variable calculation options ! linked lists type(fldList_type) , pointer :: fldsImport => null() @@ -249,7 +257,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) skip_restart_read, & flds_presndep, & flds_preso3, & - export_all + export_all, & + calc_opts rc = ESMF_SUCCESS @@ -305,6 +314,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) write(logunit,'(2a,l6)') subname,' flds_co2 = ',flds_co2 write(logunit,'(2a,l6)') subname,' skip_restart_read = ',skip_restart_read write(logunit,'(2a,l6)') subname,' export_all = ',export_all + write(logunit,'(3a)') subname,' calc_opts = ',trim(calc_opts) bcasttmp = 0 bcasttmp(1) = nx_global @@ -341,6 +351,8 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, bcasttmp, 10, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_VMBroadcast(vm, calc_opts, CX, main_task, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return nx_global = bcasttmp(1) ny_global = bcasttmp(2) @@ -366,7 +378,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) select case (trim(datamode)) case ('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA', 'JRA55do', & 'CORE_RYF6162_JRA','CORE_RYF8485_JRA','CORE_RYF9091_JRA','CORE_RYF0304_JRA', & - 'CLMNCEP','CPLHIST','GEFS','ERA5','SIMPLE') + 'CLMNCEP','CPLHIST','GEFS','UFS','ERA5','SIMPLE') if (mainproc) write(logunit,'(3a)') subname,'datm datamode = ',trim(datamode) case default call shr_log_error(' ERROR illegal datm datamode = '//trim(datamode), rc=rc) @@ -407,6 +419,9 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) case ('GEFS') call datm_datamode_gefs_advertise(exportState, fldsExport, flds_scalar_name, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case ('UFS') + call datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_scalar_name, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return case ('SIMPLE') call datm_datamode_simple_advertise(exportState, fldsExport, flds_scalar_name, & nlfilename, my_task, vm, rc) @@ -532,7 +547,7 @@ subroutine ModelAdvance(gcomp, rc) type(ESMF_Time) :: nextTime type(ESMF_TimeInterval) :: timeStep real(r8) :: nextsw_cday - logical :: restart_write ! restart alarm is ringing + logical :: restart_write ! restart alarm is ringing integer :: next_ymd ! model date integer :: next_tod ! model sec into model date integer :: yr, mon, day ! year, month, day @@ -674,6 +689,9 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('GEFS') call datm_datamode_gefs_init_pointers(exportState, sdat, logunit, mainproc, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('UFS') + call datm_datamode_ufs_init_pointers(exportState, sdat, ufs_state, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return case('SIMPLE') call datm_datamode_simple_init_pointers(exportState, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -687,7 +705,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA',& 'CORE_RYF6162_JRA','CORE_RYF8485_JRA' ,& 'CORE_RYF9091_JRA','CORE_RYF0304_JRA' , 'JRA55do', & - 'CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + 'CLMNCEP','CPLHIST','ERA5','GEFS','UFS','SIMPLE') call dshr_restart_read(restfilm, rpfile, logunit, my_task, mpicom, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return case default @@ -752,6 +770,9 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('GEFS') call datm_datamode_gefs_advance(exportstate, sdat, mainproc, logunit, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return + case('UFS') + call datm_datamode_ufs_advance(exportState, ufs_state, calc_opts, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return case('SIMPLE') call datm_datamode_simple_advance(target_ymd, target_tod, target_mon, sdat%model_calendar, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -765,7 +786,7 @@ subroutine datm_comp_run(gcomp, importState, exportState, target_ymd, target_tod case('CORE2_NYF','CORE2_IAF','CORE_IAF_JRA',& 'CORE_RYF6162_JRA','CORE_RYF8485_JRA' ,& 'CORE_RYF9091_JRA','CORE_RYF0304_JRA','JRA55do' ,& - 'CLMNCEP','CPLHIST','ERA5','GEFS','SIMPLE') + 'CLMNCEP','CPLHIST','ERA5','GEFS','UFS','SIMPLE') call dshr_restart_write(rpfile, case_name, 'datm', inst_suffix, & target_ymd, target_tod, logunit, my_task, sdat, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/datm/datm_datamode_gefs_mod.F90 b/datm/datm_datamode_gefs_mod.F90 index 157cb5c94..82a1cfab0 100644 --- a/datm/datm_datamode_gefs_mod.F90 +++ b/datm/datm_datamode_gefs_mod.F90 @@ -39,7 +39,6 @@ module datm_datamode_gefs_mod real(r8), pointer :: Faxa_swvdf(:) => null() ! stream data - real(r8), pointer :: strm_Sa_mask(:) => null() real(r8), pointer :: strm_Sa_z(:) => null() real(r8), pointer :: strm_Sa_u(:) => null() real(r8), pointer :: strm_Sa_v(:) => null() @@ -135,9 +134,6 @@ subroutine datm_datamode_gefs_init_pointers(exportState, sdat, logunit, mainproc rc = ESMF_SUCCESS ! initialize pointers for module level stream arrays - call shr_strdata_get_stream_pointer( sdat, 'Sa_mask', strm_Sa_mask , requirePointer=.true., & - errmsg=subname//'ERROR: strm_Sa_mask must be associated for gefs datamode', rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return call shr_strdata_get_stream_pointer( sdat, 'Sa_z', strm_Sa_z , requirePointer=.true., & errmsg=subname//'ERROR: strm_Sa_z must be associated for gefs datamode', rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return @@ -256,7 +252,7 @@ subroutine datm_datamode_gefs_advance(exportstate, sdat, mainproc, logunit, rc) rc = ESMF_SUCCESS - lsize = size(strm_Sa_mask) + lsize = size(strm_Sa_tbot) if (first_time) then call ESMF_VMGetCurrent(vm, rc=rc) @@ -270,13 +266,6 @@ subroutine datm_datamode_gefs_advance(exportstate, sdat, mainproc, logunit, rc) if (mainproc) write(logunit,*) subname,' tbotmax = ',tbotmax - ! determine maskmax (see below for use) - rtmp(1) = maxval(strm_Sa_mask(:)) - call ESMF_VMAllReduce(vm, rtmp, rtmp(2:), 1, ESMF_REDUCE_MAX, rc=rc) - if (ChkErr(rc,__LINE__,u_FILE_u)) return - maskmax = rtmp(2) - if (mainproc) write(logunit,*) subname,' maskmax = ',maskmax - ! reset first_time first_time = .false. end if diff --git a/datm/datm_datamode_ufs_mod.F90 b/datm/datm_datamode_ufs_mod.F90 new file mode 100644 index 000000000..b350cc3eb --- /dev/null +++ b/datm/datm_datamode_ufs_mod.F90 @@ -0,0 +1,412 @@ +!=============================================================================== +! +! Module: datm_datamode_ufs_mod +! +! Description: +! Configurable datamode for UFS. Replaces hardcoded datamodes with a dynamic, +! configuration-driven approach. +! +! - datm_datamode_ufs_advertise: Parses config and advertises stream variables. +! - datm_datamode_ufs_init_pointers: Caches pass-through pointers in state object. +! - datm_datamode_ufs_advance: Executes raw copy and chained calculations in-place. +! +!=============================================================================== +module datm_datamode_ufs_mod + + use ESMF + use NUOPC + + ! CDEPS-native imports + use shr_kind_mod, only: r8 => shr_kind_r8 + use dshr_strdata_mod, only: shr_strdata_type, shr_strdata_get_stream_pointer + use dshr_methods_mod, only: dshr_state_getfldptr, chkerr + use shr_log_mod, only: shr_log_error + use dshr_stream_mod, only: shr_stream_streamType + use dshr_fldList_mod, only: fldList_type, dshr_fldList_add + + implicit none + private + + public :: datm_datamode_ufs_advertise + public :: datm_datamode_ufs_init_pointers + public :: datm_datamode_ufs_advance + public :: ufs_datamode_state + + character(len=*), parameter :: u_FILE_u = __FILE__ + + !> \brief Dynamic mapping for pass-through variables + type :: ufs_var_map + character(len=64) :: var_name + real(r8), pointer :: ptr_strm(:) => null() + real(r8), pointer :: ptr_exp(:) => null() + end type ufs_var_map + + !> \brief Instance-specific state object for thread-safe operations + type :: ufs_datamode_state + type(ufs_var_map), allocatable :: var_maps(:) + end type ufs_datamode_state + +contains + + subroutine add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) + + use shr_strconvert_mod, only : toString + + character(len=*), intent(in) :: streamfilename + type(fldList_type), pointer :: fldsExport + type(ufs_datamode_state), intent(inout) :: ufs_state + integer, intent(out) :: rc + + ! local variables + type(ESMF_VM) :: vm + type(ESMF_Config) :: cf + integer :: i, n, nstrms + integer :: myid + character(2) :: mystrm + integer :: istat + character(len=ESMF_MAXSTR), allocatable :: strm_tmpstrings(:) + type(shr_stream_streamType), allocatable :: streamdat(:) + + character(len=*), parameter :: u_FILE_u = __FILE__ + character(len=*), parameter :: subName = '(add_stream_variables_to_export)' + + rc = ESMF_SUCCESS + + ! allocate streamdat instance on all tasks + nstrms = 0 + + ! set ESMF config + cf = ESMF_ConfigCreate(rc=RC) + call ESMF_ConfigLoadFile(config=CF ,filename=trim(streamfilename), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! get number of streams + nstrms = ESMF_ConfigGetLen(config=CF, label='stream_info:', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! allocate an array of shr_stream_streamtype objects + if (nstrms > 0) then + allocate(streamdat(nstrms), stat=istat) + if ( istat /= 0 ) then + call shr_log_error(subName//': allocation error for streamdat with size '//toString(nstrms),rc=rc) + return + end if + else + call shr_log_error("no stream_info in config file "//trim(streamfilename), rc=rc) + return + endif + + do i=1, nstrms + ! Get name of stream variables in file and model + write(mystrm,"(I2.2)") i + streamdat(i)%nvars = ESMF_ConfigGetLen(config=CF, label="stream_data_variables"//mystrm//':', rc=rc) + if( streamdat(i)%nvars > 0) then + allocate(streamdat(i)%varlist(streamdat(i)%nvars), stat=istat) + if ( istat /= 0 ) then + call shr_log_error(subName//& + ': allocation error for streamdat('//toString(i)//')%varlist'//& + ' with size '//toString(streamdat(i)%nvars), rc=rc) + return + end if + allocate(strm_tmpstrings(streamdat(i)%nvars), stat=istat) + if ( istat /= 0 ) then + call shr_log_error(subName//& + ': allocation error for strm_tmpstrings('//toString(i)//')%varlist'//& + ' with size '//toString(streamdat(i)%nvars), rc=rc) + return + end if + call ESMF_ConfigGetAttribute(CF,valueList=strm_tmpstrings,label="stream_data_variables"//mystrm//':', rc=rc) + do n=1, streamdat(i)%nvars + streamdat(i)%varlist(n)%nameinfile = strm_tmpstrings(n)(1:index(trim(strm_tmpstrings(n)), " ")) + streamdat(i)%varlist(n)%nameinmodel = strm_tmpstrings(n)(index(trim(strm_tmpstrings(n)), " ", .true.)+1:) + + call append_var_map(ufs_state%var_maps, trim(streamdat(i)%varlist(n)%nameinmodel)) + call dshr_fldList_add(fldsExport, trim(streamdat(i)%varlist(n)%nameinmodel)) + enddo + deallocate(strm_tmpstrings) + else + call shr_log_error("stream data variables must be provided", rc=rc) + return + endif + end do ! i nstrms + + ! Clean up local memory + if (allocated(streamdat)) then + do i=1, nstrms + if (allocated(streamdat(i)%varlist)) deallocate(streamdat(i)%varlist) + end do + deallocate(streamdat) + end if + call ESMF_ConfigDestroy(config=CF, rc=RC) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + end subroutine add_stream_variables_to_export + + !============================================================================= + ! \brief Reads config streams and advertises to CDEPS field list + !============================================================================= + subroutine datm_datamode_ufs_advertise(exportState, fldsExport, ufs_state, flds_scalar_name, rc) + + type(esmf_State) , intent(inout) :: exportState + type(fldList_type), pointer :: fldsExport + type(ufs_datamode_state), intent(inout) :: ufs_state + character(len=*) , intent(in) :: flds_scalar_name + integer, intent(out) :: rc + + character(len=18) :: streamfilename = 'datm.streams' + type(fldlist_type), pointer :: fldList + + rc = ESMF_SUCCESS + + ! parse datm.streams stream_variables to fldsExport and ufs_state + call add_stream_variables_to_export(streamfilename, fldsExport, ufs_state, rc) + call dshr_fldList_add(fldsExport, trim(flds_scalar_name)) + + fldlist => fldsExport ! the head of the linked list + do while (associated(fldlist)) + call NUOPC_Advertise(exportState, standardName=fldlist%stdname, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call ESMF_LogWrite('(datm_comp_advertise): Fr_atm '//trim(fldList%stdname), ESMF_LOGMSG_INFO) + fldList => fldList%next + enddo + + end subroutine datm_datamode_ufs_advertise + + + !============================================================================= + ! \brief Caches pass-through pointers natively into the instance state object + !============================================================================= + subroutine datm_datamode_ufs_init_pointers(exportState, sdat, ufs_state, rc) + type(ESMF_State), intent(inout) :: exportState + type(shr_strdata_type), intent(inout) :: sdat + type(ufs_datamode_state), intent(inout) :: ufs_state + integer, intent(out) :: rc + + character(len=*), parameter :: subName = 'datm_datamode_ufs_init_pointers: ' + integer :: i + + rc = ESMF_SUCCESS + + ! Cache standard pass-through pointers to eliminate overhead in the run loop + if (allocated(ufs_state%var_maps)) then + do i = 1, size(ufs_state%var_maps) + call shr_strdata_get_stream_pointer(sdat, trim(ufs_state%var_maps(i)%var_name), & + ufs_state%var_maps(i)%ptr_strm, requirePointer=.true., & + errmsg=trim(subName)//'ERROR: stream pointer missing for '//trim(ufs_state%var_maps(i)%var_name), rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + call dshr_state_getfldptr(exportState, trim(ufs_state%var_maps(i)%var_name), & + fldptr1=ufs_state%var_maps(i)%ptr_exp, allowNullReturn=.true., rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end do + end if + + end subroutine datm_datamode_ufs_init_pointers + + + !============================================================================= + ! \brief Core run loop. Performs array copies and triggers calculation driver. + !============================================================================= + subroutine datm_datamode_ufs_advance(exportState, ufs_state, calc_opts, rc) + type(ESMF_State), intent(inout) :: exportState + type(ufs_datamode_state), intent(inout) :: ufs_state + character(len=*), intent(in) :: calc_opts + integer, intent(out) :: rc + + integer :: i + rc = ESMF_SUCCESS + + ! ------------------------------------------------------------------------- + ! Phase 1: Ingestion (Stream -> Export State) + ! 100% Native, 100% Thread-Safe Array Math + ! ------------------------------------------------------------------------- + if (allocated(ufs_state%var_maps)) then + do i = 1, size(ufs_state%var_maps) + if (associated(ufs_state%var_maps(i)%ptr_exp) .and. associated(ufs_state%var_maps(i)%ptr_strm)) then + ufs_state%var_maps(i)%ptr_exp(:) = ufs_state%var_maps(i)%ptr_strm(:) + end if + end do + end if + + ! ------------------------------------------------------------------------- + ! Phase 2: Chained Calculations Driver + ! ------------------------------------------------------------------------- + if (len_trim(calc_opts) > 0) then + call datm_datamode_ufs_calc_driver(exportState, calc_opts, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine datm_datamode_ufs_advance + + + !============================================================================= + ! \brief Driver subroutine to route execution based on calc_opts string + !============================================================================= + subroutine datm_datamode_ufs_calc_driver(exportState, calc_opts, rc) + type(ESMF_State), intent(inout) :: exportState + character(len=*), intent(in) :: calc_opts + integer, intent(out) :: rc + + rc = ESMF_SUCCESS + + if (index(calc_opts, 'convert_precip_accum_to_rate') > 0) then + call calc_convert_precip_accum_to_rate(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (index(calc_opts, 'convert_rad_accum_to_flux') > 0) then + call calc_convert_rad_accum_to_flux(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (index(calc_opts, 'partition_sw_4band') > 0) then + call calc_partition_sw_4band(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (index(calc_opts, 'partition_precip_freezing') > 0) then + call calc_partition_precip_freezing(exportState, rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + end subroutine datm_datamode_ufs_calc_driver + + + !============================================================================= + ! \brief Subroutine to dynamically append variables via Fortran 2003 move_alloc + !============================================================================= + subroutine append_var_map(maps_array, new_var_name) + type(ufs_var_map), allocatable, intent(inout) :: maps_array(:) + character(len=*), intent(in) :: new_var_name + + type(ufs_var_map), allocatable :: temp_maps(:) + integer :: current_size + + if (allocated(maps_array)) then + current_size = size(maps_array) + allocate(temp_maps(current_size + 1)) + temp_maps(1:current_size) = maps_array + temp_maps(current_size + 1)%var_name = trim(new_var_name) + call move_alloc(from=temp_maps, to=maps_array) + else + allocate(maps_array(1)) + maps_array(1)%var_name = trim(new_var_name) + end if + end subroutine append_var_map + + + !============================================================================= + ! Modular Calculation Subroutines + !============================================================================= + + subroutine calc_convert_precip_accum_to_rate(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + + character(len=*), parameter :: subName = 'calc_convert_precip_accum_to_rate: ' + real(r8), pointer :: Faxa_prec(:) => null() + + rc = ESMF_SUCCESS + call dshr_state_getfldptr(exportState, 'Faxa_prec', fldptr1=Faxa_prec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (.not. associated(Faxa_prec)) then + call shr_log_error(trim(subName)//'ERROR: Faxa_prec required for precip calculation.', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (associated(Faxa_prec)) then + Faxa_prec(:) = Faxa_prec(:) * (1000.0_r8 / 3600.0_r8) + end if + end subroutine calc_convert_precip_accum_to_rate + + + subroutine calc_convert_rad_accum_to_flux(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + + character(len=*), parameter :: subName = 'calc_convert_rad_accum_to_flux: ' + real(r8), pointer :: Faxa_swdn(:) => null() + real(r8), pointer :: Faxa_lwdn(:) => null() + + rc = ESMF_SUCCESS + call dshr_state_getfldptr(exportState, 'Faxa_swdn', fldptr1=Faxa_swdn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_lwdn', fldptr1=Faxa_lwdn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + ! Apply conversion safely to whatever radiation variables the user provided + if (associated(Faxa_swdn)) Faxa_swdn(:) = Faxa_swdn(:) / 3600.0_r8 + if (associated(Faxa_lwdn)) Faxa_lwdn(:) = Faxa_lwdn(:) / 3600.0_r8 + end subroutine calc_convert_rad_accum_to_flux + + + subroutine calc_partition_sw_4band(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + + character(len=*), parameter :: subName = 'calc_partition_sw_4band: ' + real(r8), pointer :: Faxa_swdn(:) => null() + real(r8), pointer :: Faxa_swndr(:) => null() + real(r8), pointer :: Faxa_swvdr(:) => null() + real(r8), pointer :: Faxa_swndf(:) => null() + real(r8), pointer :: Faxa_swvdf(:) => null() + + rc = ESMF_SUCCESS + + call dshr_state_getfldptr(exportState, 'Faxa_swdn', fldptr1=Faxa_swdn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndr', fldptr1=Faxa_swndr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdr', fldptr1=Faxa_swvdr, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swndf', fldptr1=Faxa_swndf, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_swvdf', fldptr1=Faxa_swvdf, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (.not. associated(Faxa_swdn)) then + call shr_log_error(trim(subName)//'ERROR: Faxa_swdn required as input for sw partitioning.', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + ! Only write to the output fields that the user explicitly allocated/advertised + if (associated(Faxa_swdn)) then + if (associated(Faxa_swndr)) Faxa_swndr(:) = Faxa_swdn(:) * 0.25_r8 + if (associated(Faxa_swvdr)) Faxa_swvdr(:) = Faxa_swdn(:) * 0.25_r8 + if (associated(Faxa_swndf)) Faxa_swndf(:) = Faxa_swdn(:) * 0.25_r8 + if (associated(Faxa_swvdf)) Faxa_swvdf(:) = Faxa_swdn(:) * 0.25_r8 + end if + end subroutine calc_partition_sw_4band + + + subroutine calc_partition_precip_freezing(exportState, rc) + type(ESMF_State), intent(inout) :: exportState + integer, intent(out) :: rc + + character(len=*), parameter :: subName = 'calc_partition_precip_freezing: ' + real(r8), pointer :: Faxa_prec(:) => null() + real(r8), pointer :: Faxa_prrn(:) => null() + real(r8), pointer :: Faxa_prsn(:) => null() + + rc = ESMF_SUCCESS + + call dshr_state_getfldptr(exportState, 'Faxa_prec', fldptr1=Faxa_prec, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_prrn', fldptr1=Faxa_prrn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + call dshr_state_getfldptr(exportState, 'Faxa_prsn', fldptr1=Faxa_prsn, rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + + if (.not. associated(Faxa_prec)) then + call shr_log_error(trim(subName)//'ERROR: Faxa_prec required as input for precip partitioning.', rc=rc) + if (ChkErr(rc,__LINE__,u_FILE_u)) return + end if + + if (associated(Faxa_prec)) then + if (associated(Faxa_prrn)) Faxa_prrn(:) = Faxa_prec(:) * 0.5_r8 + if (associated(Faxa_prsn)) Faxa_prsn(:) = Faxa_prec(:) * 0.5_r8 + end if + end subroutine calc_partition_precip_freezing + +end module datm_datamode_ufs_mod diff --git a/dice/ice_comp_nuopc.F90 b/dice/ice_comp_nuopc.F90 index 6a328923e..3524fe52e 100644 --- a/dice/ice_comp_nuopc.F90 +++ b/dice/ice_comp_nuopc.F90 @@ -182,6 +182,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) integer :: bcasttmp(4) real(r8) :: rbcasttmp(3) type(ESMF_VM) :: vm + logical :: isPresent, isSet character(len=*),parameter :: subname=trim(modName)//':(InitializeAdvertise) ' !------------------------------------------------------------------------------- @@ -240,6 +241,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) rbcasttmp(1) = flux_swpf rbcasttmp(2) = flux_Qmin rbcasttmp(3) = flux_Qacc0 + if(export_all) bcasttmp(4) = 1 endif ! broadcast namelist input @@ -254,7 +256,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CX, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, rbcasttmp, 3, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return diff --git a/dlnd/lnd_comp_nuopc.F90 b/dlnd/lnd_comp_nuopc.F90 index 045aaeb5c..787fcd238 100644 --- a/dlnd/lnd_comp_nuopc.F90 +++ b/dlnd/lnd_comp_nuopc.F90 @@ -223,7 +223,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CX, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return nx_global = bcasttmp(1) diff --git a/docn/ocn_comp_nuopc.F90 b/docn/ocn_comp_nuopc.F90 index 013aae46f..00d064ef0 100644 --- a/docn/ocn_comp_nuopc.F90 +++ b/docn/ocn_comp_nuopc.F90 @@ -188,7 +188,7 @@ end subroutine SetServices !=============================================================================== subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) use shr_nl_mod, only: shr_nl_find_group_name - + ! input/output variables type(ESMF_GridComp) :: gcomp type(ESMF_State) :: importState, exportState @@ -260,6 +260,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if(skip_restart_read) bcasttmp(3) = 1 if(export_all) bcasttmp(4) = 1 rtmp(1) = sst_constant_value + if(export_all) bcasttmp(4) = 1 endif ! Broadcast namelist input diff --git a/drof/rof_comp_nuopc.F90 b/drof/rof_comp_nuopc.F90 index 9693778a2..8a70000ac 100644 --- a/drof/rof_comp_nuopc.F90 +++ b/drof/rof_comp_nuopc.F90 @@ -235,7 +235,7 @@ subroutine InitializeAdvertise(gcomp, importState, exportState, clock, rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return call ESMF_VMBroadcast(vm, restfilm, CX, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return - call ESMF_VMBroadcast(vm, bcasttmp, 3, main_task, rc=rc) + call ESMF_VMBroadcast(vm, bcasttmp, 4, main_task, rc=rc) if (ChkErr(rc,__LINE__,u_FILE_u)) return nx_global = bcasttmp(1) diff --git a/dshr/dshr_fldlist_mod.F90 b/dshr/dshr_fldlist_mod.F90 index fd15c3919..2416ef02d 100644 --- a/dshr/dshr_fldlist_mod.F90 +++ b/dshr/dshr_fldlist_mod.F90 @@ -79,7 +79,6 @@ subroutine dshr_fldlist_realize(state, fldLists, flds_scalar_name, flds_scalar_n stdname = fldList%stdname if (NUOPC_IsConnected(state, fieldName=stdname) .or. export_all) then - ! Check field name since linked list might have empty string if (trim(stdname) == '') then fldList => fldList%next diff --git a/fox b/fox deleted file mode 160000 index 7775cc392..000000000 --- a/fox +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7775cc392d13f405f13b4a7411d80aad6c49e3d6 diff --git a/share/genf90 b/share/genf90 deleted file mode 160000 index 4816965ba..000000000 --- a/share/genf90 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 4816965ba946731352bad195b7d946a5fe682ff5