diff --git a/CMakeLists.txt b/CMakeLists.txt index 226aea148..549738794 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,9 +85,13 @@ add_library(fv3atm cpl/module_block_data.F90 cpl/module_cplfields.F90 cpl/module_cap_cpl.F90 - io/clm_lake_io.F90 - io/FV3GFS_io.F90 - io/FV3GFS_restart_io.F90 + io/fv3atm_common_io.F90 + io/fv3atm_clm_lake_io.F90 + io/fv3atm_rrfs_sd_io.F90 + io/fv3atm_sfc_io.F90 + io/fv3atm_oro_io.F90 + io/fv3atm_history_io.F90 + io/fv3atm_restart_io.F90 io/module_write_netcdf.F90 io/module_write_restart_netcdf.F90 io/module_fv3_io_def.F90 diff --git a/atmos_model.F90 b/atmos_model.F90 index 7470f6971..5c54aed86 100644 --- a/atmos_model.F90 +++ b/atmos_model.F90 @@ -90,13 +90,14 @@ module atmos_model_mod use stochastic_physics_wrapper_mod, only: stochastic_physics_wrapper,stochastic_physics_wrapper_end -use FV3GFS_io_mod, only: FV3GFS_restart_read, FV3GFS_restart_write, & - FV3GFS_GFS_checksum, & - FV3GFS_diag_register, FV3GFS_diag_output, & +use fv3atm_history_io_mod, only: fv3atm_diag_register, fv3atm_diag_output, & DIAG_SIZE -use FV3GFS_restart_io_mod, only: FV3GFS_restart_register, & +use fv3atm_restart_io_mod, only: fv3atm_restart_register, & + fv3atm_checksum, & fv_phy_restart_output, & - fv_sfc_restart_output + fv_sfc_restart_output, & + fv3atm_restart_read, & + fv3atm_restart_write use fv_ufs_restart_io_mod, only: fv_dyn_restart_register, & fv_dyn_restart_output use fv_iau_mod, only: iau_external_data_type,getiauforcing,iau_initialize @@ -369,7 +370,7 @@ subroutine update_atmos_radiation_physics (Atmos) if (chksum_debug) then if (mpp_pe() == mpp_root_pe()) print *,'RADIATION STEP ', GFS_control%kdt, GFS_control%fhour - call FV3GFS_GFS_checksum(GFS_control, GFS_data, Atm_block) + call fv3atm_checksum(GFS_control, GFS_data, Atm_block) endif if (mpp_pe() == mpp_root_pe() .and. debug) write(6,*) "physics driver" @@ -383,7 +384,7 @@ subroutine update_atmos_radiation_physics (Atmos) if (chksum_debug) then if (mpp_pe() == mpp_root_pe()) print *,'PHYSICS STEP1 ', GFS_control%kdt, GFS_control%fhour - call FV3GFS_GFS_checksum(GFS_control, GFS_data, Atm_block) + call fv3atm_checksum(GFS_control, GFS_data, Atm_block) endif if (GFS_Control%do_sppt .or. GFS_Control%do_shum .or. GFS_Control%do_skeb .or. & @@ -402,7 +403,7 @@ subroutine update_atmos_radiation_physics (Atmos) if (chksum_debug) then if (mpp_pe() == mpp_root_pe()) print *,'PHYSICS STEP2 ', GFS_control%kdt, GFS_control%fhour - call FV3GFS_GFS_checksum(GFS_control, GFS_data, Atm_block) + call fv3atm_checksum(GFS_control, GFS_data, Atm_block) endif call getiauforcing(GFS_control,IAU_data) if (mpp_pe() == mpp_root_pe() .and. debug) write(6,*) "end of radiation and physics step" @@ -736,15 +737,15 @@ subroutine atmos_model_init (Atmos, Time_init, Time, Time_step) !rab call atmosphere_tracer_postinit (GFS_data, Atm_block) call atmosphere_nggps_diag (Time, init=.true.) - call FV3GFS_diag_register (GFS_Diag, Time, Atm_block, GFS_control, Atmos%lon, Atmos%lat, Atmos%axes) + call fv3atm_diag_register (GFS_Diag, Time, Atm_block, GFS_control, Atmos%lon, Atmos%lat, Atmos%axes) call GFS_restart_populate (GFS_restart_var, GFS_control, GFS_data%Statein, GFS_data%Stateout, GFS_data%Sfcprop, & GFS_data%Coupling, GFS_data%Grid, GFS_data%Tbd, GFS_data%Cldprop, GFS_data%Radtend, & GFS_data%IntDiag, Init_parm, GFS_Diag) if (quilting_restart) then call fv_dyn_restart_register (Atm(mygrid)) - call FV3GFS_restart_register (GFS_data%Sfcprop, GFS_restart_var, Atm_block, GFS_control) + call fv3atm_restart_register (GFS_data%Sfcprop, GFS_restart_var, Atm_block, GFS_control) endif - call FV3GFS_restart_read (GFS_data, GFS_restart_var, Atm_block, GFS_control, Atmos%domain_for_read, & + call fv3atm_restart_read (GFS_data, GFS_restart_var, Atm_block, GFS_control, Atmos%domain_for_read, & Atm(mygrid)%flagstruct%warm_start, ignore_rst_cksum) if(GFS_control%do_ca .and. Atm(mygrid)%flagstruct%warm_start)then call read_ca_restart (Atmos%domain,GFS_control%ncells,GFS_control%nca,GFS_control%ncells_g,GFS_control%nca_g) @@ -966,7 +967,7 @@ subroutine update_atmos_model_state (Atmos, rc) if (chksum_debug) then if (mpp_pe() == mpp_root_pe()) print *,'UPDATE STATE ', GFS_control%kdt, GFS_control%fhour if (mpp_pe() == mpp_root_pe()) print *,'in UPDATE STATE ', size(GFS_data(1)%SfcProp%tsfc),'nblks=',Atm_block%nblks - call FV3GFS_GFS_checksum(GFS_control, GFS_data, Atm_block) + call fv3atm_checksum(GFS_control, GFS_data, Atm_block) endif !--- advance time --- @@ -995,7 +996,7 @@ subroutine update_atmos_model_state (Atmos, rc) endif if (mpp_pe() == mpp_root_pe()) write(6,*) ' gfs diags time since last bucket empty: ',time_int/3600.,'hrs' call atmosphere_nggps_diag(Atmos%Time) - call FV3GFS_diag_output(Atmos%Time, GFS_Diag, Atm_block, GFS_control%nx, GFS_control%ny, & + call fv3atm_diag_output(Atmos%Time, GFS_Diag, Atm_block, GFS_control%nx, GFS_control%ny, & GFS_control%levs, 1, 1, 1.0_GFS_kind_phys, time_int, time_intfull, & GFS_control%fhswr, GFS_control%fhlwr) endif @@ -1109,7 +1110,7 @@ subroutine atmos_model_restart(Atmos, timestamp) call fv_dyn_restart_output(Atm(mygrid), timestamp) else call atmosphere_restart(timestamp) - call FV3GFS_restart_write (GFS_data, GFS_restart_var, Atm_block, & + call fv3atm_restart_write (GFS_data, GFS_restart_var, Atm_block, & GFS_control, Atmos%domain, timestamp) endif if(GFS_control%do_ca)then diff --git a/fv3_cap.F90 b/fv3_cap.F90 index 7b3ab2eba..50ad49104 100644 --- a/fv3_cap.F90 +++ b/fv3_cap.F90 @@ -1,4 +1,4 @@ -!--------------- FV3GFS solo model ----------------- +!--------------- FV3 ATM solo model ---------------- ! !*** The FV3 atmosphere grid component nuopc cap ! @@ -11,7 +11,7 @@ ! 02 Nov 2017: J. Wang Use Gerhard's transferable RouteHandle ! -module fv3gfs_cap_mod +module fv3atm_cap_mod use ESMF use NUOPC @@ -80,14 +80,14 @@ module fv3gfs_cap_mod contains !----------------------------------------------------------------------- -!------------------- Solo fv3gfs code starts here ---------------------- +!------------------- Solo fv3atm code starts here ---------------------- !----------------------------------------------------------------------- subroutine SetServices(gcomp, rc) type(ESMF_GridComp) :: gcomp integer, intent(out) :: rc - character(len=*),parameter :: subname='(fv3gfs_cap:SetServices)' + character(len=*),parameter :: subname='(fv3atm_cap:SetServices)' rc = ESMF_SUCCESS @@ -983,7 +983,7 @@ subroutine InitializeRealize(gcomp, rc) integer, intent(out) :: rc ! local variables - character(len=*),parameter :: subname='(fv3gfs_cap:InitializeRealize)' + character(len=*),parameter :: subname='(fv3atm_cap:InitializeRealize)' type(ESMF_Clock) :: clock type(ESMF_State) :: importState, exportState integer :: urc @@ -1248,7 +1248,7 @@ subroutine fv3_checkimport(gcomp, rc) integer, intent(out) :: rc ! local variables - character(len=*),parameter :: subname='(fv3gfs_cap:fv3_checkimport)' + character(len=*),parameter :: subname='(fv3atm_cap:fv3_checkimport)' integer :: n, nf type(ESMF_Clock) :: clock type(ESMF_Time) :: currTime, invalidTime @@ -1335,7 +1335,7 @@ subroutine TimestampExport_phase1(gcomp, rc) integer, intent(out) :: rc ! local variables - character(len=*),parameter :: subname='(fv3gfs_cap:TimestampExport_phase1)' + character(len=*),parameter :: subname='(fv3atm_cap:TimestampExport_phase1)' type(ESMF_Clock) :: driverClock, modelClock type(ESMF_State) :: exportState @@ -1365,7 +1365,7 @@ subroutine ModelFinalize(gcomp, rc) integer, intent(out) :: rc ! local variables - character(len=*),parameter :: subname='(fv3gfs_cap:ModelFinalize)' + character(len=*),parameter :: subname='(fv3atm_cap:ModelFinalize)' integer :: i, urc type(ESMF_VM) :: vm real(kind=8) :: MPI_Wtime, timeffs @@ -1413,4 +1413,4 @@ end subroutine ModelFinalize ! !----------------------------------------------------------------------------- -end module fv3gfs_cap_mod +end module fv3atm_cap_mod diff --git a/io/FV3GFS_io.F90 b/io/FV3GFS_io.F90 deleted file mode 100644 index 876248d16..000000000 --- a/io/FV3GFS_io.F90 +++ /dev/null @@ -1,4325 +0,0 @@ -module FV3GFS_io_mod - -!----------------------------------------------------------------------- -! gfs_physics_driver_mod defines the GFS physics routines used by -! the GFDL FMS system to obtain tendencies and boundary fluxes due -! to the physical parameterizations and processes that drive -! atmospheric time tendencies for use by other components, namely -! the atmospheric dynamical core. -! -! NOTE: This module currently supports only the operational GFS -! parameterizations as of September 2015. Further development -! is needed to support the full suite of physical -! parameterizations present in the GFS physics package. -!----------------------------------------------------------------------- -! -!--- FMS/GFDL modules - use block_control_mod, only: block_control_type - use mpp_mod, only: mpp_error, mpp_pe, mpp_root_pe, & - mpp_chksum, NOTE, FATAL - use fms_mod, only: stdout - use fms2_io_mod, only: FmsNetcdfDomainFile_t, unlimited, & - open_file, close_file, & - register_axis, register_restart_field, & - register_variable_attribute, register_field, & - read_restart, write_restart, write_data, & - get_global_io_domain_indices, variable_exists - use mpp_domains_mod, only: domain1d, domain2d, domainUG - use time_manager_mod, only: time_type - use diag_manager_mod, only: register_diag_field, send_data - use diag_axis_mod, only: get_axis_global_length, get_diag_axis, & - get_diag_axis_name - use diag_data_mod, only: output_fields, max_output_fields - use diag_util_mod, only: find_input_field - use constants_mod, only: grav, rdgas - use physcons, only: con_tice !saltwater freezing temp (K) - use clm_lake_io, only: clm_lake_data_type -! -!--- GFS_typedefs - use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, & - GFS_data_type, kind_phys - use GFS_restart, only: GFS_restart_type - use GFS_diagnostics, only: GFS_externaldiag_type - -! -!----------------------------------------------------------------------- - implicit none - private - - !--- public interfaces --- - public FV3GFS_restart_read, FV3GFS_restart_write - public FV3GFS_GFS_checksum - public fv3gfs_diag_register, fv3gfs_diag_output -#ifdef use_WRTCOMP - public fv_phys_bundle_setup -#endif - - !--- GFDL filenames - character(len=32) :: fn_oro = 'oro_data.nc' - character(len=32) :: fn_oro_ls = 'oro_data_ls.nc' - character(len=32) :: fn_oro_ss = 'oro_data_ss.nc' - character(len=32) :: fn_srf = 'sfc_data.nc' - character(len=32) :: fn_phy = 'phy_data.nc' - character(len=32) :: fn_dust12m= 'dust12m_data.nc' - character(len=32) :: fn_emi = 'emi_data.nc' - character(len=32) :: fn_rrfssd = 'SMOKE_RRFS_data.nc' - - !--- GFDL FMS netcdf restart data types defined in fms2_io - type(FmsNetcdfDomainFile_t) :: Oro_restart, Sfc_restart, Phy_restart, dust12m_restart, emi_restart, rrfssd_restart - type(FmsNetcdfDomainFile_t) :: Oro_ls_restart, Oro_ss_restart - - !--- GFDL FMS restart containers - character(len=32), allocatable, dimension(:) :: oro_name2, sfc_name2, sfc_name3 - real(kind=kind_phys), allocatable, target, dimension(:,:,:) :: oro_var2, sfc_var2, phy_var2, sfc_var3ice - character(len=32), allocatable, dimension(:) :: oro_ls_ss_name - real(kind=kind_phys), allocatable, target, dimension(:,:,:) :: oro_ls_var, oro_ss_var, oro_var3v, oro_var3s - real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: sfc_var3, phy_var3 - character(len=32), allocatable, dimension(:) :: dust12m_name, emi_name, rrfssd_name - real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: rrfssd_var - real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: dust12m_var - real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: emi_var - !--- Noah MP restart containers - real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: sfc_var3sn,sfc_var3eq,sfc_var3zn - - real(kind=kind_phys) :: zhour -! - integer, parameter :: r8 = kind_phys - integer :: tot_diag_idx = 0 - integer :: total_outputlevel = 0 - integer :: isco,ieco,jsco,jeco,levo,num_axes_phys - integer :: fhzero, ncld, nsoil, imp_physics, landsfcmdl - real(4) :: dtp - logical :: lprecip_accu - character(len=64) :: Sprecip_accu - integer,dimension(:), allocatable :: nstt, nstt_vctbl, all_axes - character(20),dimension(:), allocatable :: axis_name, axis_name_vert - real(4), dimension(:,:,:), allocatable, target :: buffer_phys_bl, buffer_phys_nb - real(4), dimension(:,:,:,:), allocatable, target :: buffer_phys_windvect - real(kind=kind_phys),dimension(:,:),allocatable :: lon, lat, uwork - real(kind=kind_phys),dimension(:,:,:),allocatable:: uwork3d - logical :: uwork_set = .false. - character(128) :: uwindname - integer, parameter, public :: DIAG_SIZE = 800 - real, parameter :: missing_value = 9.99e20_r8 - real, parameter:: stndrd_atmos_ps = 101325.0_r8 - real, parameter:: stndrd_atmos_lapse = 0.0065_r8 - real, parameter:: drythresh = 1.e-4_r8, zero = 0.0_r8, one = 1.0_r8 - real, parameter:: min_lake_orog = 200.0_r8 - real(kind=kind_phys), parameter :: timin = 173.0_r8 ! minimum temperature allowed for snow/ice - -!--- miscellaneous other variables - logical :: use_wrtgridcomp_output = .FALSE. - logical :: module_is_initialized = .FALSE. - - type rrfs_sd_data_type - ! The smoke_data_type stores temporary arrays used to read or - ! write RRFS-SD restart and axis variables. - - real(kind_phys), pointer, private, dimension(:,:) :: & ! i,j variables - emdust=>null(), emseas=>null(), emanoc=>null(), fhist=>null(), coef_bb_dc=>null() - - real(kind_phys), pointer, private, dimension(:,:,:) :: & - fire_in=>null() ! i, j, fire_aux_data_levels - - contains - procedure, public :: register_axis => rrfs_sd_register_axis ! register fire_aux_data_levels axis - procedure, public :: write_axis => rrfs_sd_write_axis ! write fire_aux_data_levels variable - procedure, public :: allocate_data => rrfs_sd_allocate_data ! allocate all pointers - procedure, public :: fill_data => rrfs_sd_fill_data ! fill data with default values - procedure, public :: register_fields => rrfs_sd_register_fields ! register rrfs_sd fields - procedure, public :: deallocate_data => rrfs_sd_deallocate_data ! deallocate pointers - procedure, public :: copy_to_temporaries => rrfs_sd_copy_to_temporaries ! Copy Sfcprop to arrays - procedure, public :: copy_from_temporaries => rrfs_sd_copy_from_temporaries ! Copy arrays to Sfcprop - final :: rrfs_sd_final ! Destructor; calls deallocate_data - end type rrfs_sd_data_type - - interface copy_from_GFS_Data - module procedure copy_from_GFS_Data_2d_phys2phys, & - copy_from_GFS_Data_3d_phys2phys, & - copy_from_GFS_Data_2d_int2phys, & - copy_from_GFS_Data_3d_int2phys, & - copy_from_GFS_Data_2d_stack_phys2phys - end interface - - interface copy_to_GFS_Data - module procedure copy_to_GFS_Data_2d_phys2phys, & - copy_to_GFS_Data_3d_phys2phys, & - copy_to_GFS_Data_2d_int2phys, & - copy_to_GFS_Data_3d_int2phys, & - copy_to_GFS_Data_3d_slice_phys2phys - end interface copy_to_GFS_Data - - CONTAINS - -!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -! -! PUBLIC SUBROUTINES -! -!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -! -!-------------------- -! FV3GFS_restart_read -!-------------------- - subroutine FV3GFS_restart_read (GFS_Data, GFS_Restart, Atm_block, Model, fv_domain, warm_start, ignore_rst_cksum) - type(GFS_data_type), intent(inout) :: GFS_Data(:) - type(GFS_restart_type), intent(inout) :: GFS_Restart - type(block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(inout) :: Model - type(domain2d), intent(in) :: fv_domain - logical, intent(in) :: warm_start - logical, intent(in) :: ignore_rst_cksum - - !--- read in surface data from chgres - call sfc_prop_restart_read (GFS_Data%Sfcprop, Atm_block, Model, fv_domain, warm_start, ignore_rst_cksum) - - !--- read in physics restart data - call phys_restart_read (GFS_Restart, Atm_block, Model, fv_domain, ignore_rst_cksum) - - end subroutine FV3GFS_restart_read - -!--------------------- -! FV3GFS_restart_write -!--------------------- - subroutine FV3GFS_restart_write (GFS_Data, GFS_Restart, Atm_block, Model, fv_domain, timestamp) - type(GFS_data_type), intent(inout) :: GFS_Data(:) - type(GFS_restart_type), intent(inout) :: GFS_Restart - type(block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(in) :: Model - type(domain2d), intent(in) :: fv_domain - character(len=32), optional, intent(in) :: timestamp - - !--- write surface data from chgres - call sfc_prop_restart_write (GFS_Data%Sfcprop, Atm_block, Model, fv_domain, timestamp) - - !--- write physics restart data - call phys_restart_write (GFS_Restart, Atm_block, Model, fv_domain, timestamp) - - end subroutine FV3GFS_restart_write - - -!-------------------- -! FV3GFS_GFS_checksum -!-------------------- - subroutine FV3GFS_GFS_checksum (Model, GFS_Data, Atm_block) - !--- interface variables - type(GFS_control_type), intent(in) :: Model - type(GFS_data_type), intent(in) :: GFS_Data(:) - type (block_control_type), intent(in) :: Atm_block - !--- local variables - integer :: outunit, j, i, ix, nb, isc, iec, jsc, jec, lev, ct, l, ntr, k - integer :: nsfcprop2d, idx_opt, nt - real(kind=kind_phys), allocatable :: temp2d(:,:,:) - real(kind=kind_phys), allocatable :: temp3d(:,:,:,:) - real(kind=kind_phys), allocatable :: temp3dlevsp1(:,:,:,:) - integer, allocatable :: ii1(:), jj1(:) - character(len=32) :: name - - isc = Model%isc - iec = Model%isc+Model%nx-1 - jsc = Model%jsc - jec = Model%jsc+Model%ny-1 - lev = Model%levs - - ntr = size(GFS_Data(1)%Statein%qgrs,3) - - nsfcprop2d = 93 - if (Model%lsm == Model%lsm_noahmp) then - nsfcprop2d = nsfcprop2d + 49 - if (Model%use_cice_alb) then - nsfcprop2d = nsfcprop2d + 4 - endif - elseif (Model%lsm == Model%lsm_ruc) then - nsfcprop2d = nsfcprop2d + 4 + 12 - if (Model%rdlai) then - nsfcprop2d = nsfcprop2d + 1 - endif - else - if (Model%use_cice_alb) then - nsfcprop2d = nsfcprop2d + 4 - endif - endif - - if (Model%nstf_name(1) > 0) then - nsfcprop2d = nsfcprop2d + 16 - endif - - if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - nsfcprop2d = nsfcprop2d + 10 - endif - - allocate (temp2d(isc:iec,jsc:jec,nsfcprop2d+Model%ntot2d+Model%nctp)) - allocate (temp3d(isc:iec,jsc:jec,1:lev,14+Model%ntot3d+2*ntr)) - allocate (temp3dlevsp1(isc:iec,jsc:jec,1:lev+1,3)) - - temp2d = zero - temp3d = zero - temp3dlevsp1 = zero - -!$omp parallel do default(shared) private(i, j, k, nb, ix, nt, ii1, jj1) - block_loop: do nb = 1, Atm_block%nblks - allocate(ii1(Atm_block%blksz(nb))) - allocate(jj1(Atm_block%blksz(nb))) - ii1=Atm_block%index(nb)%ii - isc + 1 - jj1=Atm_block%index(nb)%jj - jsc + 1 - - ! Copy into temp2d - nt=0 - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Statein%pgr) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%slmsk) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsfc) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tisfc) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zorl) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%fice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%hprime(:,1)) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sncovr) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snoalb) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alvsf) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alnsf) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alvwf) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alnwf) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%facsf) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%facwf) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%slope) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%shdmin) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%shdmax) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tg3) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%vfrac) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%vtype) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stype) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%uustar) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%oro) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%oro_uf) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%hice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%weasd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%canopy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%ffmm) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%ffhh) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%f10m) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tprcp) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%srflag) - lsm_choice: if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%slc) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smc) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stc) - elseif (Model%lsm == Model%lsm_ruc) then - do k=1,3 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sh2o(:,k)) - enddo - ! Combine levels 4 to lsoil_lsm (9 for RUC) into one - nt=nt+1 - do ix=1,Atm_block%blksz(nb) - temp2d(ii1(ix),jj1(ix),nt) = sum(GFS_Data(nb)%Sfcprop%sh2o(ix,4:Model%lsoil_lsm)) - enddo - do k=1,3 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smois(:,k)) - enddo - ! Combine levels 4 to lsoil_lsm (9 for RUC) into one - nt=nt+1 - do ix=1,Atm_block%blksz(nb) - temp2d(ii1(ix),jj1(ix),nt) = sum(GFS_Data(nb)%Sfcprop%smois(ix,4:Model%lsoil_lsm)) - enddo - do k=1,3 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tslb(:,k)) - enddo - ! Combine levels 4 to lsoil_lsm (9 for RUC) into one - nt=nt+1 - do ix=1,Atm_block%blksz(nb) - temp2d(ii1(ix),jj1(ix),nt) = sum(GFS_Data(nb)%Sfcprop%tslb(ix,4:Model%lsoil_lsm)) - enddo - endif lsm_choice - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t2m) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%q2m) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirbmdi) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirdfdi) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visbmdi) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visdfdi) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirbmui) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirdfui) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visbmui) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visdfui) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%sfcdsw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%sfcnsw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%sfcdlw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%xlon) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%xlat) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%xlat_d) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%sinlat) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%coslat) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%area) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%dx) - if (Model%ntoz > 0) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%ddy_o3) - endif - if (Model%h2o_phys) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%ddy_h) - endif - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Cldprop%cv) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Cldprop%cvt) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Cldprop%cvb) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%sfalb) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%coszen) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%tsflw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%semis) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%coszdg) - - ! Radtend%sfcfsw is an array of derived type, so we copy all - ! eight elements of the type in one loop - do ix=1,Atm_block%blksz(nb) - temp2d(ii1(ix),jj1(ix),nt+1) = GFS_Data(nb)%Radtend%sfcfsw(ix)%upfxc - temp2d(ii1(ix),jj1(ix),nt+2) = GFS_Data(nb)%Radtend%sfcfsw(ix)%upfx0 - temp2d(ii1(ix),jj1(ix),nt+3) = GFS_Data(nb)%Radtend%sfcfsw(ix)%dnfxc - temp2d(ii1(ix),jj1(ix),nt+4) = GFS_Data(nb)%Radtend%sfcfsw(ix)%dnfx0 - temp2d(ii1(ix),jj1(ix),nt+5) = GFS_Data(nb)%Radtend%sfcflw(ix)%upfxc - temp2d(ii1(ix),jj1(ix),nt+6) = GFS_Data(nb)%Radtend%sfcflw(ix)%upfx0 - temp2d(ii1(ix),jj1(ix),nt+7) = GFS_Data(nb)%Radtend%sfcflw(ix)%dnfxc - temp2d(ii1(ix),jj1(ix),nt+8) = GFS_Data(nb)%Radtend%sfcflw(ix)%dnfx0 - enddo - nt = nt + 8 - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tiice(:,1)) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tiice(:,2)) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirvis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirnir_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifvis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifnir_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%emis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%emis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sncovr_ice) - - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirvis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirnir_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifvis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifnir_ice) - endif - - lsm_choice_2: if (Model%lsm == Model%lsm_noahmp) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tvxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tgxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%canicexy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%canliqxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%eahxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tahxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%cmxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%chxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%fwetxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sneqvoxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alboldxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qsnowxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%wslakexy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zwtxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%waxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%wtxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%lfmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%rtmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%woodxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stblcpxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%fastcpxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xsaixy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xlaixy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%taussxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smcwtdxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%deeprechxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%rechxy) - - ! These five arrays use bizarre indexing, so we use loops: - do k=-2,0 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snicexy(:,k)) - enddo - - do k=-2,0 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snliqxy(:,k)) - enddo - - do k=-2,0 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsnoxy(:,k)) - enddo - - do k=1,4 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smoiseq(:,k)) - enddo - - do k=-2,4 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zsnsoxy(:,k)) - enddo - elseif (Model%lsm == Model%lsm_ruc) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%wetness) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%clw_surf_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%clw_surf_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qwv_surf_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qwv_surf_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsnow_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsnow_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowfallac_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowfallac_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sfalb_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sfalb_lnd_bck) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sfalb_ice) - if (Model%rdlai) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xlaixy) - endif - endif lsm_choice_2 - - nstf_name_choice: if (Model%nstf_name(1) > 0) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tref) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%z_c) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%c_0) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%c_d) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%w_0) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%w_d) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xt) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xs) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xu) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xz) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zm) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xtts) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xzts) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%ifd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%dt_cool) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qrain) - endif nstf_name_choice - -! Flake - if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%T_snow) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%T_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%h_ML) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_ML) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_mnw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%h_talb) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_talb) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_bot1) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_bot2) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%c_t) - endif - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Tbd%phy_f2d) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Tbd%phy_fctd) - - ! Copy to temp3dlevsp1 - nt=0 - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3dlevsp1, GFS_Data(nb)%Statein%phii) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3dlevsp1, GFS_Data(nb)%Statein%prsi) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3dlevsp1, GFS_Data(nb)%Statein%prsik) - - ! Copy to temp3d - nt=0 - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%phil) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%prsl) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%prslk) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%ugrs) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%vgrs) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%vvl) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%tgrs) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gu0) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gv0) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gt0) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%htrsw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%htrlw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%swhc) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%lwhc) - do l = 1,Model%ntot3d - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Tbd%phy_f3d(:,:,l)) - enddo - do l = 1,ntr - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%qgrs(:,:,l)) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gq0(:,:,l)) - enddo - enddo block_loop - - - outunit = stdout() - do i = 1,nsfcprop2d+Model%ntot2d+Model%nctp - write (name, '(i3.3,3x,4a)') i, ' 2d ' - write(outunit,100) name, mpp_chksum(temp2d(:,:,i:i)) - enddo - do i = 1,3 - write (name, '(i2.2,3x,4a)') i, ' 3d levsp1' - write(outunit,100) name, mpp_chksum(temp3dlevsp1(:,:,:,i:i)) - enddo - do i = 1,14+Model%ntot3d+2*ntr - write (name, '(i2.2,3x,4a)') i, ' 3d levs' - write(outunit,100) name, mpp_chksum(temp3d(:,:,:,i:i)) - enddo -100 format("CHECKSUM::",A32," = ",Z20) - - deallocate(temp2d) - deallocate(temp3d) - deallocate(temp3dlevsp1) - end subroutine FV3GFS_GFS_checksum - -!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -! -! PRIVATE SUBROUTINES -! -!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - pure subroutine copy_from_GFS_Data_2d_phys2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(in) :: var_block(:) - real(kind=kind_phys), intent(out) :: var2d(:,:,:) - integer ix - - nt=nt+1 - do ix=1,size(var_block) - var2d(ii1(ix),jj1(ix),nt) = var_block(ix) - enddo - end subroutine copy_from_GFS_Data_2d_phys2phys - - pure subroutine copy_from_GFS_Data_3d_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(in) :: var_block(:,:) - real(kind=kind_phys), intent(out) :: var3d(:,:,:,:) - integer ix, k - - nt=nt+1 - do k=lbound(var_block,2),ubound(var_block,2) - do ix=1,size(var_block,1) - var3d(ii1(ix),jj1(ix),k,nt) = var_block(ix,k) - enddo - enddo - end subroutine copy_from_GFS_Data_3d_phys2phys - - pure subroutine copy_from_GFS_Data_2d_int2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc, var_block(:) - integer, intent(inout) :: nt - real(kind=kind_phys), intent(out) :: var2d(:,:,:) - integer ix - - nt=nt+1 - do ix=1,size(var_block) - var2d(ii1(ix),jj1(ix),nt) = var_block(ix) - enddo - end subroutine copy_from_GFS_Data_2d_int2phys - - pure subroutine copy_from_GFS_Data_2d_stack_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - ! For copying phy_f2d and phy_fctd - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(in) :: var_block(:,:) - real(kind=kind_phys), intent(out) :: var3d(:,:,:) - integer ix, k - - nt=nt+1 - do k=lbound(var_block,2),ubound(var_block,2) - do ix=1,size(var_block,1) - var3d(ii1(ix),jj1(ix),nt) = var_block(ix,k) - enddo - enddo - end subroutine copy_from_GFS_Data_2d_stack_phys2phys - - pure subroutine copy_from_GFS_Data_3d_int2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), var_block(:,:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(out) :: var3d(:,:,:,:) - integer ix, k - - nt=nt+1 - do k=lbound(var_block,2),ubound(var_block,2) - do ix=1,size(var_block,1) - var3d(ii1(ix),jj1(ix),k,nt) = real(var_block(ix,k),kind_phys) - enddo - enddo - end subroutine copy_from_GFS_Data_3d_int2phys - - pure subroutine copy_to_GFS_Data_2d_phys2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(out) :: var_block(:) - real(kind=kind_phys), intent(in) :: var2d(:,:,:) - integer ix - - nt=nt+1 - do ix=1,size(var_block) - var_block(ix) = var2d(ii1(ix),jj1(ix),nt) - enddo - end subroutine copy_to_GFS_Data_2d_phys2phys - - pure subroutine copy_to_GFS_Data_3d_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(out) :: var_block(:,:) - real(kind=kind_phys), intent(in) :: var3d(:,:,:,:) - integer ix, k - - nt=nt+1 - do k=lbound(var_block,2),ubound(var_block,2) - do ix=1,size(var_block,1) - var_block(ix,k) = var3d(ii1(ix),jj1(ix),k,nt) - enddo - enddo - end subroutine copy_to_GFS_Data_3d_phys2phys - - pure subroutine copy_to_GFS_Data_3d_slice_phys2phys(ii1,jj1,isc,jsc,nt,k1,k2,var3d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc, k1, k2 - integer, intent(inout) :: nt - real(kind=kind_phys), intent(out) :: var_block(:,:) - real(kind=kind_phys), intent(in) :: var3d(:,:,:,:) - integer ix, k - - nt=nt+1 - do k=k1,k2 - do ix=1,size(var_block,1) - var_block(ix,k) = var3d(ii1(ix),jj1(ix),k,nt) - enddo - enddo - end subroutine copy_to_GFS_Data_3d_slice_phys2phys - - pure subroutine copy_to_GFS_Data_2d_int2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - integer, intent(out) :: var_block(:) - real(kind=kind_phys), intent(in) :: var2d(:,:,:) - integer ix - - nt=nt+1 - do ix=1,size(var_block) - var_block(ix) = int(var2d(ii1(ix),jj1(ix),nt)) - enddo - end subroutine copy_to_GFS_Data_2d_int2phys - - pure subroutine copy_to_GFS_Data_3d_int2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - integer, intent(out) :: var_block(:,:) - real(kind=kind_phys), intent(in) :: var3d(:,:,:,:) - integer ix - - nt=nt+1 - do ix=1,size(var_block,1) - var_block(ix,:) = int(var3d(ii1(ix),jj1(ix),:,nt)) - enddo - end subroutine copy_to_GFS_Data_3d_int2phys - - - pure subroutine fill_Sfcprop_names(Model,sfc_name2,sfc_name3,nvar_s2m,warm_start) - implicit none - type(GFS_control_type), intent(in) :: Model - integer, intent(in) :: nvar_s2m - character(len=32),intent(out) :: sfc_name2(:), sfc_name3(:) - logical, intent(in) :: warm_start - integer :: nt - - !--- names of the 2D variables to save - nt=0 - nt=nt+1 ; sfc_name2(nt) = 'slmsk' - nt=nt+1 ; sfc_name2(nt) = 'tsea' !tsfc - nt=nt+1 ; sfc_name2(nt) = 'sheleg' !weasd - nt=nt+1 ; sfc_name2(nt) = 'tg3' - nt=nt+1 ; sfc_name2(nt) = 'zorl' - nt=nt+1 ; sfc_name2(nt) = 'alvsf' - nt=nt+1 ; sfc_name2(nt) = 'alvwf' - nt=nt+1 ; sfc_name2(nt) = 'alnsf' - nt=nt+1 ; sfc_name2(nt) = 'alnwf' - nt=nt+1 ; sfc_name2(nt) = 'facsf' - nt=nt+1 ; sfc_name2(nt) = 'facwf' - nt=nt+1 ; sfc_name2(nt) = 'vfrac' - nt=nt+1 ; sfc_name2(nt) = 'canopy' - nt=nt+1 ; sfc_name2(nt) = 'f10m' - nt=nt+1 ; sfc_name2(nt) = 't2m' - nt=nt+1 ; sfc_name2(nt) = 'q2m' - nt=nt+1 ; sfc_name2(nt) = 'vtype' - nt=nt+1 ; sfc_name2(nt) = 'stype' - nt=nt+1 ; sfc_name2(nt) = 'uustar' - nt=nt+1 ; sfc_name2(nt) = 'ffmm' - nt=nt+1 ; sfc_name2(nt) = 'ffhh' - nt=nt+1 ; sfc_name2(nt) = 'hice' - nt=nt+1 ; sfc_name2(nt) = 'fice' - nt=nt+1 ; sfc_name2(nt) = 'tisfc' - nt=nt+1 ; sfc_name2(nt) = 'tprcp' - nt=nt+1 ; sfc_name2(nt) = 'srflag' - nt=nt+1 ; sfc_name2(nt) = 'snwdph' !snowd - nt=nt+1 ; sfc_name2(nt) = 'shdmin' - nt=nt+1 ; sfc_name2(nt) = 'shdmax' - nt=nt+1 ; sfc_name2(nt) = 'slope' - nt=nt+1 ; sfc_name2(nt) = 'snoalb' - !--- variables below here are optional - nt=nt+1 ; sfc_name2(nt) = 'sncovr' - nt=nt+1 ; sfc_name2(nt) = 'snodl' !snowd on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'weasdl'!weasd on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'tsfc' !tsfc composite - nt=nt+1 ; sfc_name2(nt) = 'tsfcl' !temp on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'zorlw' !zorl on water portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'zorll' !zorl on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'zorli' !zorl on ice portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'albdirvis_lnd' - nt=nt+1 ; sfc_name2(nt) = 'albdirnir_lnd' - nt=nt+1 ; sfc_name2(nt) = 'albdifvis_lnd' - nt=nt+1 ; sfc_name2(nt) = 'albdifnir_lnd' - nt=nt+1 ; sfc_name2(nt) = 'emis_lnd' - nt=nt+1 ; sfc_name2(nt) = 'emis_ice' - nt=nt+1 ; sfc_name2(nt) = 'sncovr_ice' - nt=nt+1 ; sfc_name2(nt) = 'snodi' ! snowd on ice portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'weasdi'! weasd on ice portion of a cell - - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - nt=nt+1 ; sfc_name2(nt) = 'albdirvis_ice' - nt=nt+1 ; sfc_name2(nt) = 'albdifvis_ice' - nt=nt+1 ; sfc_name2(nt) = 'albdirnir_ice' - nt=nt+1 ; sfc_name2(nt) = 'albdifnir_ice' - endif - - if(Model%cplwav) then - nt=nt+1 ; sfc_name2(nvar_s2m) = 'zorlwav' !zorl from wave component - endif - - if (Model%nstf_name(1) > 0) then - !--- NSSTM inputs only needed when (nstf_name(1) > 0) .and. (nstf_name(2)) == 0) - nt=nt+1 ; sfc_name2(nt) = 'tref' - nt=nt+1 ; sfc_name2(nt) = 'z_c' - nt=nt+1 ; sfc_name2(nt) = 'c_0' - nt=nt+1 ; sfc_name2(nt) = 'c_d' - nt=nt+1 ; sfc_name2(nt) = 'w_0' - nt=nt+1 ; sfc_name2(nt) = 'w_d' - nt=nt+1 ; sfc_name2(nt) = 'xt' - nt=nt+1 ; sfc_name2(nt) = 'xs' - nt=nt+1 ; sfc_name2(nt) = 'xu' - nt=nt+1 ; sfc_name2(nt) = 'xv' - nt=nt+1 ; sfc_name2(nt) = 'xz' - nt=nt+1 ; sfc_name2(nt) = 'zm' - nt=nt+1 ; sfc_name2(nt) = 'xtts' - nt=nt+1 ; sfc_name2(nt) = 'xzts' - nt=nt+1 ; sfc_name2(nt) = 'd_conv' - nt=nt+1 ; sfc_name2(nt) = 'ifd' - nt=nt+1 ; sfc_name2(nt) = 'dt_cool' - nt=nt+1 ; sfc_name2(nt) = 'qrain' - endif -! -! Only needed when Noah MP LSM is used - 29 2D -! - if (Model%lsm == Model%lsm_noahmp) then - nt=nt+1 ; sfc_name2(nt) = 'snowxy' - nt=nt+1 ; sfc_name2(nt) = 'tvxy' - nt=nt+1 ; sfc_name2(nt) = 'tgxy' - nt=nt+1 ; sfc_name2(nt) = 'canicexy' - nt=nt+1 ; sfc_name2(nt) = 'canliqxy' - nt=nt+1 ; sfc_name2(nt) = 'eahxy' - nt=nt+1 ; sfc_name2(nt) = 'tahxy' - nt=nt+1 ; sfc_name2(nt) = 'cmxy' - nt=nt+1 ; sfc_name2(nt) = 'chxy' - nt=nt+1 ; sfc_name2(nt) = 'fwetxy' - nt=nt+1 ; sfc_name2(nt) = 'sneqvoxy' - nt=nt+1 ; sfc_name2(nt) = 'alboldxy' - nt=nt+1 ; sfc_name2(nt) = 'qsnowxy' - nt=nt+1 ; sfc_name2(nt) = 'wslakexy' - nt=nt+1 ; sfc_name2(nt) = 'zwtxy' - nt=nt+1 ; sfc_name2(nt) = 'waxy' - nt=nt+1 ; sfc_name2(nt) = 'wtxy' - nt=nt+1 ; sfc_name2(nt) = 'lfmassxy' - nt=nt+1 ; sfc_name2(nt) = 'rtmassxy' - nt=nt+1 ; sfc_name2(nt) = 'stmassxy' - nt=nt+1 ; sfc_name2(nt) = 'woodxy' - nt=nt+1 ; sfc_name2(nt) = 'stblcpxy' - nt=nt+1 ; sfc_name2(nt) = 'fastcpxy' - nt=nt+1 ; sfc_name2(nt) = 'xsaixy' - nt=nt+1 ; sfc_name2(nt) = 'xlaixy' - nt=nt+1 ; sfc_name2(nt) = 'taussxy' - nt=nt+1 ; sfc_name2(nt) = 'smcwtdxy' - nt=nt+1 ; sfc_name2(nt) = 'deeprechxy' - nt=nt+1 ; sfc_name2(nt) = 'rechxy' - else if (Model%lsm == Model%lsm_ruc .and. warm_start) then - nt=nt+1 ; sfc_name2(nt) = 'wetness' - nt=nt+1 ; sfc_name2(nt) = 'clw_surf_land' - nt=nt+1 ; sfc_name2(nt) = 'clw_surf_ice' - nt=nt+1 ; sfc_name2(nt) = 'qwv_surf_land' - nt=nt+1 ; sfc_name2(nt) = 'qwv_surf_ice' - nt=nt+1 ; sfc_name2(nt) = 'tsnow_land' - nt=nt+1 ; sfc_name2(nt) = 'tsnow_ice' - nt=nt+1 ; sfc_name2(nt) = 'snowfall_acc_land' - nt=nt+1 ; sfc_name2(nt) = 'snowfall_acc_ice' - nt=nt+1 ; sfc_name2(nt) = 'sfalb_lnd' - nt=nt+1 ; sfc_name2(nt) = 'sfalb_lnd_bck' - nt=nt+1 ; sfc_name2(nt) = 'sfalb_ice' - if (Model%rdlai) then - nt=nt+1 ; sfc_name2(nt) = 'lai' - endif - else if (Model%lsm == Model%lsm_ruc .and. Model%rdlai) then - nt=nt+1 ; sfc_name2(nt) = 'lai' - endif - - if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - nt=nt+1 ; sfc_name2(nt) = 'T_snow' - nt=nt+1 ; sfc_name2(nt) = 'T_ice' - nt=nt+1 ; sfc_name2(nt) = 'h_ML' - nt=nt+1 ; sfc_name2(nt) = 't_ML' - nt=nt+1 ; sfc_name2(nt) = 't_mnw' - nt=nt+1 ; sfc_name2(nt) = 'h_talb' - nt=nt+1 ; sfc_name2(nt) = 't_talb' - nt=nt+1 ; sfc_name2(nt) = 't_bot1' - nt=nt+1 ; sfc_name2(nt) = 't_bot2' - nt=nt+1 ; sfc_name2(nt) = 'c_t' - endif - end subroutine fill_sfcprop_names - -!---------------------------------------------------------------------- -! sfc_prop_restart_read -!---------------------------------------------------------------------- -! creates and populates a data type which is then used to "register" -! restart variables with the GFDL FMS restart subsystem. -! calls a GFDL FMS routine to restore the data from a restart file. -! calculates sncovr if it is not present in the restart file. -! -! calls: register_restart_field, restart_state, free_restart -! -! opens: oro_data.tile?.nc, sfc_data.tile?.nc -! -!---------------------------------------------------------------------- - subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_start, ignore_rst_cksum) - !--- interface variable definitions - type(GFS_sfcprop_type), intent(inout) :: Sfcprop(:) - type (block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(inout) :: Model - type (domain2d), intent(in) :: fv_domain - logical, intent(in) :: warm_start - logical, intent(in) :: ignore_rst_cksum - !--- local variables - integer :: i, j, k, ix, lsoil, num, nb, i_start, j_start, i_end, j_end, nt, n - integer :: isc, iec, jsc, jec, npz, nx, ny - integer :: id_restart - integer :: nvar_o2, nvar_s2m, nvar_s2o, nvar_s3 - integer :: nvar_oro_ls_ss - integer :: nvar_vegfr, nvar_soilfr - integer :: nvar_s2r, nvar_s2mp, nvar_s3mp, isnow - integer :: nvar_emi, nvar_dust12m, nvar_gbbepx, nvar_before_lake, nvar_s2l, nvar_rrfssd - integer, allocatable :: ii1(:), jj1(:) - real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p1 => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p2 => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p3 => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_fr => NULL() - !--- local variables for sncovr calculation - integer :: vegtyp - logical :: mand - real(kind=kind_phys) :: rsnow, tem, tem1 - !--- directory of the input files - character(5) :: indir='INPUT' - character(37) :: infile - !--- fms2_io file open logic - logical :: amiopen - logical :: is_lsoil - - type(clm_lake_data_type) :: clm_lake - type(rrfs_sd_data_type) :: rrfs_sd_data - - nvar_o2 = 19 - nvar_oro_ls_ss = 10 - - nvar_vegfr = Model%nvegcat - nvar_soilfr = Model%nsoilcat - - if (Model%nstf_name(1) > 0) then - nvar_s2o = 18 - else - nvar_s2o = 0 - endif - if(Model%rrfs_sd) then - nvar_dust12m = 5 - nvar_rrfssd = 3 - nvar_emi = 1 - else - nvar_dust12m = 0 - nvar_rrfssd = 0 - nvar_emi = 0 - endif - - if (Model%lsm == Model%lsm_ruc .and. warm_start) then - if(Model%rdlai) then - nvar_s2r = 13 - else - nvar_s2r = 12 - end if - nvar_s3 = 5 - else - if(Model%rdlai) then - nvar_s2r = 1 - else - nvar_s2r = 0 - endif - nvar_s3 = 3 - endif - - if (Model%lsm == Model%lsm_noahmp) then - nvar_s2mp = 29 !mp 2D - nvar_s3mp = 5 !mp 3D - else - nvar_s2mp = 0 !mp 2D - nvar_s3mp = 0 !mp 3D - endif - - isc = Atm_block%isc - iec = Atm_block%iec - jsc = Atm_block%jsc - jec = Atm_block%jec - npz = Atm_block%npz - nx = (iec - isc + 1) - ny = (jec - jsc + 1) - - !--- OROGRAPHY FILE - - !--- open file - infile=trim(indir)//'/'//trim(fn_oro) - amiopen=open_file(Oro_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file '//trim(infile) ) - - if (.not. allocated(oro_name2)) then - !--- allocate the various containers needed for orography data - allocate(oro_name2(nvar_o2)) - allocate(oro_var2(nx,ny,nvar_o2)) - - allocate(oro_var3v(nx,ny,nvar_vegfr)) - allocate(oro_var3s(nx,ny,nvar_soilfr)) - - oro_var2 = -9999._kind_phys - - num = 1 ; oro_name2(num) = 'stddev' ! hprime(ix,1) - num = num + 1 ; oro_name2(num) = 'convexity' ! hprime(ix,2) - num = num + 1 ; oro_name2(num) = 'oa1' ! hprime(ix,3) - num = num + 1 ; oro_name2(num) = 'oa2' ! hprime(ix,4) - num = num + 1 ; oro_name2(num) = 'oa3' ! hprime(ix,5) - num = num + 1 ; oro_name2(num) = 'oa4' ! hprime(ix,6) - num = num + 1 ; oro_name2(num) = 'ol1' ! hprime(ix,7) - num = num + 1 ; oro_name2(num) = 'ol2' ! hprime(ix,8) - num = num + 1 ; oro_name2(num) = 'ol3' ! hprime(ix,9) - num = num + 1 ; oro_name2(num) = 'ol4' ! hprime(ix,10) - num = num + 1 ; oro_name2(num) = 'theta' ! hprime(ix,11) - num = num + 1 ; oro_name2(num) = 'gamma' ! hprime(ix,12) - num = num + 1 ; oro_name2(num) = 'sigma' ! hprime(ix,13) - num = num + 1 ; oro_name2(num) = 'elvmax' ! hprime(ix,14) - num = num + 1 ; oro_name2(num) = 'orog_filt' ! oro - num = num + 1 ; oro_name2(num) = 'orog_raw' ! oro_uf - num = num + 1 ; oro_name2(num) = 'land_frac' ! land fraction [0:1] - !--- variables below here are optional - num = num + 1 ; oro_name2(num) = 'lake_frac' ! lake fraction [0:1] - num = num + 1 ; oro_name2(num) = 'lake_depth' ! lake depth(m) - - !--- register axis - call register_axis( Oro_restart, "lon", 'X' ) - call register_axis( Oro_restart, "lat", 'Y' ) - !--- register the 2D fields - do n = 1,num - var2_p => oro_var2(:,:,n) - if (trim(oro_name2(n)) == 'lake_frac' .or. trim(oro_name2(n)) == 'lake_depth' ) then - call register_restart_field(Oro_restart, oro_name2(n), var2_p, dimensions=(/'lat','lon'/), is_optional=.true.) - else - call register_restart_field(Oro_restart, oro_name2(n), var2_p, dimensions=(/'lat','lon'/)) - endif - enddo - nullify(var2_p) - - !--- register 3D vegetation and soil fractions - var3_fr => oro_var3v(:,:,:) - call register_restart_field(Oro_restart, 'vegetation_type_pct', var3_fr, dimensions=(/'num_veg_cat','lat ','lon '/) , is_optional=.true.) - var3_fr => oro_var3s(:,:,:) - call register_restart_field(Oro_restart, 'soil_type_pct', var3_fr, dimensions=(/'num_soil_cat','lat ','lon '/) , is_optional=.true.) - nullify(var3_fr) - - endif - - !--- read the orography restart/data - call mpp_error(NOTE,'reading topographic/orographic information from INPUT/oro_data.tile*.nc') - call read_restart(Oro_restart, ignore_checksum=ignore_rst_cksum) - call close_file(Oro_restart) - - - !--- copy data into GFS containers - -!$omp parallel do default(shared) private(i, j, nb, ix, num) - do nb = 1, Atm_block%nblks - !--- 2D variables - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - !--- stddev -! Sfcprop(nb)%hprim(ix) = oro_var2(i,j,1) - !--- hprime(1:14) - num = 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro_var2(i,j,num) - !--- oro - num = num + 1 ; Sfcprop(nb)%oro(ix) = oro_var2(i,j,num) - num = num + 1 ; Sfcprop(nb)%oro_uf(ix) = oro_var2(i,j,num) - - Sfcprop(nb)%landfrac(ix) = -9999.0 - Sfcprop(nb)%lakefrac(ix) = -9999.0 - - num = num + 1 ; Sfcprop(nb)%landfrac(ix) = oro_var2(i,j,num) !land frac [0:1] - if (Model%lkm > 0 ) then - if(oro_var2(i,j,num+1)>Model%lakefrac_threshold .and. & - oro_var2(i,j,num+2)>Model%lakedepth_threshold) then - Sfcprop(nb)%lakefrac(ix) = oro_var2(i,j,num+1) !lake frac [0:1] - Sfcprop(nb)%lakedepth(ix) = oro_var2(i,j,num+2) !lake depth [m] !YWu - else - Sfcprop(nb)%lakefrac(ix) = 0 - Sfcprop(nb)%lakedepth(ix) = -9999 - endif - else - Sfcprop(nb)%lakefrac(ix) = oro_var2(i,j,num+1) !lake frac [0:1] - Sfcprop(nb)%lakedepth(ix) = oro_var2(i,j,num+2) !lake depth [m] !YWu - endif - num = num + 2 ! To account for lakefrac and lakedepth - - Sfcprop(nb)%vegtype_frac(ix,:) = -9999.0 - Sfcprop(nb)%soiltype_frac(ix,:) = -9999.0 - - Sfcprop(nb)%vegtype_frac(ix,:) = oro_var3v(i,j,:) ! vegetation type fractions, [0:1] - Sfcprop(nb)%soiltype_frac(ix,:) = oro_var3s(i,j,:) ! soil type fractions, [0:1] - - !do n=1,nvar_vegfr - ! if (Sfcprop(nb)%vegtype_frac(ix,n) > 0.) print *,'Sfcprop(nb)%vegtype_frac(ix,n)',Sfcprop(nb)%vegtype_frac(ix,n),n - !enddo - !do n=1,nvar_soilfr - ! if (Sfcprop(nb)%soiltype_frac(ix,n) > 0.) print *,'Sfcprop(nb)%soiltype_frac(ix,n)',Sfcprop(nb)%soiltype_frac(ix,n),n - !enddo - - enddo - enddo - - nvar_s2m = 48 - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - nvar_s2m = nvar_s2m + 4 -! nvar_s2m = nvar_s2m + 5 - endif - if (Model%cplwav) then - nvar_s2m = nvar_s2m + 1 - endif -! CLM Lake and Flake - if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake ) then - nvar_s2l = 10 - else - nvar_s2l = 0 - endif - - nvar_before_lake=nvar_s2m+nvar_s2o+nvar_s2r+nvar_s2mp - - !--- deallocate containers and free restart container - deallocate(oro_name2, oro_var2) - deallocate(oro_var3v) - deallocate(oro_var3s) - - if_smoke: if(Model%rrfs_sd) then ! for RRFS-SD - - !--- Dust input FILE - !--- open file - infile=trim(indir)//'/'//trim(fn_dust12m) - amiopen=open_file(dust12m_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) - - if (.not. allocated(dust12m_name)) then - !--- allocate the various containers needed for fengsha dust12m data - allocate(dust12m_name(nvar_dust12m)) - allocate(dust12m_var(nx,ny,12,nvar_dust12m)) - - dust12m_name(1) = 'clay' - dust12m_name(2) = 'rdrag' - dust12m_name(3) = 'sand' - dust12m_name(4) = 'ssm' - dust12m_name(5) = 'uthr' - - !--- register axis - call register_axis(dust12m_restart, 'lon', 'X') - call register_axis(dust12m_restart, 'lat', 'Y') - call register_axis(dust12m_restart, 'time', 12) - !--- register the 3D fields - do num = 1,nvar_dust12m - var3_p2 => dust12m_var(:,:,:,num) - call register_restart_field(dust12m_restart, dust12m_name(num), var3_p2, dimensions=(/'time', 'lat ', 'lon '/),& - &is_optional=.not.mand) - enddo - nullify(var3_p2) - endif - - !--- read new GSL created dust12m restart/data - call mpp_error(NOTE,'reading dust12m information from INPUT/dust12m_data.tile*.nc') - call read_restart(dust12m_restart) - call close_file(dust12m_restart) - - do nb = 1, Atm_block%nblks - !--- 3D variables - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - do k = 1, 12 - Sfcprop(nb)%dust12m_in(ix,k,1) = dust12m_var(i,j,k,1) - Sfcprop(nb)%dust12m_in(ix,k,2) = dust12m_var(i,j,k,2) - Sfcprop(nb)%dust12m_in(ix,k,3) = dust12m_var(i,j,k,3) - Sfcprop(nb)%dust12m_in(ix,k,4) = dust12m_var(i,j,k,4) - Sfcprop(nb)%dust12m_in(ix,k,5) = dust12m_var(i,j,k,5) - enddo - enddo - enddo - - deallocate(dust12m_name,dust12m_var) - - read_emi: if(nvar_emi>0) then - !--- open anthropogenic emission file - infile=trim(indir)//'/'//trim(fn_emi) - amiopen=open_file(emi_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) - - !if (.not. allocated(emi_name)) then - !--- allocate the various containers needed for anthropogenic emission data - if(allocated(emi_name)) deallocate(emi_name) - if(allocated(emi_var)) deallocate(emi_var) - allocate(emi_name(nvar_emi)) - allocate(emi_var(nx,ny,1,nvar_emi)) - - emi_name(1) = 'e_oc' - !--- register axis - call register_axis( emi_restart, 'time', 1) ! only read first time level, even if multiple are present - call register_axis( emi_restart, "grid_xt", 'X' ) - call register_axis( emi_restart, "grid_yt", 'Y' ) - !--- register the 2D fields - do num = 1,nvar_emi - var3_p2 => emi_var(:,:,:,num) - call register_restart_field(emi_restart, emi_name(num), var3_p2, dimensions=(/'time ','grid_yt','grid_xt'/)) - enddo - nullify(var3_p2) - !endif - - !--- read anthropogenic emi restart/data - call mpp_error(NOTE,'reading emi information from INPUT/emi_data.tile*.nc') - call read_restart(emi_restart) - call close_file(emi_restart) - - do num=1,nvar_emi - do nb = 1, Atm_block%nblks - !--- 2D variables - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - Sfcprop(nb)%emi_in(ix,num) = emi_var(i,j,1,num) - enddo - enddo - enddo - - !--- deallocate containers and free restart container - deallocate(emi_name, emi_var) - endif read_emi - - !--- Dust input FILE - !--- open file - infile=trim(indir)//'/'//trim(fn_rrfssd) - amiopen=open_file(rrfssd_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) - - if (.not. allocated(rrfssd_name)) then - !--- allocate the various containers needed for rrfssd fire data - allocate(rrfssd_name(nvar_rrfssd)) - allocate(rrfssd_var(nx,ny,24,nvar_rrfssd)) - - rrfssd_name(1) = 'ebb_smoke_hr' - rrfssd_name(2) = 'frp_avg_hr' - rrfssd_name(3) = 'frp_std_hr' - - !--- register axis - call register_axis(rrfssd_restart, 'lon', 'X') - call register_axis(rrfssd_restart, 'lat', 'Y') - call register_axis(rrfssd_restart, 't', 24) - !--- register the 3D fields - mand = .false. - do num = 1,nvar_rrfssd - var3_p2 => rrfssd_var(:,:,:,num) - call register_restart_field(rrfssd_restart, rrfssd_name(num), var3_p2, dimensions=(/'t ', 'lat', 'lon'/),& - &is_optional=.not.mand) - enddo - nullify(var3_p2) - endif - - !--- read new GSL created rrfssd restart/data - call mpp_error(NOTE,'reading rrfssd information from INPUT/SMOKE_RRFS_data.nc') - call read_restart(rrfssd_restart) - call close_file(rrfssd_restart) - - do nb = 1, Atm_block%nblks - !--- 3D variables - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - !--- assign hprime(1:10) and hprime(15:24) with new oro stat data - do k = 1, 24 - Sfcprop(nb)%smoke_RRFS(ix,k,1) = rrfssd_var(i,j,k,1) - Sfcprop(nb)%smoke_RRFS(ix,k,2) = rrfssd_var(i,j,k,2) - Sfcprop(nb)%smoke_RRFS(ix,k,3) = rrfssd_var(i,j,k,3) - enddo - enddo - enddo - - deallocate(rrfssd_name, rrfssd_var) - endif if_smoke ! RRFS_SD - - !--- Modify/read-in additional orographic static fields for GSL drag suite - if (Model%gwd_opt==3 .or. Model%gwd_opt==33 .or. & - Model%gwd_opt==2 .or. Model%gwd_opt==22 ) then - - !--- open restart file - infile=trim(indir)//'/'//trim(fn_oro_ls) - amiopen=open_file(Oro_ls_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if( .not.amiopen ) call mpp_error( FATAL, 'Error with opening file '//trim(infile) ) - - !--- open restart file - infile=trim(indir)//'/'//trim(fn_oro_ss) - amiopen=open_file(Oro_ss_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if( .not.amiopen ) call mpp_error( FATAL, 'Error with opening file '//trim(infile) ) - - if (.not. allocated(oro_ls_ss_name)) then - !--- allocate the various containers needed for orography data - allocate(oro_ls_ss_name(nvar_oro_ls_ss)) - allocate(oro_ls_var(nx,ny,nvar_oro_ls_ss)) - allocate(oro_ss_var(nx,ny,nvar_oro_ls_ss)) - - oro_ls_ss_name(1) = 'stddev' - oro_ls_ss_name(2) = 'convexity' - oro_ls_ss_name(3) = 'oa1' - oro_ls_ss_name(4) = 'oa2' - oro_ls_ss_name(5) = 'oa3' - oro_ls_ss_name(6) = 'oa4' - oro_ls_ss_name(7) = 'ol1' - oro_ls_ss_name(8) = 'ol2' - oro_ls_ss_name(9) = 'ol3' - oro_ls_ss_name(10) = 'ol4' - - call register_axis(Oro_ls_restart, "lon", 'X') - call register_axis(Oro_ls_restart, "lat", 'Y') - call register_axis(Oro_ss_restart, "lon", 'X') - call register_axis(Oro_ss_restart, "lat", 'Y') - - do num = 1,nvar_oro_ls_ss - var2_p => oro_ls_var(:,:,num) - call register_restart_field(Oro_ls_restart, oro_ls_ss_name(num), var2_p, dimensions=(/'lon','lat'/)) - enddo - nullify(var2_p) - do num = 1,nvar_oro_ls_ss - var2_p => oro_ss_var(:,:,num) - call register_restart_field(Oro_ss_restart, oro_ls_ss_name(num), var2_p, dimensions=(/'lon','lat'/)) - enddo - nullify(var2_p) - end if - - !--- read new GSL created orography restart/data - call mpp_error(NOTE,'reading topographic/orographic information from & - &INPUT/oro_data_ls.tile*.nc') - call read_restart(Oro_ls_restart, ignore_checksum=ignore_rst_cksum) - call close_file(Oro_ls_restart) - call mpp_error(NOTE,'reading topographic/orographic information from & - &INPUT/oro_data_ss.tile*.nc') - call read_restart(Oro_ss_restart, ignore_checksum=ignore_rst_cksum) - call close_file(Oro_ss_restart) - - - do nb = 1, Atm_block%nblks - !--- 2D variables - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - ! Replace hprime(1:10) with GSL oro stat data only when using GSL - ! drag suite with large scale GWD and blocking as part of unified drag - ! suite. Otherwise, original oro stat data is used. - if ( (Model%gwd_opt==3 .or. Model%gwd_opt==33) .or. & - ( (Model%gwd_opt==2 .or. Model%gwd_opt==22) .and. & - Model%do_gsl_drag_ls_bl ) ) then - !--- assign hprime(1:10) and hprime(15:24) with new oro stat data - Sfcprop(nb)%hprime(ix,1) = oro_ls_var(i,j,1) - Sfcprop(nb)%hprime(ix,2) = oro_ls_var(i,j,2) - Sfcprop(nb)%hprime(ix,3) = oro_ls_var(i,j,3) - Sfcprop(nb)%hprime(ix,4) = oro_ls_var(i,j,4) - Sfcprop(nb)%hprime(ix,5) = oro_ls_var(i,j,5) - Sfcprop(nb)%hprime(ix,6) = oro_ls_var(i,j,6) - Sfcprop(nb)%hprime(ix,7) = oro_ls_var(i,j,7) - Sfcprop(nb)%hprime(ix,8) = oro_ls_var(i,j,8) - Sfcprop(nb)%hprime(ix,9) = oro_ls_var(i,j,9) - Sfcprop(nb)%hprime(ix,10) = oro_ls_var(i,j,10) - endif - Sfcprop(nb)%hprime(ix,15) = oro_ss_var(i,j,1) - Sfcprop(nb)%hprime(ix,16) = oro_ss_var(i,j,2) - Sfcprop(nb)%hprime(ix,17) = oro_ss_var(i,j,3) - Sfcprop(nb)%hprime(ix,18) = oro_ss_var(i,j,4) - Sfcprop(nb)%hprime(ix,19) = oro_ss_var(i,j,5) - Sfcprop(nb)%hprime(ix,20) = oro_ss_var(i,j,6) - Sfcprop(nb)%hprime(ix,21) = oro_ss_var(i,j,7) - Sfcprop(nb)%hprime(ix,22) = oro_ss_var(i,j,8) - Sfcprop(nb)%hprime(ix,23) = oro_ss_var(i,j,9) - Sfcprop(nb)%hprime(ix,24) = oro_ss_var(i,j,10) - enddo - enddo - - end if - - !--- SURFACE FILE - - !--- open file - infile=trim(indir)//'/'//trim(fn_srf) - amiopen=open_file(Sfc_restart, trim(infile), "read", domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if( .not.amiopen ) call mpp_error(FATAL, 'Error opening file'//trim(infile)) - - if (.not. allocated(sfc_name2)) then - !--- allocate the various containers needed for restarts - allocate(sfc_name2(nvar_s2m+nvar_s2o+nvar_s2mp+nvar_s2r+nvar_s2l)) - allocate(sfc_name3(0:nvar_s3+nvar_s3mp)) - allocate(sfc_var2(nx,ny,nvar_s2m+nvar_s2o+nvar_s2mp+nvar_s2r+nvar_s2l)) - ! Note that this may cause problems with RUC LSM for coldstart runs from GFS data - ! if the initial conditions do contain this variable, because Model%kice is 9 for - ! RUC LSM, but tiice in the initial conditions will only have two vertical layers - allocate(sfc_var3ice(nx,ny,Model%kice)) - - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp .or. (.not.warm_start)) then - allocate(sfc_var3(nx,ny,Model%lsoil,nvar_s3)) - else if (Model%lsm == Model%lsm_ruc) then - allocate(sfc_var3(nx,ny,Model%lsoil_lsm,nvar_s3)) - end if - - sfc_var2 = -9999.0_r8 - sfc_var3 = -9999.0_r8 - sfc_var3ice= -9999.0_r8 -! - if (Model%lsm == Model%lsm_noahmp) then - allocate(sfc_var3sn(nx,ny,-2:0,4:6)) - allocate(sfc_var3eq(nx,ny,1:4,7:7)) - allocate(sfc_var3zn(nx,ny,-2:4,8:8)) - sfc_var3sn = -9999.0_r8 - sfc_var3eq = -9999.0_r8 - sfc_var3zn = -9999.0_r8 - end if - - call fill_Sfcprop_names(Model,sfc_name2,sfc_name3,nvar_s2m,warm_start) - - is_lsoil=.false. - if ( .not. warm_start ) then - if( variable_exists(Sfc_restart,"lsoil") ) then - is_lsoil=.true. - call register_axis(Sfc_restart, 'lon', 'X') - call register_axis(Sfc_restart, 'lat', 'Y') - call register_axis(Sfc_restart, 'lsoil', dimension_length=Model%lsoil) - else - call register_axis(Sfc_restart, 'xaxis_1', 'X') - call register_axis(Sfc_restart, 'yaxis_1', 'Y') - call register_axis(Sfc_restart, 'zaxis_1', dimension_length=4) - call register_axis(Sfc_restart, 'Time', 1) - end if - else - call register_axis(Sfc_restart, 'xaxis_1', 'X') - call register_axis(Sfc_restart, 'yaxis_1', 'Y') - call register_axis(Sfc_restart, 'zaxis_1', dimension_length=Model%kice) - - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then - call register_axis(Sfc_restart, 'zaxis_2', dimension_length=Model%lsoil) - else if(Model%lsm == Model%lsm_ruc) then - call register_axis(Sfc_restart, 'zaxis_2', dimension_length=Model%lsoil_lsm) - end if - if(Model%lsm == Model%lsm_noahmp) then - call register_axis(Sfc_restart, 'zaxis_3', dimension_length=3) - call register_axis(Sfc_restart, 'zaxis_4', dimension_length=7) - end if - call register_axis(Sfc_restart, 'Time', unlimited) - end if - - ! Tell CLM Lake to allocate data, and register its axes and fields - if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then - call clm_lake%allocate_data(Model) - call clm_lake%copy_to_temporaries(Model,Sfcprop,Atm_block) - call clm_lake%register_axes(Model, Sfc_restart) - call clm_lake%register_fields(Sfc_restart) - endif - - if(Model%rrfs_sd) then - call rrfs_sd_data%allocate_data(Model) - call rrfs_sd_data%fill_data(Model, Sfcprop, Atm_block) - call rrfs_sd_data%register_axis(Model) - call rrfs_sd_data%register_fields - endif - - !--- register the 2D fields - do num = 1,nvar_s2m - var2_p => sfc_var2(:,:,num) - if (trim(sfc_name2(num)) == 'sncovr'.or. trim(sfc_name2(num)) == 'tsfcl' .or. trim(sfc_name2(num)) == 'zorll' & - .or. trim(sfc_name2(num)) == 'zorli' .or. trim(sfc_name2(num)) == 'zorlwav' & - .or. trim(sfc_name2(num)) == 'snodl' .or. trim(sfc_name2(num)) == 'weasdl' & - .or. trim(sfc_name2(num)) == 'snodi' .or. trim(sfc_name2(num)) == 'weasdi' & - .or. trim(sfc_name2(num)) == 'tsfc' .or. trim(sfc_name2(num)) == 'zorlw' & - .or. trim(sfc_name2(num)) == 'albdirvis_lnd' .or. trim(sfc_name2(num)) == 'albdirnir_lnd' & - .or. trim(sfc_name2(num)) == 'albdifvis_lnd' .or. trim(sfc_name2(num)) == 'albdifnir_lnd' & - .or. trim(sfc_name2(num)) == 'albdirvis_ice' .or. trim(sfc_name2(num)) == 'albdirnir_ice' & - .or. trim(sfc_name2(num)) == 'albdifvis_ice' .or. trim(sfc_name2(num)) == 'albdifnir_ice' & - .or. trim(sfc_name2(num)) == 'emis_lnd' .or. trim(sfc_name2(num)) == 'emis_ice' & - .or. trim(sfc_name2(num)) == 'sncovr_ice') then - if(is_lsoil) then - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'lat','lon'/), is_optional=.true.) - else - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'Time ','yaxis_1','xaxis_1'/),& - &is_optional=.true.) - end if - else - if(is_lsoil) then - call register_restart_field(Sfc_restart,sfc_name2(num),var2_p, dimensions=(/'lat','lon'/)) - else - call register_restart_field(Sfc_restart,sfc_name2(num),var2_p, dimensions=(/'Time ','yaxis_1','xaxis_1'/)) - end if - endif - enddo - - if (Model%nstf_name(1) > 0) then - mand = .false. - if (Model%nstf_name(2) == 0) mand = .true. - do num = nvar_s2m+1,nvar_s2m+nvar_s2o - var2_p => sfc_var2(:,:,num) - if(is_lsoil) then - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'lat','lon'/), is_optional=.not.mand) - else - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'Time ','yaxis_1','xaxis_1'/), & - &is_optional=.not.mand) - endif - enddo - endif - - if (Model%lsm == Model%lsm_ruc) then ! nvar_s2mp = 0 - do num = nvar_s2m+nvar_s2o+1, nvar_s2m+nvar_s2o+nvar_s2r - var2_p => sfc_var2(:,:,num) - if(is_lsoil) then - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'lat','lon'/) ) - else - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'Time ','yaxis_1','xaxis_1'/) ) - end if - enddo - endif ! mp/ruc - - -! Noah MP register only necessary only lsm = 2, not necessary has values - if (nvar_s2mp > 0) then - mand = .false. - do num = nvar_s2m+nvar_s2o+1,nvar_s2m+nvar_s2o+nvar_s2mp - var2_p => sfc_var2(:,:,num) - if(is_lsoil) then - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'lat','lon'/), is_optional=.not.mand) - else - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'Time ','yaxis_1','xaxis_1'/), & - &is_optional=.not.mand) - end if - enddo - endif ! noahmp - -! Flake - if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - mand = .false. - do num = nvar_before_lake+1,nvar_before_lake+nvar_s2l - var2_p => sfc_var2(:,:,num) - if(is_lsoil) then - call register_restart_field(Sfc_restart, sfc_name2(num),var2_p,dimensions=(/'lat','lon'/), is_optional=.not.mand) - else - call register_restart_field(Sfc_restart, sfc_name2(num),var2_p,dimensions=(/'Time ','yaxis_1','xaxis_1'/), is_optional=.not.mand) - endif - enddo - endif - - nullify(var2_p) - endif ! if not allocated - - - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp .or. (.not.warm_start)) then - !--- names of the 3D variables to save - sfc_name3(1) = 'stc' - sfc_name3(2) = 'smc' - sfc_name3(3) = 'slc' - if (Model%lsm == Model%lsm_noahmp) then - sfc_name3(4) = 'snicexy' - sfc_name3(5) = 'snliqxy' - sfc_name3(6) = 'tsnoxy' - sfc_name3(7) = 'smoiseq' - sfc_name3(8) = 'zsnsoxy' - endif - else if (Model%lsm == Model%lsm_ruc) then - !--- names of the 2D variables to save - sfc_name3(1) = 'tslb' - sfc_name3(2) = 'smois' - sfc_name3(3) = 'sh2o' - sfc_name3(4) = 'smfr' - sfc_name3(5) = 'flfr' - endif - - !--- register the 3D fields - sfc_name3(0) = 'tiice' - var3_p => sfc_var3ice(:,:,:) - call register_restart_field(Sfc_restart, sfc_name3(0), var3_p, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_1', 'Time '/),& - &is_optional=.true.) - - do num = 1,nvar_s3 - var3_p => sfc_var3(:,:,:,num) - if ( warm_start ) then - call register_restart_field(Sfc_restart, sfc_name3(num), var3_p, dimensions=(/'xaxis_1', 'yaxis_1', 'lsoil ', 'Time '/),& - &is_optional=.true.) - else - if(is_lsoil) then - call register_restart_field(Sfc_restart, sfc_name3(num), var3_p, dimensions=(/'lat ', 'lon ', 'lsoil'/), is_optional=.true.) - else - call register_restart_field(Sfc_restart, sfc_name3(num), var3_p, dimensions=(/'xaxis_1','yaxis_1','zaxis_1','Time '/),& - &is_optional=.true.) - end if - end if - enddo - - if (Model%lsm == Model%lsm_noahmp) then - mand = .false. - do num = nvar_s3+1,nvar_s3+3 - var3_p1 => sfc_var3sn(:,:,:,num) - call register_restart_field(Sfc_restart, sfc_name3(num), var3_p1, dimensions=(/'xaxis_1', 'yaxis_1','zaxis_2', 'Time '/),& - &is_optional=.not.mand) - enddo - - var3_p2 => sfc_var3eq(:,:,:,7) - call register_restart_field(Sfc_restart, sfc_name3(7), var3_p2, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_3', 'Time '/),& - &is_optional=.not.mand) - - var3_p3 => sfc_var3zn(:,:,:,8) - call register_restart_field(Sfc_restart, sfc_name3(8), var3_p3, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_4', 'Time '/),& - &is_optional=.not.mand) - - nullify(var3_p1) - nullify(var3_p2) - nullify(var3_p3) - endif !mp - - nullify(var3_p) - -!--- Noah MP define arbitrary value (number layers of snow) to indicate -!coldstart(sfcfile doesn't include noah mp fields) or not - - if (Model%lsm == Model%lsm_noahmp) then - sfc_var2(1,1,nvar_s2m+19) = -66666.0_r8 - endif - - !--- read the surface restart/data - call mpp_error(NOTE,'reading surface properties data from INPUT/sfc_data.tile*.nc') - call read_restart(Sfc_restart, ignore_checksum=ignore_rst_cksum) - call close_file(Sfc_restart) - - ! Tell clm_lake to copy data to temporary arrays - if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then - call clm_lake%copy_from_temporaries(Model,Sfcprop,Atm_block) - endif - - if(Model%rrfs_sd) then - call rrfs_sd_data%copy_from_temporaries(Model,Sfcprop,Atm_block) - end if - -! write(0,*)' stype read in min,max=',minval(sfc_var2(:,:,35)),maxval(sfc_var2(:,:,35)),' sfc_name2=',sfc_name2(35) -! write(0,*)' stype read in min,max=',minval(sfc_var2(:,:,18)),maxval(sfc_var2(:,:,18)) -! write(0,*)' sfc_var2=',sfc_var2(:,:,12) - - !--- place the data into the block GFS containers - -!$omp parallel do default(shared) private(i, j, nb, ix, nt, ii1, jj1, lsoil) - block_loop: do nb = 1, Atm_block%nblks - allocate(ii1(Atm_block%blksz(nb))) - allocate(jj1(Atm_block%blksz(nb))) - ii1=Atm_block%index(nb)%ii - isc + 1 - jj1=Atm_block%index(nb)%jj - jsc + 1 - - nt=0 - -!--- 2D variables -! ------------ - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%slmsk) !--- slmsk - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfco) !--- tsfc (tsea in sfc file) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasd) !--- weasd (sheleg in sfc file) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tg3) !--- tg3 - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorl) !--- zorl composite - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alvsf) !--- alvsf - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alvwf) !--- alvwf - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alnsf) !--- alnsf - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alnwf) !--- alnwf - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%facsf) !--- facsf - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%facwf) !--- facwf - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%vfrac) !--- vfrac - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canopy) !--- canopy - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%f10m) !--- f10m - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t2m) !--- t2m - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%q2m) !--- q2m - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%vtype) !--- vtype - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stype) !--- stype - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%uustar) !--- uustar - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ffmm) !--- ffmm - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ffhh) !--- ffhh - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%hice) !--- hice - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fice) !--- fice - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tisfc) !--- tisfc - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tprcp) !--- tprcp - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%srflag) !--- srflag - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowd) !--- snowd (snwdph in the file) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%shdmin) !--- shdmin - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%shdmax) !--- shdmax - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%slope) !--- slope - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snoalb) !--- snoalb - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sncovr) !--- sncovr - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snodl) !--- snodl (snowd on land portion of a cell) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasdl) !--- weasdl (weasd on land portion of a cell) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfc) !--- tsfc composite - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfcl) !--- tsfcl (temp on land portion of a cell) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorlw) !--- zorlw (zorl on water portion of a cell) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorll) !--- zorll (zorl on land portion of a cell) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorli) !--- zorli (zorl on ice portion of a cell) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirvis_lnd) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirnir_lnd) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifvis_lnd) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifnir_lnd) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%emis_lnd) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%emis_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sncovr_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snodi) !--- snodi (snowd on ice portion of a cell) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasdi) !--- weasdi (weasd on ice portion of a cell) - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirvis_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifvis_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirnir_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifnir_ice) -! call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_ice) - endif - if(Model%cplwav) then - !tgs - the following line is a bug. It should be nt = nt - !nt = nvar_s2m-1 ! Next item will be at nvar_s2m - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorlwav) !--- (zorl from wave model) - else - Sfcprop(nb)%zorlwav = Sfcprop(nb)%zorlw - endif - - do_lsi_fractions: do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%stype(ix) == 14 .or. Sfcprop(nb)%stype(ix) <= 0) then - Sfcprop(nb)%landfrac(ix) = zero - Sfcprop(nb)%stype(ix) = 0 - if (Sfcprop(nb)%lakefrac(ix) > zero) then - Sfcprop(nb)%lakefrac(ix) = one - endif - endif - - if_frac_grid: if (Model%frac_grid) then - if (Sfcprop(nb)%landfrac(ix) > -999.0_r8) then - Sfcprop(nb)%slmsk(ix) = ceiling(Sfcprop(nb)%landfrac(ix)-1.0e-6) - if (Sfcprop(nb)%slmsk(ix) == 1 .and. Sfcprop(nb)%stype(ix) == 14) & - Sfcprop(nb)%slmsk(ix) = 0 - if (Sfcprop(nb)%lakefrac(ix) > zero) then - Sfcprop(nb)%oceanfrac(ix) = zero ! lake & ocean don't coexist in a cell - if (nint(Sfcprop(nb)%slmsk(ix)) /= 1) then - if(Sfcprop(nb)%fice(ix) >= Model%min_lakeice) then - Sfcprop(nb)%slmsk(ix) = 2 - else - Sfcprop(nb)%slmsk(ix) = 0 - endif - endif - else - Sfcprop(nb)%lakefrac(ix) = zero - Sfcprop(nb)%oceanfrac(ix) = one - Sfcprop(nb)%landfrac(ix) - if (nint(Sfcprop(nb)%slmsk(ix)) /= 1) then - if (Sfcprop(nb)%fice(ix) >= Model%min_seaice) then - Sfcprop(nb)%slmsk(ix) = 2 - else - Sfcprop(nb)%slmsk(ix) = 0 - endif - endif - endif - else - Model%frac_grid = .false. - if (nint(Sfcprop(nb)%slmsk(ix)) == 1) then - Sfcprop(nb)%landfrac(ix) = one - Sfcprop(nb)%lakefrac(ix) = zero - Sfcprop(nb)%oceanfrac(ix) = zero - else - if (Sfcprop(nb)%slmsk(ix) < 0.1_r8 .or. Sfcprop(nb)%slmsk(ix) > 1.9_r8) then - Sfcprop(nb)%landfrac(ix) = zero - if (Sfcprop(nb)%oro_uf(ix) > min_lake_orog) then ! lakes - Sfcprop(nb)%lakefrac(ix) = one - Sfcprop(nb)%oceanfrac(ix) = zero - else ! ocean - Sfcprop(nb)%lakefrac(ix) = zero - Sfcprop(nb)%oceanfrac(ix) = one - endif - endif - endif - endif - else ! not a fractional grid - if (Sfcprop(nb)%landfrac(ix) > -999.0_r8) then - if (Sfcprop(nb)%lakefrac(ix) > zero) then - Sfcprop(nb)%oceanfrac(ix) = zero - Sfcprop(nb)%landfrac(ix) = zero - Sfcprop(nb)%lakefrac(ix) = one - Sfcprop(nb)%slmsk(ix) = zero - if (Sfcprop(nb)%fice(ix) >= Model%min_lakeice) Sfcprop(nb)%slmsk(ix) = 2.0 - else - Sfcprop(nb)%slmsk(ix) = nint(Sfcprop(nb)%landfrac(ix)) - if (Sfcprop(nb)%stype(ix) <= 0 .or. Sfcprop(nb)%stype(ix) == 14) & - Sfcprop(nb)%slmsk(ix) = zero - if (nint(Sfcprop(nb)%slmsk(ix)) == 0) then - Sfcprop(nb)%oceanfrac(ix) = one - Sfcprop(nb)%landfrac(ix) = zero - Sfcprop(nb)%lakefrac(ix) = zero - if (Sfcprop(nb)%fice(ix) >= Model%min_seaice) Sfcprop(nb)%slmsk(ix) = 2.0 - else - Sfcprop(nb)%landfrac(ix) = one - Sfcprop(nb)%lakefrac(ix) = zero - Sfcprop(nb)%oceanfrac(ix) = zero - endif - endif - else - if (nint(Sfcprop(nb)%slmsk(ix)) == 1 .and. Sfcprop(nb)%stype(ix) > 0 & - .and. Sfcprop(nb)%stype(ix) /= 14) then - Sfcprop(nb)%landfrac(ix) = one - Sfcprop(nb)%lakefrac(ix) = zero - Sfcprop(nb)%oceanfrac(ix) = zero - else - Sfcprop(nb)%slmsk(ix) = zero - Sfcprop(nb)%landfrac(ix) = zero - if (Sfcprop(nb)%oro_uf(ix) > min_lake_orog) then ! lakes - Sfcprop(nb)%lakefrac(ix) = one - Sfcprop(nb)%oceanfrac(ix) = zero - if (Sfcprop(nb)%fice(ix) > Model%min_lakeice) Sfcprop(nb)%slmsk(ix) = 2.0 - else ! ocean - Sfcprop(nb)%lakefrac(ix) = zero - Sfcprop(nb)%oceanfrac(ix) = one - if (Sfcprop(nb)%fice(ix) > Model%min_seaice) Sfcprop(nb)%slmsk(ix) = 2.0 - endif - endif - endif - endif if_frac_grid - enddo do_lsi_fractions - - if (warm_start .and. Model%kdt > 1) then - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%slmsk(ix) = sfc_var2(ii1(ix),jj1(ix),1) !--- slmsk - enddo - endif - - ! - !--- NSSTM variables - !tgs - the following line is a bug that will show if(Model%cplwav) = true - !nt = nvar_s2m - if (Model%nstf_name(1) > 0) then - if (Model%nstf_name(2) == 1) then ! nsst spinup - !--- nsstm tref - nt = nt + 18 - Sfcprop(nb)%tref = Sfcprop(nb)%tsfco - Sfcprop(nb)%z_c = zero - Sfcprop(nb)%c_0 = zero - Sfcprop(nb)%c_d = zero - Sfcprop(nb)%w_0 = zero - Sfcprop(nb)%w_d = zero - Sfcprop(nb)%xt = zero - Sfcprop(nb)%xs = zero - Sfcprop(nb)%xu = zero - Sfcprop(nb)%xv = zero - Sfcprop(nb)%xz = 20.0_r8 - Sfcprop(nb)%zm = zero - Sfcprop(nb)%xtts = zero - Sfcprop(nb)%xzts = zero - Sfcprop(nb)%d_conv = zero - Sfcprop(nb)%ifd = zero - Sfcprop(nb)%dt_cool = zero - Sfcprop(nb)%qrain = zero - elseif (Model%nstf_name(2) == 0) then ! nsst restart - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tref) !--- nsstm tref - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%z_c) !--- nsstm z_c - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_0) !--- nsstm c_0 - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_d) !--- nsstm c_d - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%w_0) !--- nsstm w_0 - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%w_d) !--- nsstm w_d - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xt) !--- nsstm xt - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xs) !--- nsstm xs - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xu) !--- nsstm xu - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xv) !--- nsstm xv - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xz) !--- nsstm xz - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zm) !--- nsstm zm - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xtts) !--- nsstm xtts - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xzts) !--- nsstm xzts - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%d_conv) !--- nsstm d_conv - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ifd) !--- nsstm ifd - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%dt_cool) !--- nsstm dt_cool - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qrain) !--- nsstm qrain - endif - endif - - if (Model%lsm == Model%lsm_ruc .and. warm_start) then - !--- Extra RUC variables - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wetness) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%clw_surf_land) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%clw_surf_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qwv_surf_land) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qwv_surf_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsnow_land) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsnow_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowfallac_land) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowfallac_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_lnd) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_lnd_bck) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_ice) - if (Model%rdlai) then - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xlaixy) - endif - else if (Model%lsm == Model%lsm_ruc) then - ! Initialize RUC snow cover on ice from snow cover - Sfcprop(nb)%sncovr_ice = Sfcprop(nb)%sncovr - if (Model%rdlai) then - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xlaixy) - end if - elseif (Model%lsm == Model%lsm_noahmp) then - !--- Extra Noah MP variables - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tvxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tgxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canicexy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canliqxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%eahxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tahxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%cmxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%chxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fwetxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sneqvoxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alboldxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qsnowxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wslakexy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zwtxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%waxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wtxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%lfmassxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rtmassxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stmassxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%woodxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stblcpxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fastcpxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xsaixy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xlaixy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%taussxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%smcwtdxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%deeprechxy) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rechxy) - endif - if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_snow) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_ice) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_ML) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_ML) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_mnw) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_talb) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_talb) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot1) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot2) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_t) - endif - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp .or. (.not.warm_start)) then - !--- 3D variables - nt=0 - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil,sfc_var3,Sfcprop(nb)%stc) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil,sfc_var3,Sfcprop(nb)%smc) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil,sfc_var3,Sfcprop(nb)%slc) - - if (Model%lsm == Model%lsm_noahmp) then - ! These use weird indexing which is lost during a Fortran subroutine call, so we use loops instead: - nt=nt+1 - do lsoil = -2, 0 - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%snicexy(ix,lsoil) = sfc_var3sn(ii1(ix),jj1(ix),lsoil,nt) - enddo - enddo - - nt=nt+1 - do lsoil = -2, 0 - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%snliqxy(ix,lsoil) = sfc_var3sn(ii1(ix),jj1(ix),lsoil,nt) - enddo - enddo - - nt=nt+1 - do lsoil = -2, 0 - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%tsnoxy(ix,lsoil) = sfc_var3sn(ii1(ix),jj1(ix),lsoil,nt) - enddo - enddo - - nt=nt+1 - do lsoil = 1, 4 - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%smoiseq(ix,lsoil) = sfc_var3eq(ii1(ix),jj1(ix),lsoil,nt) - enddo - enddo - - nt=nt+1 - do lsoil = -2, 4 - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%zsnsoxy(ix,lsoil) = sfc_var3zn(ii1(ix),jj1(ix),lsoil,nt) - enddo - enddo - endif - - else if (Model%lsm == Model%lsm_ruc) then - !--- 3D variables - nt=0 - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil_lsm,sfc_var3,Sfcprop(nb)%tslb) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil_lsm,sfc_var3,Sfcprop(nb)%smois) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil_lsm,sfc_var3,Sfcprop(nb)%sh2o) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil_lsm,sfc_var3,Sfcprop(nb)%keepsmfr) - call copy_to_GFS_Data(ii1,jj1,isc,jsc,nt,1,Model%lsoil_lsm,sfc_var3,Sfcprop(nb)%flag_frsoil) - endif - - do k = 1,Model%kice - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%tiice(ix,k) = sfc_var3ice(ii1(ix),jj1(ix),k) !--- internal ice temp - enddo - enddo - - deallocate(ii1,jj1) - - end do block_loop - call mpp_error(NOTE, 'gfs_driver:: - after put to container ') - -! so far: At cold start everything is 9999.0, warm start snowxy has values -! but the 3D of snow fields are not available because not allocated yet. -! ix,nb loops may be consolidate with the Noah MP isnowxy init -! restore traditional vars first,we need some of them to init snow fields -! snow depth to actual snow layers; so we can allocate and register -! note zsnsoxy is from -2:4 - isnowxy is from 0:-2, but we need -! exact snow layers to pass 3D fields correctly, snow layers are -! different fro grid to grid, we have to init point by point/grid. -! It has to be done after the weasd is available -! sfc_var2(1,1,32) is the first; we need this to allocate snow related fields - - i = Atm_block%index(1)%ii(1) - isc + 1 - j = Atm_block%index(1)%jj(1) - jsc + 1 - - if (sfc_var2(i,j,33) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing snodl') -!$omp parallel do default(shared) private(nb, ix, tem) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%landfrac(ix) > zero) then - tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) - Sfcprop(nb)%snodl(ix) = Sfcprop(nb)%snowd(ix) * tem - else - Sfcprop(nb)%snodl(ix) = zero - endif - enddo - enddo - endif - - if (sfc_var2(i,j,34) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing weasdl') -!$omp parallel do default(shared) private(nb, ix, tem) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%landfrac(ix) > zero) then - tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) - Sfcprop(nb)%weasdl(ix) = Sfcprop(nb)%weasd(ix) * tem - else - Sfcprop(nb)%weasdl(ix) = zero - endif - enddo - enddo - endif - - if (sfc_var2(i,j,36) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing tsfcl') -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%tsfcl(ix) = Sfcprop(nb)%tsfco(ix) !--- compute tsfcl from existing variables - enddo - enddo - endif - - if (sfc_var2(i,j,37) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorlw') -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%landfrac(ix) < one .and. Sfcprop(nb)%fice(ix) < one) then - Sfcprop(nb)%zorlw(ix) = min(Sfcprop(nb)%zorl(ix), 0.317) - endif - enddo - enddo - endif - - if (sfc_var2(i,j,38) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorll') -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%zorll(ix) = Sfcprop(nb)%zorl(ix) !--- compute zorll from existing variables - enddo - enddo - endif - - if (sfc_var2(i,j,39) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorli') -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix)) > zero) then - Sfcprop(nb)%zorli(ix) = one - endif - enddo - enddo - endif - - if (sfc_var2(i,j,45) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing emis_ice') -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%emis_ice(ix) = 0.96 - enddo - enddo - endif - - if (sfc_var2(i,j,46) < -9990.0_r8 .and. Model%lsm /= Model%lsm_ruc) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing sncovr_ice') -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) -! Sfcprop(nb)%sncovr_ice(ix) = Sfcprop(nb)%sncovr(ix) - Sfcprop(nb)%sncovr_ice(ix) = zero - enddo - enddo - endif - - if (sfc_var2(i,j,47) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing snodi') -!$omp parallel do default(shared) private(nb, ix, tem) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%fice(ix) > zero) then - tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) - Sfcprop(nb)%snodi(ix) = min(Sfcprop(nb)%snowd(ix) * tem, 3.0) - else - Sfcprop(nb)%snodi(ix) = zero - endif - enddo - enddo - endif - - if (sfc_var2(i,j,48) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing weasdi') -!$omp parallel do default(shared) private(nb, ix, tem) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%fice(ix) > zero) then - tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) - Sfcprop(nb)%weasdi(ix) = Sfcprop(nb)%weasd(ix)*tem - else - Sfcprop(nb)%weasdi(ix) = zero - endif - enddo - enddo - endif - - if (Model%use_cice_alb) then - if (sfc_var2(i,j,49) < -9990.0_r8) then -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%oceanfrac(ix) > zero .and. & - Sfcprop(nb)%fice(ix) >= Model%min_seaice) then - Sfcprop(nb)%albdirvis_ice(ix) = 0.6_kind_phys - Sfcprop(nb)%albdifvis_ice(ix) = 0.6_kind_phys - Sfcprop(nb)%albdirnir_ice(ix) = 0.6_kind_phys - Sfcprop(nb)%albdifnir_ice(ix) = 0.6_kind_phys - endif - enddo - enddo - endif - - endif - - ! Fill in composite tsfc for coldstart runs - must happen after tsfcl is computed - compute_tsfc_for_colstart: if (sfc_var2(i,j,35) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing composite tsfc') - if(Model%frac_grid) then ! 3-way composite -!$omp parallel do default(shared) private(nb, ix, tem, tem1) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%tsfco(ix) = max(con_tice, Sfcprop(nb)%tsfco(ix)) ! this may break restart reproducibility - tem1 = one - Sfcprop(nb)%landfrac(ix) - tem = tem1 * Sfcprop(nb)%fice(ix) ! tem = ice fraction wrt whole cell - Sfcprop(nb)%tsfc(ix) = Sfcprop(nb)%tsfcl(ix) * Sfcprop(nb)%landfrac(ix) & - + Sfcprop(nb)%tisfc(ix) * tem & - + Sfcprop(nb)%tsfco(ix) * (tem1-tem) - enddo - enddo - else -!$omp parallel do default(shared) private(nb, ix, tem) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - if (Sfcprop(nb)%slmsk(ix) == 1) then - Sfcprop(nb)%tsfc(ix) = Sfcprop(nb)%tsfcl(ix) - else - tem = one - Sfcprop(nb)%fice(ix) - Sfcprop(nb)%tsfc(ix) = Sfcprop(nb)%tisfc(ix) * Sfcprop(nb)%fice(ix) & - + Sfcprop(nb)%tsfco(ix) * tem - endif - enddo - enddo - endif - endif compute_tsfc_for_colstart - - if (sfc_var2(i,j,nvar_s2m) < -9990.0_r8) then - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorlwav') -!$omp parallel do default(shared) private(nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%zorlwav(ix) = Sfcprop(nb)%zorl(ix) !--- compute zorlwav from existing variables - enddo - enddo - endif - - if (nint(sfc_var3ice(1,1,1)) == -9999) then !--- initialize internal ice temp from layer 1 and 2 soil temp - if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing tiice') - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - Sfcprop(nb)%tiice(ix,1) = max(timin, min(con_tice, Sfcprop(nb)%stc(ix,1))) - Sfcprop(nb)%tiice(ix,2) = max(timin, min(con_tice, Sfcprop(nb)%stc(ix,2))) - enddo - enddo - endif - - ! A standard-compliant Fortran 2003 compiler will call clm_lake_final and rrfs_sd_final here. - - end subroutine sfc_prop_restart_read - - -!---------------------------------------------------------------------- -! sfc_prop_restart_write -!---------------------------------------------------------------------- -! routine to write out GFS surface restarts via the GFDL FMS restart -! subsystem. -! takes an optional argument to append timestamps for intermediate -! restarts. -! -! calls: register_restart_field, save_restart -!---------------------------------------------------------------------- - subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timestamp) - !--- interface variable definitions - type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) - type(block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(in) :: Model - type(domain2d), intent(in) :: fv_domain - character(len=32), optional, intent(in) :: timestamp - !--- local variables - integer :: i, j, k, nb, ix, lsoil, num, nt - integer :: isc, iec, jsc, jec, npz, nx, ny - integer :: id_restart - integer :: nvar2m, nvar2o, nvar3 - integer :: nvar2r, nvar2mp, nvar3mp, nvar_before_lake, nvar2l - logical :: mand - integer, allocatable :: ii1(:), jj1(:) - character(len=32) :: fn_srf = 'sfc_data.nc' - real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p1 => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p2 => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p3 => NULL() - real(kind_phys) :: ice - !--- directory of the input files - character(7) :: indir='RESTART' - character(72) :: infile - !--- fms2_io file open logic - logical :: amiopen - !--- variables used for fms2_io register axis - integer :: is, ie - integer, allocatable, dimension(:) :: buffer - type(clm_lake_data_type), target :: clm_lake - !--- temporary variables for storing rrfs_sd fields - type(rrfs_sd_data_type) :: rrfs_sd_data - - nvar2m = 48 - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - nvar2m = nvar2m + 4 -! nvar2m = nvar2m + 5 - endif - if (Model%cplwav) nvar2m = nvar2m + 1 - if (Model%nstf_name(1) > 0) then - nvar2o = 18 - else - nvar2o = 0 - endif - if (Model%lsm == Model%lsm_ruc) then - if (Model%rdlai) then - nvar2r = 13 - else - nvar2r = 12 - endif - nvar3 = 5 - else - nvar2r = 0 - nvar3 = 3 - endif - nvar2mp = 0 - nvar3mp = 0 - if (Model%lsm == Model%lsm_noahmp) then - nvar2mp = 29 - nvar3mp = 5 - endif -!CLM Lake and Flake - if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - nvar2l = 10 - else - nvar2l = 0 - endif - - nvar_before_lake=nvar2m+nvar2o+nvar2r+nvar2mp - - isc = Atm_block%isc - iec = Atm_block%iec - jsc = Atm_block%jsc - jec = Atm_block%jec - npz = Atm_block%npz - nx = (iec - isc + 1) - ny = (jec - jsc + 1) - - nvar_before_lake=nvar2m+nvar2o+nvar2r+nvar2mp - - if (Model%lsm == Model%lsm_ruc) then - if (allocated(sfc_name2)) then - ! Re-allocate if one or more of the dimensions don't match - if (size(sfc_name2).ne.nvar2m+nvar2o+nvar2mp+nvar2r+nvar2l .or. & - size(sfc_name3).ne.nvar3+nvar3mp .or. & - size(sfc_var3,dim=3).ne.Model%lsoil_lsm) then - !--- deallocate containers and free restart container - deallocate(sfc_name2) - deallocate(sfc_name3) - deallocate(sfc_var2) - deallocate(sfc_var3) - end if - end if - end if - - !--- set filename - infile=trim(indir)//'/'//trim(fn_srf) - if( present(timestamp) ) infile=trim(indir)//'/'//trim(timestamp)//'.'//trim(fn_srf) - - !--- register axis - amiopen=open_file(Sfc_restart, trim(infile), 'overwrite', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if_amiopen: if( amiopen ) then - call register_axis(Sfc_restart, 'xaxis_1', 'X') - call register_field(Sfc_restart, 'xaxis_1', 'double', (/'xaxis_1'/)) - call register_variable_attribute(Sfc_restart, 'xaxis_1', 'cartesian_axis', 'X', str_len=1) - call get_global_io_domain_indices(Sfc_restart, 'xaxis_1', is, ie, indices=buffer) - call write_data(Sfc_restart, "xaxis_1", buffer) - deallocate(buffer) - - call register_axis(Sfc_restart, 'yaxis_1', 'Y') - call register_field(Sfc_restart, 'yaxis_1', 'double', (/'yaxis_1'/)) - call register_variable_attribute(Sfc_restart, 'yaxis_1', 'cartesian_axis', 'Y', str_len=1) - call get_global_io_domain_indices(Sfc_restart, 'yaxis_1', is, ie, indices=buffer) - call write_data(Sfc_restart, "yaxis_1", buffer) - deallocate(buffer) - - call register_axis(Sfc_restart, 'zaxis_1', dimension_length=Model%kice) - call register_field(Sfc_restart, 'zaxis_1', 'double', (/'zaxis_1'/)) - call register_variable_attribute(Sfc_restart, 'zaxis_1', 'cartesian_axis', 'Z', str_len=1) - allocate( buffer(Model%kice) ) - do i=1, Model%kice - buffer(i) = i - end do - call write_data(Sfc_restart, 'zaxis_1', buffer) - deallocate(buffer) - - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then - call register_axis(Sfc_restart, 'zaxis_2', dimension_length=Model%lsoil) - call register_field(Sfc_restart, 'zaxis_2', 'double', (/'zaxis_2'/)) - call register_variable_attribute(Sfc_restart, 'zaxis_2', 'cartesian_axis', 'Z', str_len=1) - allocate( buffer(Model%lsoil) ) - do i=1, Model%lsoil - buffer(i)=i - end do - call write_data(Sfc_restart, 'zaxis_2', buffer) - deallocate(buffer) - endif - - if(Model%lsm == Model%lsm_noahmp) then - call register_axis(Sfc_restart, 'zaxis_3', dimension_length=3) - call register_field(Sfc_restart, 'zaxis_3', 'double', (/'zaxis_3'/)) - call register_variable_attribute(Sfc_restart, 'zaxis_3', 'cartesian_axis', 'Z', str_len=1) - allocate(buffer(3)) - do i=1, 3 - buffer(i) = i - end do - call write_data(Sfc_restart, 'zaxis_3', buffer) - deallocate(buffer) - - call register_axis(Sfc_restart, 'zaxis_4', dimension_length=7) - call register_field(Sfc_restart, 'zaxis_4', 'double', (/'zaxis_4'/)) - call register_variable_attribute(Sfc_restart, 'zaxis_4', 'cartesian_axis' ,'Z', str_len=1) - allocate(buffer(7)) - do i=1, 7 - buffer(i)=i - end do - call write_data(Sfc_restart, 'zaxis_4', buffer) - deallocate(buffer) - end if - call register_axis(Sfc_restart, 'Time', unlimited) - call register_field(Sfc_restart, 'Time', 'double', (/'Time'/)) - call register_variable_attribute(Sfc_restart, 'Time', 'cartesian_axis', 'T', str_len=1) - call write_data( Sfc_restart, 'Time', 1) - else - call mpp_error(FATAL, 'Error in opening file'//trim(infile) ) - end if if_amiopen - - ! Tell clm_lake to allocate data, register its axes, and call write_data for each axis's variable - if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then - call clm_lake%allocate_data(Model) - call clm_lake%register_axes(Model, Sfc_restart) - call clm_lake%write_axes(Model, Sfc_restart) - endif - - if(Model%rrfs_sd) then - call rrfs_sd_data%allocate_data(Model) - call rrfs_sd_data%register_axis(Model) - call rrfs_sd_data%write_axis(Model) - end if - - if (.not. allocated(sfc_name2)) then - !--- allocate the various containers needed for restarts - allocate(sfc_name2(nvar2m+nvar2o+nvar2mp+nvar2r+nvar2l)) - allocate(sfc_name3(0:nvar3+nvar3mp)) - allocate(sfc_var2(nx,ny,nvar2m+nvar2o+nvar2mp+nvar2r+nvar2l)) - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then - allocate(sfc_var3(nx,ny,Model%lsoil,nvar3)) - elseif (Model%lsm == Model%lsm_ruc) then - allocate(sfc_var3(nx,ny,Model%lsoil_lsm,nvar3)) - endif - sfc_var2 = -9999.0_r8 - sfc_var3 = -9999.0_r8 - if (Model%lsm == Model%lsm_noahmp) then - allocate(sfc_var3sn(nx,ny,-2:0,4:6)) - allocate(sfc_var3eq(nx,ny,1:4,7:7)) - allocate(sfc_var3zn(nx,ny,-2:4,8:8)) - - sfc_var3sn = -9999.0_r8 - sfc_var3eq = -9999.0_r8 - sfc_var3zn = -9999.0_r8 - endif - call fill_Sfcprop_names(Model,sfc_name2,sfc_name3,nvar2m,.true.) - end if - - if(Model%lkm>0) then - if(Model%iopt_lake==Model%iopt_lake_flake ) then - if(Model%me==0) then - if(size(sfc_name2)/=nvar_before_lake+10) then -3814 format("ERROR: size mismatch size(sfc_name2)=",I0," /= nvar_before_lake+10=",I0) - write(0,3814) size(sfc_name2),nvar_before_lake+10 - endif - endif - else if(Model%iopt_lake==Model%iopt_lake_clm) then - ! Tell clm_lake to register all of its fields - call clm_lake%register_fields(Sfc_restart) - endif - endif - - if(Model%rrfs_sd) then - call rrfs_sd_data%register_fields - endif - - !--- register the 2D fields - do num = 1,nvar2m - var2_p => sfc_var2(:,:,num) - if (trim(sfc_name2(num)) == 'sncovr' .or. trim(sfc_name2(num)) == 'tsfcl' .or.trim(sfc_name2(num)) == 'zorll' & - .or. trim(sfc_name2(num)) == 'zorli' .or.trim(sfc_name2(num)) == 'zorlwav' & - .or. trim(sfc_name2(num)) == 'snodl' .or. trim(sfc_name2(num)) == 'weasdl' & - .or. trim(sfc_name2(num)) == 'snodi' .or. trim(sfc_name2(num)) == 'weasdi' & - .or. trim(sfc_name2(num)) == 'tsfc' .or. trim(sfc_name2(num)) == 'zorlw' & - .or. trim(sfc_name2(num)) == 'albdirvis_lnd' .or. trim(sfc_name2(num)) == 'albdirnir_lnd' & - .or. trim(sfc_name2(num)) == 'albdifvis_lnd' .or. trim(sfc_name2(num)) == 'albdifnir_lnd' & - .or. trim(sfc_name2(num)) == 'albdirvis_ice' .or. trim(sfc_name2(num)) == 'albdirnir_ice' & - .or. trim(sfc_name2(num)) == 'albdifvis_ice' .or. trim(sfc_name2(num)) == 'albdifnir_ice' & - .or. trim(sfc_name2(num)) == 'emis_lnd' .or. trim(sfc_name2(num)) == 'emis_ice' & - .or. trim(sfc_name2(num)) == 'sncovr_ice' ) then - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'xaxis_1','yaxis_1','Time '/), is_optional=.true.) - else - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/) ) - endif - enddo - if (Model%nstf_name(1) > 0) then - mand = .false. - if (Model%nstf_name(2) ==0) mand = .true. - do num = nvar2m+1,nvar2m+nvar2o - var2_p => sfc_var2(:,:,num) - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/),& - &is_optional=.not.mand) - enddo - endif - - if (Model%lsm == Model%lsm_ruc) then ! nvar2mp =0 - do num = nvar2m+nvar2o+1, nvar2m+nvar2o+nvar2r - var2_p => sfc_var2(:,:,num) - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/)) - enddo - else if (Model%lsm == Model%lsm_noahmp) then ! nvar2r =0 - mand = .true. ! actually should be true since it is after cold start - do num = nvar2m+nvar2o+1,nvar2m+nvar2o+nvar2mp - var2_p => sfc_var2(:,:,num) - call register_restart_field(Sfc_restart, sfc_name2(num), var2_p, dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/),& - &is_optional=.not.mand) - enddo - endif - nullify(var2_p) - - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then - !--- names of the 3D variables to save - sfc_name3(1) = 'stc' - sfc_name3(2) = 'smc' - sfc_name3(3) = 'slc' - if (Model%lsm == Model%lsm_noahmp) then - sfc_name3(4) = 'snicexy' - sfc_name3(5) = 'snliqxy' - sfc_name3(6) = 'tsnoxy' - sfc_name3(7) = 'smoiseq' - sfc_name3(8) = 'zsnsoxy' - endif - else if (Model%lsm == Model%lsm_ruc) then - !--- names of the 3D variables to save - sfc_name3(1) = 'tslb' - sfc_name3(2) = 'smois' - sfc_name3(3) = 'sh2o' - sfc_name3(4) = 'smfr' - sfc_name3(5) = 'flfr' - end if - - !--- register the 3D fields - ! if (Model%frac_grid) then - sfc_name3(0) = 'tiice' - var3_p => sfc_var3ice(:,:,:) - call register_restart_field(Sfc_restart, sfc_name3(0), var3_p, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_1', 'Time '/)) - ! endif - - if(Model%lsm == Model%lsm_ruc) then - do num = 1,nvar3 - var3_p => sfc_var3(:,:,:,num) - call register_restart_field(Sfc_restart, sfc_name3(num), var3_p, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_1', 'Time '/)) - enddo - nullify(var3_p) - else - do num = 1,nvar3 - var3_p => sfc_var3(:,:,:,num) - call register_restart_field(Sfc_restart, sfc_name3(num), var3_p, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_2', 'Time '/)) - enddo - nullify(var3_p) - endif - - if (Model%lsm == Model%lsm_noahmp) then - mand = .true. - do num = nvar3+1,nvar3+3 - var3_p1 => sfc_var3sn(:,:,:,num) - call register_restart_field(Sfc_restart, sfc_name3(num), var3_p1, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_3', 'Time '/),& - &is_optional=.not.mand) - enddo - - var3_p2 => sfc_var3eq(:,:,:,7) - call register_restart_field(Sfc_restart, sfc_name3(7), var3_p2, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_2', 'Time '/),& - &is_optional=.not.mand) - - var3_p3 => sfc_var3zn(:,:,:,8) - call register_restart_field(Sfc_restart, sfc_name3(8), var3_p3, dimensions=(/'xaxis_1', 'yaxis_1', 'zaxis_4', 'Time '/),& - &is_optional=.not.mand) - - nullify(var3_p1) - nullify(var3_p2) - nullify(var3_p3) - endif ! lsm = lsm_noahmp - - !Flake - if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - mand = .false. - do num = nvar_before_lake+1,nvar_before_lake+nvar2l - var2_p => sfc_var2(:,:,num) - call register_restart_field(Sfc_restart, sfc_name2(num),var2_p,dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/),& - &is_optional=.not.mand) - enddo - endif - - ! Tell clm_lake to copy Sfcprop data to its internal temporary arrays. - if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then - call clm_lake%copy_to_temporaries(Model,Sfcprop,Atm_block) - endif - - if(Model%rrfs_sd) then - call rrfs_sd_data%copy_to_temporaries(Model,Sfcprop,Atm_block) - endif - -!$omp parallel do default(shared) private(i, j, nb, ix, nt, ii1, jj1, lsoil, k, ice) - block_loop: do nb = 1, Atm_block%nblks - allocate(ii1(Atm_block%blksz(nb))) - allocate(jj1(Atm_block%blksz(nb))) - ii1=Atm_block%index(nb)%ii - isc + 1 - jj1=Atm_block%index(nb)%jj - jsc + 1 - - nt=0 - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%slmsk) !--- slmsk - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfco) !--- tsfc (tsea in sfc file) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasd) !--- weasd (sheleg in sfc file) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tg3) !--- tg3 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorl) !--- zorl - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alvsf) !--- alvsf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alvwf) !--- alvwf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alnsf) !--- alnsf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alnwf) !--- alnwf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%facsf) !--- facsf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%facwf) !--- facwf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%vfrac) !--- vfrac - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canopy)!--- canopy - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%f10m) !--- f10m - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t2m) !--- t2m - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%q2m) !--- q2m - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%vtype) !--- vtype - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stype) !--- stype - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%uustar)!--- uustar - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ffmm) !--- ffmm - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ffhh) !--- ffhh - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%hice) !--- hice - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fice) !--- fice - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tisfc) !--- tisfc - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tprcp) !--- tprcp - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%srflag)!--- srflag - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowd) !--- snowd (snwdph in the file) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%shdmin)!--- shdmin - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%shdmax)!--- shdmax - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%slope) !--- slope - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snoalb)!--- snoalb - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sncovr) !--- sncovr - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snodl) !--- snodl (snowd on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasdl) !--- weasdl (weasd on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfc) !--- tsfc composite - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfcl) !--- tsfcl (temp on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorlw) !--- zorl (zorl on water) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorll) !--- zorll (zorl on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorli) !--- zorli (zorl on ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirvis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirnir_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifvis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifnir_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%emis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%emis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sncovr_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snodi) !--- snodi (snowd on ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasdi) !--- weasdi (weasd on ice) - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirvis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifvis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirnir_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifnir_ice) -! sfc_var2(i,j,53) = Sfcprop(nb)%sfalb_ice(ix) - endif - if (Model%cplwav) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorlwav) !--- zorlwav (zorl from wav) - endif - !--- NSSTM variables - if (Model%nstf_name(1) > 0) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tref) !--- nsstm tref - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%z_c) !--- nsstm z_c - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_0) !--- nsstm c_0 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_d) !--- nsstm c_d - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%w_0) !--- nsstm w_0 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%w_d) !--- nsstm w_d - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xt) !--- nsstm xt - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xs) !--- nsstm xs - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xu) !--- nsstm xu - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xv) !--- nsstm xv - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xz) !--- nsstm xz - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zm) !--- nsstm zm - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xtts) !--- nsstm xtts - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xzts) !--- nsstm xzts - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%d_conv) !--- nsstm d_conv - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ifd) !--- nsstm ifd - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%dt_cool)!--- nsstm dt_cool - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qrain) !--- nsstm qrain - endif - - if (Model%lsm == Model%lsm_ruc) then - !--- Extra RUC variables - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wetness) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%clw_surf_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%clw_surf_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qwv_surf_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qwv_surf_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsnow_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsnow_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowfallac_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowfallac_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_lnd_bck) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_ice) - if (Model%rdlai) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xlaixy) - endif - else if (Model%lsm == Model%lsm_noahmp) then - !--- Extra Noah MP variables - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tvxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tgxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canicexy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canliqxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%eahxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tahxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%cmxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%chxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fwetxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sneqvoxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alboldxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qsnowxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wslakexy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zwtxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%waxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wtxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%lfmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rtmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%woodxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stblcpxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fastcpxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xsaixy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xlaixy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%taussxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%smcwtdxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%deeprechxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rechxy) - endif -! Flake - if(Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_snow) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%T_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_ML) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_ML) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_mnw) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%h_talb) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_talb) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot1) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t_bot2) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_t) - endif - do k = 1,Model%kice - do ix = 1, Atm_block%blksz(nb) - ice=Sfcprop(nb)%tiice(ix,k) - if(ice NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() - !--- directory of the input files - character(5) :: indir='INPUT' - logical :: amiopen - - isc = Atm_block%isc - iec = Atm_block%iec - jsc = Atm_block%jsc - jec = Atm_block%jec - npz = Atm_block%npz - nx = (iec - isc + 1) - ny = (jec - jsc + 1) - - nvar2d = GFS_Restart%num2d - nvar3d = GFS_Restart%num3d - fdiag = GFS_Restart%fdiag - ldiag = GFS_Restart%ldiag - - !--- open restart file and register axes - fname = trim(indir)//'/'//trim(fn_phy) - amiopen=open_file(Phy_restart, trim(fname), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if( amiopen ) then - call register_axis(Phy_restart, 'xaxis_1', 'X') - call register_axis(Phy_restart, 'yaxis_1', 'Y') - call register_axis(Phy_restart, 'zaxis_1', npz) - call register_axis(Phy_restart, 'Time', unlimited) - else - call mpp_error(NOTE,'No physics restarts - cold starting physical parameterizations') - return - endif - - !--- register the restart fields - if (.not. allocated(phy_var2)) then - allocate (phy_var2(nx,ny,nvar2d)) - allocate (phy_var3(nx,ny,npz,nvar3d)) - phy_var2 = zero - phy_var3 = zero - - do num = 1,nvar2d - var2_p => phy_var2(:,:,num) - call register_restart_field(Phy_restart, trim(GFS_Restart%name2d(num)), var2_p, dimensions=(/'xaxis_1','yaxis_1','Time '/),& - &is_optional=.true.) - enddo - do num = 1,nvar3d - var3_p => phy_var3(:,:,:,num) - call register_restart_field(Phy_restart, trim(GFS_restart%name3d(num)), var3_p, dimensions=(/'xaxis_1','yaxis_1','zaxis_1','Time '/), is_optional=.true.) - enddo - nullify(var2_p) - nullify(var3_p) - endif - - !--- read the surface restart/data - call mpp_error(NOTE,'reading physics restart data from INPUT/phy_data.tile*.nc') - call read_restart(Phy_restart, ignore_checksum=ignore_rst_cksum) - call close_file(Phy_restart) - - !--- place the data into the block GFS containers - !--- phy_var* variables -!$omp parallel do default(shared) private(i, j, nb, ix) - do num = 1,nvar2d - do nb = 1,Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - GFS_Restart%data(nb,num)%var2p(ix) = phy_var2(i,j,num) - enddo - enddo - enddo - !-- if restart from init time, reset accumulated diag fields - if( Model%phour < 1.e-7) then - do num = fdiag,ldiag -!$omp parallel do default(shared) private(i, j, nb, ix) - do nb = 1,Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - GFS_Restart%data(nb,num)%var2p(ix) = zero - enddo - enddo - enddo - endif - do num = 1,nvar3d -!$omp parallel do default(shared) private(i, j, k, nb, ix) - do nb = 1,Atm_block%nblks - do k=1,npz - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - GFS_Restart%data(nb,num)%var3p(ix,k) = phy_var3(i,j,k,num) - enddo - enddo - enddo - enddo - - end subroutine phys_restart_read - - -!---------------------------------------------------------------------- -! phys_restart_write -!---------------------------------------------------------------------- -! routine to write out GFS surface restarts via the GFDL FMS restart -! subsystem. -! takes an optional argument to append timestamps for intermediate -! restarts. -! -! calls: register_restart_field, save_restart -!---------------------------------------------------------------------- - subroutine phys_restart_write (GFS_Restart, Atm_block, Model, fv_domain, timestamp) - !--- interface variable definitions - type(GFS_restart_type), intent(in) :: GFS_Restart - type(block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(in) :: Model - type(domain2d), intent(in) :: fv_domain - character(len=32), optional, intent(in) :: timestamp - !--- local variables - integer :: i, j, k, nb, ix, num - integer :: isc, iec, jsc, jec, npz, nx, ny - integer :: id_restart - integer :: nvar2d, nvar3d - real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() - real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() - !--- used for axis data for fms2_io - integer :: is, ie - integer, allocatable, dimension(:) :: buffer - character(7) :: indir='RESTART' - character(72) :: infile - logical :: amiopen - - isc = Atm_block%isc - iec = Atm_block%iec - jsc = Atm_block%jsc - jec = Atm_block%jec - npz = Atm_block%npz - nx = (iec - isc + 1) - ny = (jec - jsc + 1) - nvar2d = GFS_Restart%num2d - nvar3d = GFS_Restart%num3d - - !--- set file name - infile=trim(indir)//'/'//trim(fn_phy) - if( present(timestamp) ) infile=trim(indir)//'/'//trim(timestamp)//'.'//trim(fn_phy) - !--- register axis - amiopen=open_file(Phy_restart, trim(infile), 'overwrite', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) - if( amiopen ) then - call register_axis(Phy_restart, 'xaxis_1', 'X') - call register_field(Phy_restart, 'xaxis_1', 'double', (/'xaxis_1'/)) - call register_variable_attribute(Phy_restart, 'xaxis_1', 'cartesian_axis', 'X', str_len=1) - call get_global_io_domain_indices(Phy_restart, 'xaxis_1', is, ie, indices=buffer) - call write_data(Phy_restart, "xaxis_1", buffer) - deallocate(buffer) - - call register_axis(Phy_restart, 'yaxis_1', 'Y') - call register_field(Phy_restart, 'yaxis_1', 'double', (/'yaxis_1'/)) - call register_variable_attribute(Phy_restart, 'yaxis_1', 'cartesian_axis', 'Y', str_len=1) - call get_global_io_domain_indices(Phy_restart, 'yaxis_1', is, ie, indices=buffer) - call write_data(Phy_restart, "yaxis_1", buffer) - deallocate(buffer) - - call register_axis(Phy_restart, 'zaxis_1', npz) - call register_field(Phy_restart, 'zaxis_1', 'double', (/'zaxis_1'/)) - call register_variable_attribute(Phy_restart, 'zaxis_1', 'cartesian_axis', 'Z', str_len=1) - allocate( buffer(npz) ) - do i=1, npz - buffer(i)=i - end do - call write_data(Phy_restart, "zaxis_1", buffer) - deallocate(buffer) - - call register_axis(Phy_restart, 'Time', unlimited) - call register_field(Phy_restart, 'Time', 'double', (/'Time'/)) - call register_variable_attribute(Phy_restart, 'Time', 'cartesian_axis', 'T', str_len=1) - call write_data(Phy_restart, "Time", 1) - else - call mpp_error(FATAL, 'Error opening file '//trim(infile)) - end if - - !--- register the restart fields - if (.not. allocated(phy_var2)) then - allocate (phy_var2(nx,ny,nvar2d)) - allocate (phy_var3(nx,ny,npz,nvar3d)) - phy_var2 = zero - phy_var3 = zero - endif - - do num = 1,nvar2d - var2_p => phy_var2(:,:,num) - call register_restart_field(Phy_restart, trim(GFS_Restart%name2d(num)), var2_p, dimensions=(/'xaxis_1','yaxis_1','Time '/),& - &is_optional=.true.) - enddo - do num = 1,nvar3d - var3_p => phy_var3(:,:,:,num) - call register_restart_field(Phy_restart, trim(GFS_Restart%name3d(num)), var3_p, dimensions=(/'xaxis_1','yaxis_1','zaxis_1','Time '/),& - &is_optional=.true.) - enddo - nullify(var2_p) - nullify(var3_p) - - !--- 2D variables -!$omp parallel do default(shared) private(i, j, num, nb, ix) - do num = 1,nvar2d - do nb = 1,Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - phy_var2(i,j,num) = GFS_Restart%data(nb,num)%var2p(ix) - enddo - enddo - enddo - !--- 3D variables -!$omp parallel do default(shared) private(i, j, k, num, nb, ix) - do num = 1,nvar3d - do nb = 1,Atm_block%nblks - do k=1,npz - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - phy_var3(i,j,k,num) = GFS_Restart%data(nb,num)%var3p(ix,k) - enddo - enddo - enddo - enddo - - call write_restart(Phy_restart) - call close_file(Phy_restart) - - end subroutine phys_restart_write - -!------------------------------------------------------------------------- -!--- gfdl_diag_register --- -!------------------------------------------------------------------------- -! creates and populates a data type which is then used to "register" -! GFS physics diagnostic variables with the GFDL FMS diagnostic manager. -! includes short & long names, units, conversion factors, etc. -! there is no copying of data, but instead a clever use of pointers. -! calls a GFDL FMS routine to register diagnositcs and compare against -! the diag_table to determine what variables are to be output. -! -! calls: register_diag_field -!------------------------------------------------------------------------- - subroutine fv3gfs_diag_register(Diag, Time, Atm_block, Model, xlon, xlat, axes) - use physcons, only: con_g -!--- subroutine interface variable definitions - type(GFS_externaldiag_type), intent(inout) :: Diag(:) - type(time_type), intent(in) :: Time - type (block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(in) :: Model - real(kind=kind_phys), intent(in) :: xlon(:,:) - real(kind=kind_phys), intent(in) :: xlat(:,:) - integer, dimension(4), intent(in) :: axes -!--- local variables - integer :: idx, nrgst_bl, nrgst_nb, nrgst_vctbl - - isco = Atm_block%isc - ieco = Atm_block%iec - jsco = Atm_block%jsc - jeco = Atm_block%jec - levo = model%levs - fhzero = nint(Model%fhzero) -! ncld = Model%ncld - ncld = Model%imp_physics - nsoil = Model%lsoil - dtp = Model%dtp - imp_physics = Model%imp_physics - landsfcmdl = Model%lsm -! print *,'in fv3gfs_diag_register,ncld=',Model%ncld,Model%lsoil,Model%imp_physics, & -! ' dtp=',dtp,' landsfcmdl=',Model%lsm -! -!save lon/lat for vector interpolation - allocate(lon(isco:ieco,jsco:jeco)) - allocate(lat(isco:ieco,jsco:jeco)) - lon = xlon - lat = xlat - - do idx = 1,DIAG_SIZE - if (trim(Diag(idx)%name) == '') exit - tot_diag_idx = idx - enddo - - if (tot_diag_idx == DIAG_SIZE) then - call mpp_error(fatal, 'FV3GFS_io::fv3gfs_diag_register - need to increase parameter DIAG_SIZE') - endif - - allocate(nstt(tot_diag_idx), nstt_vctbl(tot_diag_idx)) - nstt = 0 - nstt_vctbl = 0 - nrgst_bl = 0 - nrgst_nb = 0 - nrgst_vctbl = 0 - num_axes_phys = 2 - do idx = 1,tot_diag_idx - if (diag(idx)%axes == -99) then - call mpp_error(fatal, 'gfs_driver::gfs_diag_register - attempt to register an undefined variable') - endif - Diag(idx)%id = register_diag_field (trim(Diag(idx)%mod_name), trim(Diag(idx)%name), & - axes(1:Diag(idx)%axes), Time, trim(Diag(idx)%desc), & - trim(Diag(idx)%unit), missing_value=real(missing_value)) - if(Diag(idx)%id > 0) then - if (Diag(idx)%axes == 2) then - if( index(trim(Diag(idx)%intpl_method),'bilinear') > 0 ) then - nrgst_bl = nrgst_bl + 1 - nstt(idx) = nrgst_bl - else if (trim(Diag(idx)%intpl_method) == 'nearest_stod' ) then - nrgst_nb = nrgst_nb + 1 - nstt(idx) = nrgst_nb - endif - if(trim(Diag(idx)%intpl_method) == 'vector_bilinear') then - if(Diag(idx)%name(1:1) == 'v' .or. Diag(idx)%name(1:1) == 'V') then - nrgst_vctbl = nrgst_vctbl + 1 - nstt_vctbl(idx) = nrgst_vctbl -! print *,'in phy_setup, vector_bilinear, name=', trim(Diag(idx)%name),' nstt_vctbl=', nstt_vctbl(idx), 'idx=',idx - endif - endif - else if (diag(idx)%axes == 3) then - if( index(trim(diag(idx)%intpl_method),'bilinear') > 0 ) then - nstt(idx) = nrgst_bl + 1 - nrgst_bl = nrgst_bl + levo - else if (trim(diag(idx)%intpl_method) == 'nearest_stod' ) then - nstt(idx) = nrgst_nb + 1 - nrgst_nb = nrgst_nb + levo - endif - if(trim(diag(idx)%intpl_method) == 'vector_bilinear') then - if(diag(idx)%name(1:1) == 'v' .or. diag(idx)%name(1:1) == 'V') then - nstt_vctbl(idx) = nrgst_vctbl + 1 - nrgst_vctbl = nrgst_vctbl + levo -! print *,'in phy_setup, vector_bilinear, name=', trim(diag(idx)%name),' nstt_vctbl=', nstt_vctbl(idx), 'idx=',idx - endif - endif - num_axes_phys = 3 - endif - endif - - enddo - - total_outputlevel = nrgst_bl + nrgst_nb - allocate(buffer_phys_bl(isco:ieco,jsco:jeco,nrgst_bl)) - allocate(buffer_phys_nb(isco:ieco,jsco:jeco,nrgst_nb)) - allocate(buffer_phys_windvect(3,isco:ieco,jsco:jeco,nrgst_vctbl)) - buffer_phys_bl = zero - buffer_phys_nb = zero - buffer_phys_windvect = zero - if(mpp_pe() == mpp_root_pe()) print *,'in fv3gfs_diag_register, nrgst_bl=',nrgst_bl,' nrgst_nb=',nrgst_nb, & - ' nrgst_vctbl=',nrgst_vctbl, 'isco=',isco,ieco,'jsco=',jsco,jeco,' num_axes_phys=', num_axes_phys - - end subroutine fv3gfs_diag_register -!------------------------------------------------------------------------- - - -!------------------------------------------------------------------------- -!--- gfs_diag_output --- -!------------------------------------------------------------------------- -! routine to transfer the diagnostic data to the gfdl fms diagnostic -! manager for eventual output to the history files. -! -! calls: send_data -!------------------------------------------------------------------------- - subroutine fv3gfs_diag_output(time, diag, atm_block, nx, ny, levs, ntcw, ntoz, & - dt, time_int, time_intfull, time_radsw, time_radlw) -!--- subroutine interface variable definitions - type(time_type), intent(in) :: time - type(GFS_externaldiag_type), intent(in) :: diag(:) - type (block_control_type), intent(in) :: atm_block - integer, intent(in) :: nx, ny, levs, ntcw, ntoz - real(kind=kind_phys), intent(in) :: dt - real(kind=kind_phys), intent(in) :: time_int - real(kind=kind_phys), intent(in) :: time_intfull - real(kind=kind_phys), intent(in) :: time_radsw - real(kind=kind_phys), intent(in) :: time_radlw -!--- local variables - integer :: i, j, k, idx, nblks, nb, ix, ii, jj - integer :: is_in, js_in, isc, jsc - character(len=2) :: xtra -#ifdef CCPP_32BIT - real, dimension(nx*ny) :: var2p - real, dimension(nx*ny,levs) :: var3p - real, dimension(nx,ny) :: var2 - real, dimension(nx,ny,levs) :: var3 -#else - real(kind=kind_phys), dimension(nx*ny) :: var2p - real(kind=kind_phys), dimension(nx*ny,levs) :: var3p - real(kind=kind_phys), dimension(nx,ny) :: var2 - real(kind=kind_phys), dimension(nx,ny,levs) :: var3 -#endif - real(kind=kind_phys) :: rdt, rtime_int, rtime_intfull, lcnvfac - real(kind=kind_phys) :: rtime_radsw, rtime_radlw - logical :: used - - nblks = atm_block%nblks - rdt = one/dt - rtime_int = one/time_int - rtime_intfull = one/time_intfull - rtime_radsw = one/time_radsw - rtime_radlw = one/time_radlw - - isc = atm_block%isc - jsc = atm_block%jsc - is_in = atm_block%isc - js_in = atm_block%jsc - -! if(mpp_pe()==mpp_root_pe())print *,'in,fv3gfs_io. time avg, time_int=',time_int - do idx = 1,tot_diag_idx - if (diag(idx)%id > 0) then - lcnvfac = diag(idx)%cnvfac - if (diag(idx)%time_avg) then - if ( trim(diag(idx)%time_avg_kind) == 'full' ) then - lcnvfac = lcnvfac*rtime_intfull -! if(mpp_pe()==mpp_root_pe())print *,'in,fv3gfs_io. full time avg, field=',trim(Diag(idx)%name),' time=',time_intfull - else if ( trim(diag(idx)%time_avg_kind) == 'rad_lw' ) then - lcnvfac = lcnvfac*min(rtime_radlw,rtime_int) -! if(mpp_pe()==mpp_root_pe())print *,'in,fv3gfs_io. rad longwave avg, field=',trim(Diag(idx)%name),' time=',time_radlw - else if ( trim(diag(idx)%time_avg_kind) == 'rad_sw' ) then - lcnvfac = lcnvfac*min(rtime_radsw,rtime_int) -! if(mpp_pe()==mpp_root_pe())print *,'in,fv3gfs_io. rad shortwave avg, field=',trim(Diag(idx)%name),' time=',time_radsw - else if ( trim(diag(idx)%time_avg_kind) == 'rad_swlw_min' ) then - lcnvfac = lcnvfac*min(max(rtime_radsw,rtime_radlw),rtime_int) -! if(mpp_pe()==mpp_root_pe())print *,'in,fv3gfs_io. rad swlw min avg, field=',trim(Diag(idx)%name),' time=',time_radlw,time_radsw,time_int - else - lcnvfac = lcnvfac*rtime_int - endif - endif - if (diag(idx)%axes == 2) then - ! Integer data - int_or_real: if (associated(Diag(idx)%data(1)%int2)) then - if (trim(Diag(idx)%intpl_method) == 'nearest_stod') then - var2(1:nx,1:ny) = 0._kind_phys - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - var2(i,j) = real(Diag(idx)%data(nb)%int2(ix), kind=kind_phys) - enddo - enddo - call store_data(Diag(idx)%id, var2, Time, idx, Diag(idx)%intpl_method, Diag(idx)%name) - else - call mpp_error(FATAL, 'Interpolation method ' // trim(Diag(idx)%intpl_method) // ' for integer variable ' & - // trim(Diag(idx)%name) // ' not supported.') - endif - ! Real data - else ! int_or_real - if (trim(diag(idx)%mask) == 'positive_flux') then - !--- albedos are actually a ratio of two radiation surface properties - var2(1:nx,1:ny) = 0._kind_phys - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - if (Diag(idx)%data(nb)%var21(ix) > 0._kind_phys) & - var2(i,j) = max(0._kind_phys,min(1._kind_phys,Diag(idx)%data(nb)%var2(ix)/Diag(idx)%data(nb)%var21(ix)))*lcnvfac - enddo - enddo - elseif (trim(Diag(idx)%mask) == 'land_ice_only') then - !--- need to "mask" gflux to output valid data over land/ice only - var2(1:nx,1:ny) = missing_value - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - if (Diag(idx)%data(nb)%var21(ix) /= 0) var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac - enddo - enddo - elseif (trim(Diag(idx)%mask) == 'land_only') then - !--- need to "mask" soilm to have value only over land - var2(1:nx,1:ny) = missing_value - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - if (Diag(idx)%data(nb)%var21(ix) == 1) var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac - enddo - enddo - elseif (trim(Diag(idx)%mask) == 'cldmask') then - !--- need to "mask" soilm to have value only over land - var2(1:nx,1:ny) = missing_value - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - if (Diag(idx)%data(nb)%var21(ix)*100. > 0.5) var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac - enddo - enddo - elseif (trim(Diag(idx)%mask) == 'cldmask_ratio') then - !--- need to "mask" soilm to have value only over land - var2(1:nx,1:ny) = missing_value - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - if (Diag(idx)%data(nb)%var21(ix)*100.*lcnvfac > 0.5) var2(i,j) = Diag(idx)%data(nb)%var2(ix)/ & - Diag(idx)%data(nb)%var21(ix) - enddo - enddo - elseif (trim(Diag(idx)%mask) == 'pseudo_ps') then - if ( use_wrtgridcomp_output ) then - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - var2(i,j) = (Diag(idx)%data(nb)%var2(ix)/stndrd_atmos_ps)**(rdgas/grav*stndrd_atmos_lapse) - enddo - enddo - else - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - var2(i,j) = Diag(idx)%data(nb)%var2(ix) - enddo - enddo - endif - elseif (trim(Diag(idx)%mask) == '') then - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) - var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac - enddo - enddo - endif - endif int_or_real -! used=send_data(Diag(idx)%id, var2, Time) -! print *,'in phys, after store_data, idx=',idx,' var=', trim(Diag(idx)%name) - call store_data(Diag(idx)%id, var2, Time, idx, Diag(idx)%intpl_method, Diag(idx)%name) -! if(trim(Diag(idx)%name) == 'totprcp_ave' ) print *,'in gfs_io, totprcp=',Diag(idx)%data(1)%var2(1:3), & -! ' lcnvfac=', lcnvfac - elseif (Diag(idx)%axes == 3) then - !--- - !--- skipping other 3D variables with the following else statement - !--- -! if(mpp_pe()==mpp_root_pe())print *,'in,fv3gfs_io. 3D fields, idx=',idx,'varname=',trim(diag(idx)%name), & -! 'lcnvfac=',lcnvfac, 'levo=',levo,'nx=',nx,'ny=',ny - do k=1, levo - do j = 1, ny - jj = j + jsc -1 - do i = 1, nx - ii = i + isc -1 - nb = Atm_block%blkno(ii,jj) - ix = Atm_block%ixp(ii,jj) -! if(mpp_pe()==mpp_root_pe())print *,'in,fv3gfs_io,sze(Diag(idx)%data(nb)%var3)=', & -! size(Diag(idx)%data(nb)%var3,1),size(Diag(idx)%data(nb)%var3,2) - var3(i,j,k) = Diag(idx)%data(nb)%var3(ix,levo-k+1)*lcnvfac - enddo - enddo - enddo - call store_data3D(Diag(idx)%id, var3, Time, idx, Diag(idx)%intpl_method, Diag(idx)%name) -#ifdef JUNK - else - !--- temperature tendency - if (trim(Diag(idx)%name) == 'dtemp_dt') then - var3(1:nx,1:ny,1:levs) = RESHAPE(Statein%tgrs(1:ngptc,levs:1:-1), (/nx,ny,levs/)) - var3(1:nx,1:ny,1:levs) = (RESHAPE(Stateout%gt0(1:ngptc,levs:1:-1), (/nx,ny,levs/)) & - - var3(1:nx,1:ny,1:levs))*rdt - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - !--- horizontal wind component tendency - if (trim(Diag(idx)%name) == 'du_dt') then - var3(1:nx,1:ny,1:levs) = RESHAPE(Statein%ugrs(1:ngptc,levs:1:-1), (/nx,ny,levs/)) - var3(1:nx,1:ny,1:levs) = (RESHAPE(Stateout%gu0(1:ngptc,levs:1:-1), (/nx,ny,levs/)) & - - var3(1:nx,1:ny,1:levs))*rdt - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - !--- meridional wind component tendency - if (trim(Diag(idx)%name) == 'dv_dt') then - var3(1:nx,1:ny,1:levs) = RESHAPE(Statein%vgrs(1:ngptc,levs:1:-1), (/nx,ny,levs/)) - var3(1:nx,1:ny,1:levs) = (RESHAPE(Stateout%gv0(1:ngptc,levs:1:-1), (/nx,ny,levs/)) & - - var3(1:nx,1:ny,1:levs))*rdt - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - !--- specific humidity tendency - if (trim(Diag(idx)%name) == 'dsphum_dt') then - var3(1:nx,1:ny,1:levs) = RESHAPE(Statein%qgrs(1:ngptc,levs:1:-1,1:1), (/nx,ny,levs/)) - var3(1:nx,1:ny,1:levs) = (RESHAPE(Stateout%gq0(1:ngptc,levs:1:-1,1:1), (/nx,ny,levs/)) & - - var3(1:nx,1:ny,1:levs))*rdt - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - !--- cloud water mixing ration tendency - if (trim(Diag(idx)%name) == 'dclwmr_dt') then - var3(1:nx,1:ny,1:levs) = RESHAPE(Statein%qgrs(1:ngptc,levs:1:-1,ntcw:ntcw), (/nx,ny,levs/)) - var3(1:nx,1:ny,1:levs) = (RESHAPE(Stateout%gq0(1:ngptc,levs:1:-1,ntcw:ntcw), (/nx,ny,levs/)) & - - var3(1:nx,1:ny,1:levs))*rdt - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif - !--- ozone mixing ration tendency -#ifdef MULTI_GASES - if (trim(Diag(idx)%name) == 'dspo3_dt') then -#else - if (trim(Diag(idx)%name) == 'do3mr_dt') then -#endif - var3(1:nx,1:ny,1:levs) = RESHAPE(Statein%qgrs(1:ngptc,levs:1:-1,ntoz:ntoz), (/nx,ny,levs/)) - var3(1:nx,1:ny,1:levs) = (RESHAPE(Stateout%gq0(1:ngptc,levs:1:-1,ntoz:ntoz), (/nx,ny,levs/)) & - - var3(1:nx,1:ny,1:levs))*rdt - used=send_data(Diag(idx)%id, var3, Time, is_in=is_in, js_in=js_in, ks_in=1) - endif -#endif - endif - endif - enddo - - - end subroutine fv3gfs_diag_output -! -!------------------------------------------------------------------------- - subroutine store_data(id, work, Time, idx, intpl_method, fldname) - integer, intent(in) :: id - integer, intent(in) :: idx -#ifdef CCPP_32BIT - real, intent(in) :: work(:,:) -#else - real(kind=kind_phys), intent(in) :: work(ieco-isco+1,jeco-jsco+1) -#endif - type(time_type), intent(in) :: Time - character(*), intent(in) :: intpl_method - character(*), intent(in) :: fldname -! - real(kind=kind_phys) :: sinlat, sinlon, coslon - integer k,j,i,kb,nv,i1,j1 - logical used -! - if( id > 0 ) then - if( use_wrtgridcomp_output ) then - if( trim(intpl_method) == 'bilinear') then -!$omp parallel do default(shared) private(i,j) - do j= jsco,jeco - do i= isco,ieco - buffer_phys_bl(i,j,nstt(idx)) = work(i-isco+1,j-jsco+1) - enddo - enddo - else if(trim(intpl_method) == 'nearest_stod') then -!$omp parallel do default(shared) private(i,j) - do j= jsco,jeco - do i= isco,ieco - buffer_phys_nb(i,j,nstt(idx)) = work(i-isco+1,j-jsco+1) - enddo - enddo - else if(trim(intpl_method) == 'vector_bilinear') then -!first save the data -!$omp parallel do default(shared) private(i,j) - do j= jsco,jeco - do i= isco,ieco - buffer_phys_bl(i,j,nstt(idx)) = work(i-isco+1,j-jsco+1) - enddo - enddo - if( fldname(1:1) == 'u' .or. fldname(1:1) == 'U') then - if(.not.allocated(uwork)) allocate(uwork(isco:ieco,jsco:jeco)) -!$omp parallel do default(shared) private(i,j) - do j= jsco,jeco - do i= isco,ieco - uwork(i,j) = work(i-isco+1,j-jsco+1) - enddo - enddo - uwindname = fldname - uwork_set = .true. - endif - if( fldname(1:1) == 'v' .or. fldname(1:1) == 'V') then -!set up wind vector - if( uwork_set .and. trim(uwindname(2:)) == trim(fldname(2:))) then - nv = nstt_vctbl(idx) -!$omp parallel do default(shared) private(i,j,i1,j1,sinlat,sinlon,coslon) - do j= jsco,jeco - j1 = j-jsco+1 - do i= isco,ieco - i1 = i-isco+1 - sinlat = sin(lat(i,j)) - sinlon = sin(lon(i,j)) - coslon = cos(lon(i,j)) - buffer_phys_windvect(1,i,j,nv) = uwork(i,j)*coslon - work(i1,j1)*sinlat*sinlon - buffer_phys_windvect(2,i,j,nv) = uwork(i,j)*sinlon + work(i1,j1)*sinlat*coslon - buffer_phys_windvect(3,i,j,nv) = work(i1,j1)*cos(lat(i,j)) - enddo - enddo - endif - uwork = zero - uwindname = '' - uwork_set = .false. - endif - - endif - else - used = send_data(id, work, Time) - endif - endif -! - end subroutine store_data -! -!------------------------------------------------------------------------- -! - subroutine store_data3D(id, work, Time, idx, intpl_method, fldname) - integer, intent(in) :: id - integer, intent(in) :: idx -#ifdef CCPP_32BIT - real, intent(in) :: work(:,:,:) -#else - real(kind=kind_phys), intent(in) :: work(ieco-isco+1,jeco-jsco+1,levo) -#endif - type(time_type), intent(in) :: Time - character(*), intent(in) :: intpl_method - character(*), intent(in) :: fldname -! - real(kind=kind_phys), allocatable, dimension(:,:) :: sinlon, coslon, sinlat, coslat - integer k,j,i,kb,nv,i1,j1 - logical used -! - if( id > 0 ) then - if( use_wrtgridcomp_output ) then - if( trim(intpl_method) == 'bilinear') then -!$omp parallel do default(shared) private(i,j,k) - do k= 1,levo - do j= jsco,jeco - do i= isco,ieco - buffer_phys_bl(i,j,nstt(idx)+k-1) = work(i-isco+1,j-jsco+1,k) - enddo - enddo - enddo - else if(trim(intpl_method) == 'nearest_stod') then -!$omp parallel do default(shared) private(i,j,k) - do k= 1,levo - do j= jsco,jeco - do i= isco,ieco - buffer_phys_nb(i,j,nstt(idx)+k-1) = work(i-isco+1,j-jsco+1,k) - enddo - enddo - enddo - else if(trim(intpl_method) == 'vector_bilinear') then -!first save the data -!$omp parallel do default(shared) private(i,j,k) - do k= 1,levo - do j= jsco,jeco - do i= isco,ieco - buffer_phys_bl(i,j,nstt(idx)+k-1) = work(i-isco+1,j-jsco+1,k) - enddo - enddo - enddo - if( fldname(1:1) == 'u' .or. fldname(1:1) == 'U') then - if(.not.allocated(uwork3d)) allocate(uwork3d(isco:ieco,jsco:jeco,levo)) -!$omp parallel do default(shared) private(i,j,k) - do k= 1, levo - do j= jsco,jeco - do i= isco,ieco - uwork3d(i,j,k) = work(i-isco+1,j-jsco+1,k) - enddo - enddo - enddo - uwindname = fldname - uwork_set = .true. - endif - if( fldname(1:1) == 'v' .or. fldname(1:1) == 'V') then -!set up wind vector - if( uwork_set .and. trim(uwindname(2:)) == trim(fldname(2:))) then - allocate (sinlon(isco:ieco,jsco:jeco), coslon(isco:ieco,jsco:jeco), & - sinlat(isco:ieco,jsco:jeco), coslat(isco:ieco,jsco:jeco)) -!$omp parallel do default(shared) private(i,j) - do j= jsco,jeco - do i= isco,ieco - sinlon(i,j) = sin(lon(i,j)) - coslon(i,j) = cos(lon(i,j)) - sinlat(i,j) = sin(lat(i,j)) - coslat(i,j) = cos(lat(i,j)) - enddo - enddo -!$omp parallel do default(shared) private(i,j,k,nv,i1,j1) - do k= 1, levo - nv = nstt_vctbl(idx)+k-1 - do j= jsco,jeco - j1 = j-jsco+1 - do i= isco,ieco - i1 = i-isco+1 - buffer_phys_windvect(1,i,j,nv) = uwork3d(i,j,k)*coslon(i,j) & - - work(i1,j1,k)*sinlat(i,j)*sinlon(i,j) - buffer_phys_windvect(2,i,j,nv) = uwork3d(i,j,k)*sinlon(i,j) & - + work(i1,j1,k)*sinlat(i,j)*coslon(i,j) - buffer_phys_windvect(3,i,j,nv) = work(i1,j1,k)*coslat(i,j) - enddo - enddo - enddo - deallocate (sinlon, coslon, sinlat, coslat) - endif - uwork3d = zero - uwindname = '' - uwork_set = .false. - endif - - endif - else - used = send_data(id, work, Time) - endif - endif -! - end subroutine store_data3D -! -!------------------------------------------------------------------------- -! -#ifdef use_WRTCOMP - - subroutine fv_phys_bundle_setup(Diag, axes, phys_bundle, fcst_grid, quilting, nbdlphys, rc) -! -!------------------------------------------------------------- -!*** set esmf bundle for phys output fields -!------------------------------------------------------------ -! - use esmf - use diag_data_mod, ONLY: diag_atttype -! - implicit none -! - type(GFS_externaldiag_type),intent(in) :: Diag(:) - integer, intent(in) :: axes(:) - type(ESMF_FieldBundle),intent(inout) :: phys_bundle(:) - type(ESMF_Grid),intent(inout) :: fcst_grid - logical,intent(in) :: quilting - integer, intent(in) :: nbdlphys - integer,intent(out) :: rc - -! -!*** local variables - integer i, j, k, n, idx, ibdl, nbdl - integer id, axis_length, direction, edges, axis_typ - integer num_attributes, num_field_dyn - integer currdate(6) - character(2) axis_id - character(255) :: units, long_name, cart_name, axis_direct, edgesS - character(128) :: output_name, physbdl_name, outputfile1 - logical :: lput2physbdl, loutputfile, l2dvector - type(domain1d) :: Domain - type(domainUG) :: DomainU - type(ESMF_Field) :: field - real,dimension(:),allocatable :: axis_data - character(128),dimension(:), allocatable :: bdl_intplmethod, outputfile - type(diag_atttype),dimension(:),allocatable :: attributes - real(4),dimension(:,:),pointer :: dataPtr2d -! - logical isPresent - integer udimCount - character(80),dimension(:),allocatable :: udimList -! -!------------------------------------------------------------ -!--- use wrte grid component for output - use_wrtgridcomp_output = quilting -! if(mpp_pe()==mpp_root_pe())print *,'in fv_phys bundle,use_wrtgridcomp_output=',use_wrtgridcomp_output, & -! print *,'in fv_phys bundle,use_wrtgridcomp_output=',use_wrtgridcomp_output, & -! 'isco=',isco,ieco,'jsco=',jsco,jeco,'tot_diag_idx=',tot_diag_idx -! -!------------------------------------------------------------ -!*** add attributes to the bundle such as subdomain limtis, -!*** axes, output time, etc -!------------------------------------------------------------ -! - allocate(bdl_intplmethod(nbdlphys), outputfile(nbdlphys)) - if(mpp_pe()==mpp_root_pe()) print *,'in fv_phys bundle,nbdl=',nbdlphys - do ibdl = 1, nbdlphys - loutputfile = .false. - call ESMF_FieldBundleGet(phys_bundle(ibdl), name=physbdl_name,rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - idx = index(physbdl_name,'_bilinear') - if(idx > 0) then - outputfile(ibdl) = physbdl_name(1:idx-1) - bdl_intplmethod(ibdl) = 'bilinear' - loutputfile = .true. - endif - idx = index(physbdl_name,'_nearest_stod') - if(idx > 0) then - outputfile(ibdl) = physbdl_name(1:idx-1) - bdl_intplmethod(ibdl) = 'nearest_stod' - loutputfile = .true. - endif - if( .not. loutputfile) then - outputfile(ibdl) = 'phy' - bdl_intplmethod(ibdl) = 'nearest_stod' - endif -! print *,'in fv_phys bundle,i=',ibdl,'outputfile=',trim(outputfile(ibdl)), & -! 'bdl_intplmethod=',trim(bdl_intplmethod(ibdl)) - - call ESMF_AttributeAdd(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & - attrList=(/"fhzero ", "ncld ", "nsoil ",& - "imp_physics", "dtp ", "landsfcmdl "/), rc=rc) - - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & - name="fhzero", value=fhzero, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & - name="ncld", value=ncld, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & - name="nsoil", value=nsoil, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & - name="imp_physics", value=imp_physics, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & - name="dtp", value=dtp, rc=rc) -! print *,'in fcst gfdl diag, dtp=',dtp,' ibdl=',ibdl - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & - name="landsfcmdl", value=landsfcmdl, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - -!end ibdl - enddo -! -!*** get axis names - allocate(axis_name(num_axes_phys)) - do id = 1,num_axes_phys - call get_diag_axis_name( axes(id), axis_name(id)) - enddo - isPresent = .false. - if( num_axes_phys>2 ) then - allocate(axis_name_vert(num_axes_phys-2)) - do id=3,num_axes_phys - axis_name_vert(id-2) = axis_name(id) - enddo -! - call ESMF_AttributeGet(fcst_grid, convention="NetCDF", purpose="FV3", & - name="vertical_dim_labels", isPresent=isPresent, & - itemCount=udimCount, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - if (isPresent .and. (udimCount>num_axes_phys-2) ) then - allocate(udimList(udimCount)) - call ESMF_AttributeGet(fcst_grid, convention="NetCDF", purpose="FV3", & - name="vertical_dim_labels", valueList=udimList, rc=rc) -! if(mpp_pe()==mpp_root_pe()) print *,'in fv3gfsio, vertical -! list=',udimList(1:udimCount),'rc=',rc - - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - else - - if(mpp_pe()==mpp_root_pe()) print *,'in fv_dyn bundle,axis_name_vert=',axis_name_vert - call ESMF_AttributeAdd(fcst_grid, convention="NetCDF", purpose="FV3", & - attrList=(/"vertical_dim_labels"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & - name="vertical_dim_labels", valueList=axis_name_vert, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - endif - deallocate(axis_name_vert) - endif - -!*** add attributes - if(allocated(all_axes)) deallocate(all_axes) - allocate(all_axes(num_axes_phys)) - all_axes(1:num_axes_phys) = axes(1:num_axes_phys) - if (.not. isPresent .or. (udimCount2 ) then -! if(mpp_pe()==mpp_root_pe()) print *,' in dyn add grid, axis_name=', & -! trim(axis_name(id)),'axis_data=',axis_data - if(trim(edgesS)/='') then - call ESMF_AttributeAdd(fcst_grid, convention="NetCDF", purpose="FV3", & - attrList=(/trim(axis_name(id)),trim(axis_name(id))//":long_name", & - trim(axis_name(id))//":units", trim(axis_name(id))//":cartesian_axis", & - trim(axis_name(id))//":positive", trim(axis_name(id))//":edges"/), rc=rc) - else - call ESMF_AttributeAdd(fcst_grid, convention="NetCDF", purpose="FV3", & - attrList=(/trim(axis_name(id)),trim(axis_name(id))//":long_name", & - trim(axis_name(id))//":units", trim(axis_name(id))//":cartesian_axis", & - trim(axis_name(id))//":positive"/), rc=rc) - endif - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & - name=trim(axis_name(id)), valueList=axis_data, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & - name=trim(axis_name(id))//":long_name", value=trim(long_name), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & - name=trim(axis_name(id))//":units", value=trim(units), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & - name=trim(axis_name(id))//":cartesian_axis", value=trim(cart_name), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - if(direction > 0) then - axis_direct = "up" - else - axis_direct = "down" - endif - call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & - name=trim(axis_name(id))//":positive", value=trim(axis_direct), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - if(trim(edgesS)/='') then - call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & - name=trim(axis_name(id))//":edges", value=trim(edgesS), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - endif - - endif -! - deallocate(axis_data) - enddo - endif -! print *,'in setup fieldbundle_phys, num_axes_phys=',num_axes_phys,'tot_diag_idx=',tot_diag_idx, & -! 'nbdlphys=',nbdlphys -! -!----------------------------------------------------------------------------------------- -!*** add esmf fields -! - do idx= 1,tot_diag_idx - - lput2physbdl = .false. - do ibdl = 1, nbdlphys - - if( index(trim(Diag(idx)%intpl_method),trim(bdl_intplmethod(ibdl))) > 0) then - lput2physbdl = .true. - if( Diag(idx)%id > 0 ) then - call find_output_name(trim(Diag(idx)%mod_name),trim(Diag(idx)%name),output_name) - -!add origin field - call add_field_to_phybundle(trim(output_name),trim(Diag(idx)%desc),trim(Diag(idx)%unit), "time: point", & - axes(1:Diag(idx)%axes), fcst_grid, nstt(idx), phys_bundle(ibdl), outputfile(ibdl), & - bdl_intplmethod(ibdl), rcd=rc) -! if( mpp_pe() == mpp_root_pe()) print *,'phys, add field,',trim(Diag(idx)%name),'idx=',idx,'ibdl=',ibdl -! - if( index(trim(Diag(idx)%intpl_method), "vector") > 0) then - l2dvector = .true. - if (nstt_vctbl(idx) > 0) then - output_name = 'wind'//trim(output_name)//'vector' - outputfile1 = 'none' - call add_field_to_phybundle(trim(output_name),trim(Diag(idx)%desc),trim(Diag(idx)%unit), "time: point", & - axes(1:Diag(idx)%axes), fcst_grid, nstt_vctbl(idx),phys_bundle(ibdl), outputfile1, & - bdl_intplmethod(ibdl),l2dvector=l2dvector, rcd=rc) -! if( mpp_pe() == mpp_root_pe()) print *,'in phys, add vector field,',trim(Diag(idx)%name),' idx=',idx,' ibdl=',ibdl - endif - endif - - endif - endif - enddo - if( .not. lput2physbdl ) then - if( mpp_pe() == mpp_root_pe()) print *,'WARNING: not matching interpolation method, field ',trim(Diag(idx)%name), & - ' is not added to phys bundle ' - endif - - enddo - deallocate(axis_name) - deallocate(all_axes) - - end subroutine fv_phys_bundle_setup -! -!----------------------------------------------------------------------------------------- - subroutine add_field_to_phybundle(var_name,long_name,units,cell_methods, axes,phys_grid, & - kstt,phys_bundle,output_file,intpl_method,range,l2dvector,rcd) -! - use esmf -! - implicit none - - character(*), intent(in) :: var_name, long_name, units, cell_methods - character(*), intent(in) :: output_file, intpl_method - integer, intent(in) :: axes(:) - type(esmf_grid), intent(in) :: phys_grid - integer, intent(in) :: kstt - type(esmf_fieldbundle),intent(inout) :: phys_bundle - real, intent(in), optional :: range(2) - logical, intent(in), optional :: l2dvector - integer, intent(out), optional :: rcd -! -!*** local variable - type(ESMF_Field) :: field - type(ESMF_DataCopy_Flag) :: copyflag=ESMF_DATACOPY_REFERENCE - integer rc, i, j, idx - real(4),dimension(:,:),pointer :: temp_r2d - real(4),dimension(:,:,:),pointer :: temp_r3d - logical :: l2dvector_local -! - ! fix for non-standard compilers (e.g. PGI) - l2dvector_local = .false. - if (present(l2dvector)) then - if (l2dvector) then - l2dvector_local = .true. - end if - end if -! -!*** create esmf field - if (l2dvector_local .and. size(axes)==2) then - temp_r3d => buffer_phys_windvect(1:3,isco:ieco,jsco:jeco,kstt) -! if( mpp_root_pe() == 0) print *,'phys, create wind vector esmf field' - call ESMF_LogWrite('bf create winde vector esmf field '//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - -!datacopyflag=ESMF_DATACOPY_VALUE, & - field = ESMF_FieldCreate(phys_grid, temp_r3d, datacopyflag=ESMF_DATACOPY_REFERENCE, & - gridToFieldMap=(/2,3/), ungriddedLBound=(/1/), ungriddedUBound=(/3/), & - name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) - - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - call ESMF_LogWrite('af winde vector esmf field create '//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) - - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"output_file"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name='output_file',value=trim(output_file),rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_LogWrite('before winde vector esmf field add output_file', ESMF_LOGMSG_INFO, rc=rc) - -! if( mpp_root_pe() == 0)print *,'phys, aftercreate wind vector esmf field' - call ESMF_FieldBundleAdd(phys_bundle,(/field/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - if( present(rcd)) rcd=rc - call ESMF_LogWrite('aft winde vector esmf field add to fieldbundle'//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) - return - else if( trim(intpl_method) == 'nearest_stod' ) then - if(size(axes) == 2) then - temp_r2d => buffer_phys_nb(isco:ieco,jsco:jeco,kstt) - field = ESMF_FieldCreate(phys_grid, temp_r2d, datacopyflag=copyflag, & - name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - else if(size(axes) == 3) then - temp_r3d => buffer_phys_nb(isco:ieco,jsco:jeco,kstt:kstt+levo-1) - field = ESMF_FieldCreate(phys_grid, temp_r3d, datacopyflag=copyflag, & - name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - if( mpp_pe() == mpp_root_pe()) print *,'add 3D field to after nearest_stod, fld=', trim(var_name) - endif - else if( trim(intpl_method) == 'bilinear' ) then - if(size(axes) == 2) then - temp_r2d => buffer_phys_bl(isco:ieco,jsco:jeco,kstt) - field = ESMF_FieldCreate(phys_grid, temp_r2d, datacopyflag=copyflag, & - name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - else if(size(axes) == 3) then - temp_r3d => buffer_phys_bl(isco:ieco,jsco:jeco,kstt:kstt+levo-1) - field = ESMF_FieldCreate(phys_grid, temp_r3d, datacopyflag=copyflag, & - name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - if( mpp_pe() == mpp_root_pe()) print *,'add field to after bilinear, fld=', trim(var_name) - endif - endif -! -!*** add field attributes - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"long_name"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name='long_name',value=trim(long_name),rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"units"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name='units',value=trim(units),rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"missing_value"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name='missing_value',value=real(missing_value,kind=4),rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"_FillValue"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name='_FillValue',value=real(missing_value,kind=4),rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"cell_methods"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name='cell_methods',value=trim(cell_methods),rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) -! - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"output_file"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name='output_file',value=trim(output_file),rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & - line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - -! -!*** add vertical coord attribute: - if( size(axes) > 2) then - do i=3,size(axes) - idx=0 - do j=1,size(all_axes) - if (axes(i)==all_axes(j)) then - idx=j - exit - endif - enddo - if (idx>0) then - call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & - attrList=(/"ESMF:ungridded_dim_labels"/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name="ESMF:ungridded_dim_labels", valueList=(/trim(axis_name(idx))/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - endif - enddo - endif - -!*** add field into bundle - call ESMF_FieldBundleAdd(phys_bundle,(/field/), rc=rc) - if( present(rcd)) rcd=rc -! - call ESMF_LogWrite('phys field add to fieldbundle '//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) - - end subroutine add_field_to_phybundle -! -! - subroutine find_output_name(module_name,field_name,output_name) - character(*), intent(in) :: module_name - character(*), intent(in) :: field_name - character(*), intent(out) :: output_name -! - integer i,in_num, out_num - integer tile_count -! - tile_count = 1 - in_num = find_input_field(module_name, field_name, tile_count) -! - output_name = '' - do i=1, max_output_fields - if(output_fields(i)%input_field == in_num) then - output_name = output_fields(i)%output_name - exit - endif - enddo - if(output_name == '') then - print *,'Error, cant find out put name' - endif - - end subroutine find_output_name -#endif -!------------------------------------------------------------------------- - -end module FV3GFS_io_mod diff --git a/io/FV3GFS_restart_io.F90 b/io/FV3GFS_restart_io.F90 deleted file mode 100644 index da641c04e..000000000 --- a/io/FV3GFS_restart_io.F90 +++ /dev/null @@ -1,920 +0,0 @@ -module FV3GFS_restart_io_mod - - use esmf - use block_control_mod, only: block_control_type - use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, kind_phys - use GFS_restart, only: GFS_restart_type - - implicit none - private - - real(kind_phys), parameter:: zero = 0.0, one = 1.0 - integer, parameter :: r8 = kind_phys - - integer :: nvar2d, nvar3d, npz - real(kind=kind_phys), allocatable, target, dimension(:,:,:) :: phy_var2 - real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: phy_var3 - character(len=32),dimension(:),allocatable :: phy_var2_names, phy_var3_names - - integer :: nvar2m, nvar2o, nvar3, nvar2r, nvar2mp, nvar3mp - real(kind=kind_phys), allocatable, target, dimension(:,:,:) :: sfc_var2 - real(kind=kind_phys), allocatable, target, dimension(:,:,:) :: sfc_var3ice - real(kind=kind_phys), allocatable, target, dimension(:,:,:,:) :: sfc_var3, sfc_var3sn,sfc_var3eq,sfc_var3zn - character(len=32),allocatable,dimension(:) :: sfc_name2, sfc_name3 - - type(ESMF_FieldBundle) :: phy_bundle, sfc_bundle - - public FV3GFS_restart_register - - public fv_phy_restart_output - public fv_phy_restart_bundle_setup - - public fv_sfc_restart_output - public fv_sfc_restart_bundle_setup - - interface copy_from_GFS_Data - module procedure copy_from_GFS_Data_2d_phys2phys, & - copy_from_GFS_Data_3d_phys2phys, & - copy_from_GFS_Data_2d_int2phys, & - copy_from_GFS_Data_3d_int2phys, & - copy_from_GFS_Data_2d_stack_phys2phys - end interface - - contains - - subroutine FV3GFS_restart_register (Sfcprop, GFS_restart, Atm_block, Model) - - ! this subroutine must allocate all data buffers and set the variable names - ! for both 'phy' and 'sfc' restart bundles - - implicit none - - type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) - type(GFS_restart_type), intent(in) :: GFS_Restart - type(block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(in) :: Model - - integer :: isc, iec, jsc, jec, nx, ny - integer :: num - - isc = Atm_block%isc - iec = Atm_block%iec - jsc = Atm_block%jsc - jec = Atm_block%jec - npz = Atm_block%npz - nx = (iec - isc + 1) - ny = (jec - jsc + 1) - - !--------------- phy - nvar2d = GFS_Restart%num2d - nvar3d = GFS_Restart%num3d - - allocate (phy_var2(nx,ny,nvar2d), phy_var2_names(nvar2d)) - allocate (phy_var3(nx,ny,npz,nvar3d), phy_var3_names(nvar3d)) - phy_var2 = zero - phy_var3 = zero - do num = 1,nvar2d - phy_var2_names(num) = trim(GFS_Restart%name2d(num)) - enddo - do num = 1,nvar3d - phy_var3_names(num) = trim(GFS_Restart%name3d(num)) - enddo - - !--------------- sfc - nvar2m = 48 - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - nvar2m = nvar2m + 4 -! nvar2m = nvar2m + 5 - endif - if (Model%cplwav) nvar2m = nvar2m + 1 - nvar2o = 18 - if (Model%lsm == Model%lsm_ruc) then - if (Model%rdlai) then - nvar2r = 13 - else - nvar2r = 12 - endif - nvar3 = 5 - else - nvar2r = 0 - nvar3 = 3 - endif - nvar2mp = 0 - nvar3mp = 0 - if (Model%lsm == Model%lsm_noahmp) then - nvar2mp = 29 - nvar3mp = 5 - endif - - !--- allocate the various containers needed for restarts - allocate(sfc_name2(nvar2m+nvar2o+nvar2mp+nvar2r)) - allocate(sfc_var2(nx,ny,nvar2m+nvar2o+nvar2mp+nvar2r)) - allocate(sfc_name3(0:nvar3+nvar3mp)) - allocate(sfc_var3ice(nx,ny,Model%kice)) - - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then - allocate(sfc_var3(nx,ny,Model%lsoil,nvar3)) - elseif (Model%lsm == Model%lsm_ruc) then - allocate(sfc_var3(nx,ny,Model%lsoil_lsm,nvar3)) - endif - - sfc_var2 = -9999.0_r8 - sfc_var3 = -9999.0_r8 - sfc_var3ice= -9999.0_r8 - - if (Model%lsm == Model%lsm_noahmp) then - allocate(sfc_var3sn(nx,ny,-2:0,4:6)) - allocate(sfc_var3eq(nx,ny,1:4,7:7)) - allocate(sfc_var3zn(nx,ny,-2:4,8:8)) - - sfc_var3sn = -9999.0_r8 - sfc_var3eq = -9999.0_r8 - sfc_var3zn = -9999.0_r8 - endif - - call fill_Sfcprop_names(Model,sfc_name2,sfc_name3,nvar2m,.true.) - - sfc_name3(0) = 'tiice' - - if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then - sfc_name3(1) = 'stc' - sfc_name3(2) = 'smc' - sfc_name3(3) = 'slc' - if (Model%lsm == Model%lsm_noahmp) then - sfc_name3(4) = 'snicexy' - sfc_name3(5) = 'snliqxy' - sfc_name3(6) = 'tsnoxy' - sfc_name3(7) = 'smoiseq' - sfc_name3(8) = 'zsnsoxy' - endif - else if (Model%lsm == Model%lsm_ruc) then - sfc_name3(1) = 'tslb' - sfc_name3(2) = 'smois' - sfc_name3(3) = 'sh2o' - sfc_name3(4) = 'smfr' - sfc_name3(5) = 'flfr' - end if - - end subroutine FV3GFS_restart_register - - subroutine fv_phy_restart_output(GFS_Restart, Atm_block) - - implicit none - - type(GFS_restart_type), intent(in) :: GFS_Restart - type(block_control_type), intent(in) :: Atm_block - -!*** local variables - integer :: i, j, k, n - integer :: nb, ix, num - integer :: isc, iec, jsc, jec, npz, nx, ny - integer(8) :: rchk - - isc = Atm_block%isc - iec = Atm_block%iec - jsc = Atm_block%jsc - jec = Atm_block%jec - npz = Atm_block%npz - nx = (iec - isc + 1) - ny = (jec - jsc + 1) - - !--- register the restart fields - if (.not. allocated(phy_var2)) then - write(0,*)'phy_var2 must be allocated' - endif - if (.not. allocated(phy_var3)) then - write(0,*)'phy_var3 must be allocated' - endif - - !--- 2D variables - do num = 1,nvar2d - do nb = 1,Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - phy_var2(i,j,num) = GFS_Restart%data(nb,num)%var2p(ix) - enddo - enddo - enddo - - !--- 3D variables - do num = 1,nvar3d - do nb = 1,Atm_block%nblks - do k=1,npz - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - phy_var3(i,j,k,num) = GFS_Restart%data(nb,num)%var3p(ix,k) - enddo - enddo - enddo - enddo - - end subroutine fv_phy_restart_output - - subroutine fv_sfc_restart_output(Sfcprop, Atm_block, Model) - !--- interface variable definitions - implicit none - - type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) - type(block_control_type), intent(in) :: Atm_block - type(GFS_control_type), intent(in) :: Model - - integer :: i, j, k, nb, ix, lsoil, num, nt - integer :: isc, iec, jsc, jec, npz, nx, ny - integer, allocatable :: ii1(:), jj1(:) - real(kind_phys) :: ice - integer :: is, ie - - isc = Atm_block%isc - iec = Atm_block%iec - jsc = Atm_block%jsc - jec = Atm_block%jec - npz = Atm_block%npz - nx = (iec - isc + 1) - ny = (jec - jsc + 1) - -!$omp parallel do default(shared) private(i, j, nb, ix, nt, ii1, jj1, lsoil, k, ice) - block_loop: do nb = 1, Atm_block%nblks - allocate(ii1(Atm_block%blksz(nb))) - allocate(jj1(Atm_block%blksz(nb))) - ii1=Atm_block%index(nb)%ii - isc + 1 - jj1=Atm_block%index(nb)%jj - jsc + 1 - - nt=0 - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%slmsk) !--- slmsk - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfco) !--- tsfc (tsea in sfc file) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasd) !--- weasd (sheleg in sfc file) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tg3) !--- tg3 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorl) !--- zorl - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alvsf) !--- alvsf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alvwf) !--- alvwf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alnsf) !--- alnsf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alnwf) !--- alnwf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%facsf) !--- facsf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%facwf) !--- facwf - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%vfrac) !--- vfrac - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canopy)!--- canopy - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%f10m) !--- f10m - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%t2m) !--- t2m - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%q2m) !--- q2m - - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%vtype) !--- vtype - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stype) !--- stype - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%uustar)!--- uustar - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ffmm) !--- ffmm - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ffhh) !--- ffhh - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%hice) !--- hice - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fice) !--- fice - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tisfc) !--- tisfc - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tprcp) !--- tprcp - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%srflag)!--- srflag - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowd) !--- snowd (snwdph in the file) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%shdmin)!--- shdmin - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%shdmax)!--- shdmax - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%slope) !--- slope - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snoalb)!--- snoalb - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sncovr) !--- sncovr - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snodl) !--- snodl (snowd on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasdl) !--- weasdl (weasd on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfc) !--- tsfc composite - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsfcl) !--- tsfcl (temp on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorlw) !--- zorl (zorl on water) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorll) !--- zorll (zorl on land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorli) !--- zorli (zorl on ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirvis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirnir_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifvis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifnir_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%emis_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%emis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sncovr_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snodi) !--- snodi (snowd on ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%weasdi) !--- weasdi (weasd on ice) - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirvis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifvis_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdirnir_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%albdifnir_ice) -! sfc_var2(i,j,53) = Sfcprop(nb)%sfalb_ice(ix) - endif - if (Model%cplwav) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zorlwav) !--- zorlwav (zorl from wav) - endif - !--- NSSTM variables - if (Model%nstf_name(1) > 0) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tref) !--- nsstm tref - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%z_c) !--- nsstm z_c - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_0) !--- nsstm c_0 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%c_d) !--- nsstm c_d - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%w_0) !--- nsstm w_0 - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%w_d) !--- nsstm w_d - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xt) !--- nsstm xt - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xs) !--- nsstm xs - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xu) !--- nsstm xu - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xv) !--- nsstm xv - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xz) !--- nsstm xz - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zm) !--- nsstm zm - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xtts) !--- nsstm xtts - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xzts) !--- nsstm xzts - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%d_conv) !--- nsstm d_conv - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%ifd) !--- nsstm ifd - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%dt_cool)!--- nsstm dt_cool - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qrain) !--- nsstm qrain - - ! FIXME convert negative zero (-0.0) to zero (0.0) - do j=1,ny - do i=1,nx - if(sfc_var2(i,j,nt) == 0.0) sfc_var2(i,j,nt) = 0.0 - end do - end do - endif - - if (Model%lsm == Model%lsm_ruc) then - !--- Extra RUC variables - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wetness) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%clw_surf_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%clw_surf_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qwv_surf_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qwv_surf_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsnow_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tsnow_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowfallac_land) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowfallac_ice) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_lnd) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_lnd_bck) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sfalb_ice) - if (Model%rdlai) then - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xlaixy) - endif - else if (Model%lsm == Model%lsm_noahmp) then - !--- Extra Noah MP variables - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%snowxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tvxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tgxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canicexy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%canliqxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%eahxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%tahxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%cmxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%chxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fwetxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%sneqvoxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%alboldxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%qsnowxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wslakexy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%zwtxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%waxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%wtxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%lfmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rtmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stmassxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%woodxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%stblcpxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%fastcpxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xsaixy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%xlaixy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%taussxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%smcwtdxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%deeprechxy) - call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,sfc_var2,Sfcprop(nb)%rechxy) - endif - - do k = 1,Model%kice - do ix = 1, Atm_block%blksz(nb) - ice=Sfcprop(nb)%tiice(ix,k) - if(ice phy_var2(:,:,num) - call create_2d_field_and_add_to_bundle(temp_r2d, trim(phy_var2_names(num)), trim(outputfile), grid, bundle) - enddo - - do num = 1,nvar3d - temp_r3d => phy_var3(:,:,:,num) - call create_3d_field_and_add_to_bundle(temp_r3d, trim(phy_var3_names(num)), "zaxis_1", npz, trim(outputfile), grid, bundle) - enddo - - end subroutine fv_phy_restart_bundle_setup - - subroutine fv_sfc_restart_bundle_setup(bundle, grid, Model, rc) -! -!------------------------------------------------------------- -!*** set esmf bundle for sfc restart fields -!------------------------------------------------------------ -! - use esmf - - implicit none - - type(ESMF_FieldBundle),intent(inout) :: bundle - type(ESMF_Grid),intent(inout) :: grid - type(GFS_control_type), intent(in) :: Model - integer,intent(out) :: rc - -!*** local variables - integer i, j, k, n - character(128) :: sfcbdl_name - type(ESMF_Field) :: field - character(128) :: outputfile - real(kind_phys),dimension(:,:),pointer :: temp_r2d - real(kind_phys),dimension(:,:,:),pointer :: temp_r3d - - integer :: num - - if (.not. allocated(sfc_var2)) then - write(0,*)'ERROR sfc_var2, NOT allocated' - endif - if (.not. allocated(sfc_var3)) then - write(0,*)'ERROR sfc_var3 NOT allocated' - endif - - sfc_bundle = bundle - - call ESMF_FieldBundleGet(bundle, name=sfcbdl_name,rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - outputfile = trim(sfcbdl_name) - -!*** add esmf fields - - do num = 1,nvar2m - temp_r2d => sfc_var2(:,:,num) - call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc_name2(num)), outputfile, grid, bundle) - enddo - - if (Model%nstf_name(1) > 0) then - do num = nvar2m+1,nvar2m+nvar2o - temp_r2d => sfc_var2(:,:,num) - call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc_name2(num)), outputfile, grid, bundle) - enddo - endif - - if (Model%lsm == Model%lsm_ruc) then ! nvar2mp =0 - do num = nvar2m+nvar2o+1, nvar2m+nvar2o+nvar2r - temp_r2d => sfc_var2(:,:,num) - call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc_name2(num)), outputfile, grid, bundle) - enddo - else if (Model%lsm == Model%lsm_noahmp) then ! nvar2r =0 - do num = nvar2m+nvar2o+1,nvar2m+nvar2o+nvar2mp - temp_r2d => sfc_var2(:,:,num) - call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc_name2(num)), outputfile, grid, bundle) - enddo - endif - - temp_r3d => sfc_var3ice(:,:,:) - call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc_name3(0)), "zaxis_1", Model%kice, trim(outputfile), grid, bundle) - - if(Model%lsm == Model%lsm_ruc) then - do num = 1,nvar3 - temp_r3d => sfc_var3(:,:,:,num) - call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc_name3(num)), "zaxis_1", Model%kice, trim(outputfile), grid, bundle) - enddo - else - do num = 1,nvar3 - temp_r3d => sfc_var3(:,:,:,num) - call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc_name3(num)), "zaxis_2", Model%lsoil, trim(outputfile), grid, bundle) - enddo - endif - - if (Model%lsm == Model%lsm_noahmp) then - do num = nvar3+1,nvar3+3 - temp_r3d => sfc_var3sn(:,:,:,num) - call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc_name3(num)), "zaxis_3", 3, trim(outputfile), grid, bundle) - enddo - - temp_r3d => sfc_var3eq(:,:,:,7) - call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc_name3(7)), "zaxis_2", Model%lsoil, trim(outputfile), grid, bundle) - - temp_r3d => sfc_var3zn(:,:,:,8) - call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc_name3(8)), "zaxis_4", 7, trim(outputfile), grid, bundle) - endif ! lsm = lsm_noahmp - - end subroutine fv_sfc_restart_bundle_setup - - subroutine create_2d_field_and_add_to_bundle(temp_r2d, field_name, outputfile, grid, bundle) - - use esmf - - implicit none - - real(kind_phys), dimension(:,:), pointer, intent(in) :: temp_r2d - character(len=*), intent(in) :: field_name - character(len=*), intent(in) :: outputfile - type(ESMF_Grid), intent(in) :: grid - type(ESMF_FieldBundle), intent(inout) :: bundle - - type(ESMF_Field) :: field - - integer :: rc, i - - field = ESMF_FieldCreate(grid, temp_r2d, datacopyflag=ESMF_DATACOPY_REFERENCE, & - name=trim(field_name), indexFlag=ESMF_INDEX_DELOCAL, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU,line=__LINE__, file=__FILE__)) & - call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", name='output_file', value=trim(outputfile), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_FieldBundleAdd(bundle, (/field/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - end subroutine create_2d_field_and_add_to_bundle - - subroutine create_3d_field_and_add_to_bundle(temp_r3d, field_name, axis_name, num_levels, outputfile, grid, bundle) - - use esmf - - implicit none - - real(kind_phys), dimension(:,:,:), pointer, intent(in) :: temp_r3d - character(len=*), intent(in) :: field_name - character(len=*), intent(in) :: axis_name - integer, intent(in) :: num_levels - character(len=*), intent(in) :: outputfile - type(ESMF_Grid), intent(in) :: grid - type(ESMF_FieldBundle), intent(inout) :: bundle - - type(ESMF_Field) :: field - - integer :: rc, i - - field = ESMF_FieldCreate(grid, temp_r3d, datacopyflag=ESMF_DATACOPY_REFERENCE, & - name=trim(field_name), indexFlag=ESMF_INDEX_DELOCAL, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU,line=__LINE__, file=__FILE__)) & - call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", name='output_file', value=trim(outputfile), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - call add_zaxis_to_field(field, axis_name, num_levels) - - call ESMF_FieldBundleAdd(bundle, (/field/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) - - end subroutine create_3d_field_and_add_to_bundle - - subroutine add_zaxis_to_field(field, axis_name, num_levels) - - use esmf - - implicit none - - type(ESMF_Field), intent(inout) :: field - character(len=*), intent(in) :: axis_name - integer, intent(in) :: num_levels - - real(kind_phys), allocatable, dimension(:) :: buffer - integer :: rc, i - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & - name="ESMF:ungridded_dim_labels", valueList=(/trim(axis_name)/), rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - allocate( buffer(num_levels) ) - do i=1, num_levels - buffer(i)=i - end do - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3-dim", & - name=trim(axis_name), valueList=buffer, rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - deallocate(buffer) - - call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3-dim", & - name=trim(axis_name)//"cartesian_axis", value="Z", rc=rc) - if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return - - end subroutine add_zaxis_to_field - - pure subroutine fill_Sfcprop_names(Model,sfc_name2,sfc_name3,nvar_s2m,warm_start) - implicit none - type(GFS_control_type), intent(in) :: Model - integer, intent(in) :: nvar_s2m - character(len=32),intent(out) :: sfc_name2(:), sfc_name3(:) - logical, intent(in) :: warm_start - integer :: nt - - !--- names of the 2D variables to save - nt=0 - nt=nt+1 ; sfc_name2(nt) = 'slmsk' - nt=nt+1 ; sfc_name2(nt) = 'tsea' !tsfc - nt=nt+1 ; sfc_name2(nt) = 'sheleg' !weasd - nt=nt+1 ; sfc_name2(nt) = 'tg3' - nt=nt+1 ; sfc_name2(nt) = 'zorl' - nt=nt+1 ; sfc_name2(nt) = 'alvsf' - nt=nt+1 ; sfc_name2(nt) = 'alvwf' - nt=nt+1 ; sfc_name2(nt) = 'alnsf' - nt=nt+1 ; sfc_name2(nt) = 'alnwf' - nt=nt+1 ; sfc_name2(nt) = 'facsf' - nt=nt+1 ; sfc_name2(nt) = 'facwf' - nt=nt+1 ; sfc_name2(nt) = 'vfrac' - nt=nt+1 ; sfc_name2(nt) = 'canopy' - nt=nt+1 ; sfc_name2(nt) = 'f10m' - nt=nt+1 ; sfc_name2(nt) = 't2m' - nt=nt+1 ; sfc_name2(nt) = 'q2m' - nt=nt+1 ; sfc_name2(nt) = 'vtype' - nt=nt+1 ; sfc_name2(nt) = 'stype' - nt=nt+1 ; sfc_name2(nt) = 'uustar' - nt=nt+1 ; sfc_name2(nt) = 'ffmm' - nt=nt+1 ; sfc_name2(nt) = 'ffhh' - nt=nt+1 ; sfc_name2(nt) = 'hice' - nt=nt+1 ; sfc_name2(nt) = 'fice' - nt=nt+1 ; sfc_name2(nt) = 'tisfc' - nt=nt+1 ; sfc_name2(nt) = 'tprcp' - nt=nt+1 ; sfc_name2(nt) = 'srflag' - nt=nt+1 ; sfc_name2(nt) = 'snwdph' !snowd - nt=nt+1 ; sfc_name2(nt) = 'shdmin' - nt=nt+1 ; sfc_name2(nt) = 'shdmax' - nt=nt+1 ; sfc_name2(nt) = 'slope' - nt=nt+1 ; sfc_name2(nt) = 'snoalb' - !--- variables below here are optional - nt=nt+1 ; sfc_name2(nt) = 'sncovr' - nt=nt+1 ; sfc_name2(nt) = 'snodl' !snowd on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'weasdl'!weasd on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'tsfc' !tsfc composite - nt=nt+1 ; sfc_name2(nt) = 'tsfcl' !temp on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'zorlw' !zorl on water portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'zorll' !zorl on land portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'zorli' !zorl on ice portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'albdirvis_lnd' - nt=nt+1 ; sfc_name2(nt) = 'albdirnir_lnd' - nt=nt+1 ; sfc_name2(nt) = 'albdifvis_lnd' - nt=nt+1 ; sfc_name2(nt) = 'albdifnir_lnd' - nt=nt+1 ; sfc_name2(nt) = 'emis_lnd' - nt=nt+1 ; sfc_name2(nt) = 'emis_ice' - nt=nt+1 ; sfc_name2(nt) = 'sncovr_ice' - nt=nt+1 ; sfc_name2(nt) = 'snodi' ! snowd on ice portion of a cell - nt=nt+1 ; sfc_name2(nt) = 'weasdi'! weasd on ice portion of a cell - - if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then - nt=nt+1 ; sfc_name2(nt) = 'albdirvis_ice' - nt=nt+1 ; sfc_name2(nt) = 'albdifvis_ice' - nt=nt+1 ; sfc_name2(nt) = 'albdirnir_ice' - nt=nt+1 ; sfc_name2(nt) = 'albdifnir_ice' -! nt=nt+1 ; sfc_name2(nt) = 'sfalb_ice' - endif - - if(Model%cplwav) then - sfc_name2(nvar_s2m) = 'zorlwav' !zorl from wave component - endif - - nt = nvar_s2m ! next variable will be at nvar_s2m - - !--- NSSTM inputs only needed when (nstf_name(1) > 0) .and. (nstf_name(2)) == 0) - nt=nt+1 ; sfc_name2(nt) = 'tref' - nt=nt+1 ; sfc_name2(nt) = 'z_c' - nt=nt+1 ; sfc_name2(nt) = 'c_0' - nt=nt+1 ; sfc_name2(nt) = 'c_d' - nt=nt+1 ; sfc_name2(nt) = 'w_0' - nt=nt+1 ; sfc_name2(nt) = 'w_d' - nt=nt+1 ; sfc_name2(nt) = 'xt' - nt=nt+1 ; sfc_name2(nt) = 'xs' - nt=nt+1 ; sfc_name2(nt) = 'xu' - nt=nt+1 ; sfc_name2(nt) = 'xv' - nt=nt+1 ; sfc_name2(nt) = 'xz' - nt=nt+1 ; sfc_name2(nt) = 'zm' - nt=nt+1 ; sfc_name2(nt) = 'xtts' - nt=nt+1 ; sfc_name2(nt) = 'xzts' - nt=nt+1 ; sfc_name2(nt) = 'd_conv' - nt=nt+1 ; sfc_name2(nt) = 'ifd' - nt=nt+1 ; sfc_name2(nt) = 'dt_cool' - nt=nt+1 ; sfc_name2(nt) = 'qrain' -! -! Only needed when Noah MP LSM is used - 29 2D -! - if (Model%lsm == Model%lsm_noahmp) then - nt=nt+1 ; sfc_name2(nt) = 'snowxy' - nt=nt+1 ; sfc_name2(nt) = 'tvxy' - nt=nt+1 ; sfc_name2(nt) = 'tgxy' - nt=nt+1 ; sfc_name2(nt) = 'canicexy' - nt=nt+1 ; sfc_name2(nt) = 'canliqxy' - nt=nt+1 ; sfc_name2(nt) = 'eahxy' - nt=nt+1 ; sfc_name2(nt) = 'tahxy' - nt=nt+1 ; sfc_name2(nt) = 'cmxy' - nt=nt+1 ; sfc_name2(nt) = 'chxy' - nt=nt+1 ; sfc_name2(nt) = 'fwetxy' - nt=nt+1 ; sfc_name2(nt) = 'sneqvoxy' - nt=nt+1 ; sfc_name2(nt) = 'alboldxy' - nt=nt+1 ; sfc_name2(nt) = 'qsnowxy' - nt=nt+1 ; sfc_name2(nt) = 'wslakexy' - nt=nt+1 ; sfc_name2(nt) = 'zwtxy' - nt=nt+1 ; sfc_name2(nt) = 'waxy' - nt=nt+1 ; sfc_name2(nt) = 'wtxy' - nt=nt+1 ; sfc_name2(nt) = 'lfmassxy' - nt=nt+1 ; sfc_name2(nt) = 'rtmassxy' - nt=nt+1 ; sfc_name2(nt) = 'stmassxy' - nt=nt+1 ; sfc_name2(nt) = 'woodxy' - nt=nt+1 ; sfc_name2(nt) = 'stblcpxy' - nt=nt+1 ; sfc_name2(nt) = 'fastcpxy' - nt=nt+1 ; sfc_name2(nt) = 'xsaixy' - nt=nt+1 ; sfc_name2(nt) = 'xlaixy' - nt=nt+1 ; sfc_name2(nt) = 'taussxy' - nt=nt+1 ; sfc_name2(nt) = 'smcwtdxy' - nt=nt+1 ; sfc_name2(nt) = 'deeprechxy' - nt=nt+1 ; sfc_name2(nt) = 'rechxy' - else if (Model%lsm == Model%lsm_ruc .and. warm_start) then - nt=nt+1 ; sfc_name2(nt) = 'wetness' - nt=nt+1 ; sfc_name2(nt) = 'clw_surf_land' - nt=nt+1 ; sfc_name2(nt) = 'clw_surf_ice' - nt=nt+1 ; sfc_name2(nt) = 'qwv_surf_land' - nt=nt+1 ; sfc_name2(nt) = 'qwv_surf_ice' - nt=nt+1 ; sfc_name2(nt) = 'tsnow_land' - nt=nt+1 ; sfc_name2(nt) = 'tsnow_ice' - nt=nt+1 ; sfc_name2(nt) = 'snowfall_acc_land' - nt=nt+1 ; sfc_name2(nt) = 'snowfall_acc_ice' - nt=nt+1 ; sfc_name2(nt) = 'sfalb_lnd' - nt=nt+1 ; sfc_name2(nt) = 'sfalb_lnd_bck' - nt=nt+1 ; sfc_name2(nt) = 'sfalb_ice' - if (Model%rdlai) then - nt=nt+1 ; sfc_name2(nt) = 'lai' - endif - else if (Model%lsm == Model%lsm_ruc .and. Model%rdlai) then - nt=nt+1 ; sfc_name2(nt) = 'lai' - endif - end subroutine fill_sfcprop_names - - pure subroutine copy_from_GFS_Data_2d_phys2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(in) :: var_block(:) - real(kind=kind_phys), intent(out) :: var2d(:,:,:) - integer ix - - nt=nt+1 - do ix=1,size(var_block) - var2d(ii1(ix),jj1(ix),nt) = var_block(ix) - enddo - end subroutine copy_from_GFS_Data_2d_phys2phys - - pure subroutine copy_from_GFS_Data_3d_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(in) :: var_block(:,:) - real(kind=kind_phys), intent(out) :: var3d(:,:,:,:) - integer ix, k - - nt=nt+1 - do k=lbound(var_block,2),ubound(var_block,2) - do ix=1,size(var_block,1) - var3d(ii1(ix),jj1(ix),k,nt) = var_block(ix,k) - enddo - enddo - end subroutine copy_from_GFS_Data_3d_phys2phys - - pure subroutine copy_from_GFS_Data_2d_int2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc, var_block(:) - integer, intent(inout) :: nt - real(kind=kind_phys), intent(out) :: var2d(:,:,:) - integer ix - - nt=nt+1 - do ix=1,size(var_block) - var2d(ii1(ix),jj1(ix),nt) = var_block(ix) - enddo - end subroutine copy_from_GFS_Data_2d_int2phys - - pure subroutine copy_from_GFS_Data_2d_stack_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - ! For copying phy_f2d and phy_fctd - implicit none - integer, intent(in) :: ii1(:), jj1(:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(in) :: var_block(:,:) - real(kind=kind_phys), intent(out) :: var3d(:,:,:) - integer ix, k - - nt=nt+1 - do k=lbound(var_block,2),ubound(var_block,2) - do ix=1,size(var_block,1) - var3d(ii1(ix),jj1(ix),nt) = var_block(ix,k) - enddo - enddo - end subroutine copy_from_GFS_Data_2d_stack_phys2phys - - pure subroutine copy_from_GFS_Data_3d_int2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) - implicit none - integer, intent(in) :: ii1(:), jj1(:), var_block(:,:), isc, jsc - integer, intent(inout) :: nt - real(kind=kind_phys), intent(out) :: var3d(:,:,:,:) - integer ix, k - - nt=nt+1 - do k=lbound(var_block,2),ubound(var_block,2) - do ix=1,size(var_block,1) - var3d(ii1(ix),jj1(ix),k,nt) = real(var_block(ix,k),kind_phys) - enddo - enddo - end subroutine copy_from_GFS_Data_3d_int2phys - -end module FV3GFS_restart_io_mod diff --git a/io/clm_lake_io.F90 b/io/clm_lake_io.F90 deleted file mode 100644 index 6a47f3ab6..000000000 --- a/io/clm_lake_io.F90 +++ /dev/null @@ -1,432 +0,0 @@ -module clm_lake_io - use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, & - GFS_data_type, kind_phys - use GFS_restart, only: GFS_restart_type - use GFS_diagnostics, only: GFS_externaldiag_type - use block_control_mod, only: block_control_type - use fms2_io_mod, only: FmsNetcdfDomainFile_t, unlimited, & - open_file, close_file, & - register_axis, register_restart_field, & - register_variable_attribute, register_field, & - read_restart, write_restart, write_data, & - get_global_io_domain_indices, variable_exists - - implicit none - - type clm_lake_data_type - ! The clm_lake_data_type derived type is a class that stores - ! temporary arrays used to read or write CLM Lake model restart - ! and axis variables. It can safely be declared and unused, but - ! you should only call these routines if the CLM Lake Model was - ! (or will be) used by this execution of the FV3. It is the - ! responsibility of the caller to ensure the necessary data is in - ! Sfc_restart, Sfcprop, and Model. - - ! All 2D variables needed for a restart - real(kind_phys), pointer, private, dimension(:,:) :: & - T_snow=>null(), T_ice=>null(), & - lake_snl2d=>null(), lake_h2osno2d=>null(), lake_tsfc=>null(), clm_lakedepth=>null(), & - lake_savedtke12d=>null(), lake_sndpth2d=>null(), clm_lake_initialized=>null() - - ! All 3D variables needed for a restart - real(kind_phys), pointer, private, dimension(:,:,:) :: & - lake_z3d=>null(), lake_dz3d=>null(), lake_soil_watsat3d=>null(), & - lake_csol3d=>null(), lake_soil_tkmg3d=>null(), lake_soil_tkdry3d=>null(), & - lake_soil_tksatu3d=>null(), lake_snow_z3d=>null(), lake_snow_dz3d=>null(), & - lake_snow_zi3d=>null(), lake_h2osoi_vol3d=>null(), lake_h2osoi_liq3d=>null(), & - lake_h2osoi_ice3d=>null(), lake_t_soisno3d=>null(), lake_t_lake3d=>null(), & - lake_icefrac3d=>null(), lake_clay3d=>null(), lake_sand3d=>null() - - contains - - ! register_axes calls registers_axis on Sfc_restart for all required axes - procedure, public :: register_axes => clm_lake_register_axes - - ! allocate_data allocates all of the pointers in this object - procedure, public :: allocate_data => clm_lake_allocate_data - - ! register_fields calls register_field on Sfc_restart for all CLM Lake model restart variables - procedure, public :: register_fields => clm_lake_register_fields - - ! deallocate_data deallocates all pointers, allowing this object to be used repeatedly. - ! It is safe to call deallocate_data if no data has been allocated. - procedure, public :: deallocate_data => clm_lake_deallocate_data - - ! write_axes writes variables to Sfc_restart, with the name of - ! each axis, containing the appropriate information - procedure, public :: write_axes => clm_lake_write_axes - - ! copy_to_temporaries copies from Sfcprop to internal pointers (declared above) - procedure, public :: copy_to_temporaries => clm_lake_copy_to_temporaries - - ! copy_to_temporaries copies from internal pointers (declared above) to Sfcprop - procedure, public :: copy_from_temporaries => clm_lake_copy_from_temporaries - - ! A fortran 2003 compliant compiler will call clm_lake_final - ! automatically when an object of this type goes out of - ! scope. This will deallocate any arrays via a call to - ! deallocate_data. It is safe to call this routine if no data has - ! been allocated. - final :: clm_lake_final - end type clm_lake_data_type - - CONTAINS - subroutine clm_lake_allocate_data(data,Model) - ! Deallocate all data, and reallocate to the size specified in Model - implicit none - class(clm_lake_data_type) :: data - type(GFS_control_type), intent(in) :: Model - - integer :: nx, ny - call data%deallocate_data - - nx=Model%nx - ny=Model%ny - - allocate(data%T_snow(nx,ny)) - allocate(data%T_ice(nx,ny)) - allocate(data%lake_snl2d(nx,ny)) - allocate(data%lake_h2osno2d(nx,ny)) - allocate(data%lake_tsfc(nx,ny)) - allocate(data%lake_savedtke12d(nx,ny)) - allocate(data%lake_sndpth2d(nx,ny)) - allocate(data%clm_lakedepth(nx,ny)) - allocate(data%clm_lake_initialized(nx,ny)) - - allocate(data%lake_z3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_dz3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_soil_watsat3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_csol3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_soil_tkmg3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_soil_tkdry3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_soil_tksatu3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_snow_z3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) - allocate(data%lake_snow_dz3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) - allocate(data%lake_snow_zi3d(nx,ny,Model%nlevsnowsoil_clm_lake)) - allocate(data%lake_h2osoi_vol3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) - allocate(data%lake_h2osoi_liq3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) - allocate(data%lake_h2osoi_ice3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) - allocate(data%lake_t_soisno3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) - allocate(data%lake_t_lake3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_icefrac3d(nx,ny,Model%nlevlake_clm_lake)) - allocate(data%lake_clay3d(nx,ny,Model%nlevsoil_clm_lake)) - allocate(data%lake_sand3d(nx,ny,Model%nlevsoil_clm_lake)) - end subroutine clm_lake_allocate_data - - subroutine clm_lake_register_axes(data,Model,Sfc_restart) - ! Register all five axes needed by CLM Lake restart data - implicit none - class(clm_lake_data_type) :: data - type(GFS_control_type), intent(in) :: Model - type(FmsNetcdfDomainFile_t) :: Sfc_restart - call register_axis(Sfc_restart, 'levlake_clm_lake', dimension_length=Model%nlevlake_clm_lake) - - call register_axis(Sfc_restart, 'levsoil_clm_lake', dimension_length=Model%nlevsoil_clm_lake) - - call register_axis(Sfc_restart, 'levsnow_clm_lake', dimension_length=Model%nlevsnow_clm_lake) - - call register_axis(Sfc_restart, 'levsnowsoil_clm_lake', dimension_length=Model%nlevsnowsoil_clm_lake) - - call register_axis(Sfc_restart, 'levsnowsoil1_clm_lake', dimension_length=Model%nlevsnowsoil1_clm_lake) - end subroutine clm_lake_register_axes - - subroutine clm_lake_write_axes(data, Model, Sfc_restart) - ! Create variables with the name name as each clm_lake axis, and - ! fill the variable with the appropriate indices - implicit none - class(clm_lake_data_type) :: data - type(GFS_control_type), intent(in) :: Model - type(FmsNetcdfDomainFile_t) :: Sfc_restart - real(kind_phys) :: levlake_clm_lake(Model%nlevlake_clm_lake) - real(kind_phys) :: levsoil_clm_lake(Model%nlevsoil_clm_lake) - real(kind_phys) :: levsnow_clm_lake(Model%nlevsnow_clm_lake) - real(kind_phys) :: levsnowsoil_clm_lake(Model%nlevsnowsoil_clm_lake) - real(kind_phys) :: levsnowsoil1_clm_lake(Model%nlevsnowsoil1_clm_lake) - integer :: i - call register_field(Sfc_restart, 'levlake_clm_lake', 'double', (/'levlake_clm_lake'/)) - call register_variable_attribute(Sfc_restart, 'levlake_clm_lake', 'cartesian_axis' ,'Z', str_len=1) - - call register_field(Sfc_restart, 'levsoil_clm_lake', 'double', (/'levsoil_clm_lake'/)) - call register_variable_attribute(Sfc_restart, 'levsoil_clm_lake', 'cartesian_axis' ,'Z', str_len=1) - - call register_field(Sfc_restart, 'levsnow_clm_lake', 'double', (/'levsnow_clm_lake'/)) - call register_variable_attribute(Sfc_restart, 'levsnow_clm_lake', 'cartesian_axis' ,'Z', str_len=1) - - call register_field(Sfc_restart, 'levsnowsoil_clm_lake', 'double', (/'levsnowsoil_clm_lake'/)) - call register_variable_attribute(Sfc_restart, 'levsnowsoil_clm_lake', 'cartesian_axis' ,'Z', str_len=1) - - call register_field(Sfc_restart, 'levsnowsoil1_clm_lake', 'double', (/'levsnowsoil1_clm_lake'/)) - call register_variable_attribute(Sfc_restart, 'levsnowsoil1_clm_lake', 'cartesian_axis' ,'Z', str_len=1) - - do i=1,Model%nlevlake_clm_lake - levlake_clm_lake(i) = i - enddo - do i=1,Model%nlevsoil_clm_lake - levsoil_clm_lake(i) = i - enddo - do i=1,Model%nlevsnow_clm_lake - levsnow_clm_lake(i) = i - enddo - do i=-Model%nlevsnow_clm_lake,Model%nlevsoil_clm_lake - levsnowsoil_clm_lake(i+Model%nlevsnow_clm_lake+1) = i - enddo - do i=-Model%nlevsnow_clm_lake+1,Model%nlevsoil_clm_lake - levsnowsoil1_clm_lake(i+Model%nlevsnow_clm_lake) = i - enddo - - call write_data(Sfc_restart, 'levlake_clm_lake', levlake_clm_lake) - call write_data(Sfc_restart, 'levsoil_clm_lake', levsoil_clm_lake) - call write_data(Sfc_restart, 'levsnow_clm_lake', levsnow_clm_lake) - call write_data(Sfc_restart, 'levsnowsoil_clm_lake', levsnowsoil_clm_lake) - call write_data(Sfc_restart, 'levsnowsoil1_clm_lake', levsnowsoil1_clm_lake) - end subroutine clm_lake_write_axes - - subroutine clm_lake_copy_to_temporaries(data, Model, Sfcprop, Atm_block) - ! Copies from Sfcprop variables to the corresponding data temporary variables. - ! Terrible things will happen if you don't call data%allocate_data first. - implicit none - class(clm_lake_data_type) :: data - type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) - type(GFS_control_type), intent(in) :: Model - type(block_control_type), intent(in) :: Atm_block - - integer :: nb, ix, isc, jsc, i, j - isc = Model%isc - jsc = Model%jsc - - ! Copy data to temporary arrays - -!$omp parallel do default(shared) private(i, j, nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - - data%T_snow(i,j) = Sfcprop(nb)%T_snow(ix) - data%T_ice(i,j) = Sfcprop(nb)%T_ice(ix) - data%lake_snl2d(i,j) = Sfcprop(nb)%lake_snl2d(ix) - data%lake_h2osno2d(i,j) = Sfcprop(nb)%lake_h2osno2d(ix) - data%lake_tsfc(i,j) = Sfcprop(nb)%lake_tsfc(ix) - data%lake_savedtke12d(i,j) = Sfcprop(nb)%lake_savedtke12d(ix) - data%lake_sndpth2d(i,j) = Sfcprop(nb)%lake_sndpth2d(ix) - data%clm_lakedepth(i,j) = Sfcprop(nb)%clm_lakedepth(ix) - data%clm_lake_initialized(i,j) = Sfcprop(nb)%clm_lake_initialized(ix) - - data%lake_z3d(i,j,:) = Sfcprop(nb)%lake_z3d(ix,:) - data%lake_dz3d(i,j,:) = Sfcprop(nb)%lake_dz3d(ix,:) - data%lake_soil_watsat3d(i,j,:) = Sfcprop(nb)%lake_soil_watsat3d(ix,:) - data%lake_csol3d(i,j,:) = Sfcprop(nb)%lake_csol3d(ix,:) - data%lake_soil_tkmg3d(i,j,:) = Sfcprop(nb)%lake_soil_tkmg3d(ix,:) - data%lake_soil_tkdry3d(i,j,:) = Sfcprop(nb)%lake_soil_tkdry3d(ix,:) - data%lake_soil_tksatu3d(i,j,:) = Sfcprop(nb)%lake_soil_tksatu3d(ix,:) - data%lake_snow_z3d(i,j,:) = Sfcprop(nb)%lake_snow_z3d(ix,:) - data%lake_snow_dz3d(i,j,:) = Sfcprop(nb)%lake_snow_dz3d(ix,:) - data%lake_snow_zi3d(i,j,:) = Sfcprop(nb)%lake_snow_zi3d(ix,:) - data%lake_h2osoi_vol3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_vol3d(ix,:) - data%lake_h2osoi_liq3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_liq3d(ix,:) - data%lake_h2osoi_ice3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_ice3d(ix,:) - data%lake_t_soisno3d(i,j,:) = Sfcprop(nb)%lake_t_soisno3d(ix,:) - data%lake_t_lake3d(i,j,:) = Sfcprop(nb)%lake_t_lake3d(ix,:) - data%lake_icefrac3d(i,j,:) = Sfcprop(nb)%lake_icefrac3d(ix,:) - data%lake_clay3d(i,j,:) = Sfcprop(nb)%lake_clay3d(ix,:) - data%lake_sand3d(i,j,:) = Sfcprop(nb)%lake_sand3d(ix,:) - enddo - enddo - end subroutine clm_lake_copy_to_temporaries - - subroutine clm_lake_copy_from_temporaries(data, Model, Sfcprop, Atm_block) - ! Copies from data temporary variables to the corresponding Sfcprop variables. - ! Terrible things will happen if you don't call data%allocate_data first. - implicit none - class(clm_lake_data_type) :: data - type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) - type(GFS_control_type), intent(in) :: Model - type(block_control_type), intent(in) :: Atm_block - - integer :: nb, ix, isc, jsc, i, j - isc = Model%isc - jsc = Model%jsc - - ! Copy data to temporary arrays - -!$omp parallel do default(shared) private(i, j, nb, ix) - do nb = 1, Atm_block%nblks - do ix = 1, Atm_block%blksz(nb) - i = Atm_block%index(nb)%ii(ix) - isc + 1 - j = Atm_block%index(nb)%jj(ix) - jsc + 1 - - Sfcprop(nb)%T_snow(ix) = data%T_snow(i,j) - Sfcprop(nb)%T_ice(ix) = data%T_ice(i,j) - Sfcprop(nb)%lake_snl2d(ix) = data%lake_snl2d(i,j) - Sfcprop(nb)%lake_h2osno2d(ix) = data%lake_h2osno2d(i,j) - Sfcprop(nb)%lake_tsfc(ix) = data%lake_tsfc(i,j) - Sfcprop(nb)%lake_savedtke12d(ix) = data%lake_savedtke12d(i,j) - Sfcprop(nb)%lake_sndpth2d(ix) = data%lake_sndpth2d(i,j) - Sfcprop(nb)%clm_lakedepth(ix) = data%clm_lakedepth(i,j) - Sfcprop(nb)%clm_lake_initialized(ix) = data%clm_lake_initialized(i,j) - - Sfcprop(nb)%lake_z3d(ix,:) = data%lake_z3d(i,j,:) - Sfcprop(nb)%lake_dz3d(ix,:) = data%lake_dz3d(i,j,:) - Sfcprop(nb)%lake_soil_watsat3d(ix,:) = data%lake_soil_watsat3d(i,j,:) - Sfcprop(nb)%lake_csol3d(ix,:) = data%lake_csol3d(i,j,:) - Sfcprop(nb)%lake_soil_tkmg3d(ix,:) = data%lake_soil_tkmg3d(i,j,:) - Sfcprop(nb)%lake_soil_tkdry3d(ix,:) = data%lake_soil_tkdry3d(i,j,:) - Sfcprop(nb)%lake_soil_tksatu3d(ix,:) = data%lake_soil_tksatu3d(i,j,:) - Sfcprop(nb)%lake_snow_z3d(ix,:) = data%lake_snow_z3d(i,j,:) - Sfcprop(nb)%lake_snow_dz3d(ix,:) = data%lake_snow_dz3d(i,j,:) - Sfcprop(nb)%lake_snow_zi3d(ix,:) = data%lake_snow_zi3d(i,j,:) - Sfcprop(nb)%lake_h2osoi_vol3d(ix,:) = data%lake_h2osoi_vol3d(i,j,:) - Sfcprop(nb)%lake_h2osoi_liq3d(ix,:) = data%lake_h2osoi_liq3d(i,j,:) - Sfcprop(nb)%lake_h2osoi_ice3d(ix,:) = data%lake_h2osoi_ice3d(i,j,:) - Sfcprop(nb)%lake_t_soisno3d(ix,:) = data%lake_t_soisno3d(i,j,:) - Sfcprop(nb)%lake_t_lake3d(ix,:) = data%lake_t_lake3d(i,j,:) - Sfcprop(nb)%lake_icefrac3d(ix,:) = data%lake_icefrac3d(i,j,:) - Sfcprop(nb)%lake_clay3d(ix,:) = data%lake_clay3d(i,j,:) - Sfcprop(nb)%lake_sand3d(ix,:) = data%lake_sand3d(i,j,:) - enddo - enddo - end subroutine clm_lake_copy_from_temporaries - - subroutine clm_lake_register_fields(data, Sfc_restart) - ! Registers all restart fields needed by the CLM Lake Model. - ! Terrible things will happen if you don't call data%allocate_data - ! and data%register_axes first. - implicit none - class(clm_lake_data_type) :: data - type(FmsNetcdfDomainFile_t) :: Sfc_restart - - ! Register 2D fields - call register_restart_field(Sfc_restart, 'T_snow', data%T_snow, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'T_ice', data%T_ice, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'lake_snl2d', data%lake_snl2d, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'lake_h2osno2d', data%lake_h2osno2d, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'lake_tsfc', data%lake_tsfc, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'lake_savedtke12d', data%lake_savedtke12d, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'lake_sndpth2d', data%lake_sndpth2d, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'clm_lakedepth', data%clm_lakedepth, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'clm_lake_initialized', data%clm_lake_initialized, & - dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) - - ! Register 3D fields - call register_restart_field(Sfc_restart, 'lake_z3d', data%lake_z3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart, 'lake_dz3d', data%lake_dz3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_soil_watsat3d', data%lake_soil_watsat3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_csol3d', data%lake_csol3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_soil_tkmg3d', data%lake_soil_tkmg3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_soil_tkdry3d', data%lake_soil_tkdry3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_soil_tksatu3d', data%lake_soil_tksatu3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_snow_z3d', data%lake_snow_z3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_snow_dz3d', data%lake_snow_dz3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_snow_zi3d', data%lake_snow_zi3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsnowsoil_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_h2osoi_vol3d', data%lake_h2osoi_vol3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_h2osoi_liq3d', data%lake_h2osoi_liq3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_h2osoi_ice3d', data%lake_h2osoi_ice3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_t_soisno3d', data%lake_t_soisno3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_t_lake3d', data%lake_t_lake3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_icefrac3d', data%lake_icefrac3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levlake_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_clay3d', data%lake_clay3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsoil_clm_lake ', 'Time '/), is_optional=.true.) - call register_restart_field(Sfc_restart,'lake_sand3d', data%lake_sand3d, & - dimensions=(/'xaxis_1 ', 'yaxis_1 ', & - 'levsoil_clm_lake ', 'Time '/), is_optional=.true.) - end subroutine clm_lake_register_fields - - subroutine clm_lake_final(data) - ! Final routine for clm_lake_data_type, called automatically when - ! an object of that type goes out of scope. This is simply a - ! wrapper around data%deallocate_data(). - implicit none - type(clm_lake_data_type) :: data - call clm_lake_deallocate_data(data) - end subroutine clm_lake_final - - subroutine clm_lake_deallocate_data(data) - ! Deallocates all data used, and nullifies the pointers. The data - ! object can safely be used again after this call. This is also - ! the implementation of the clm_lake_data_type final routine. - implicit none - class(clm_lake_data_type) :: data - - ! Deallocate and nullify any associated pointers - - ! This #define reduces code length by a lot -#define IF_ASSOC_DEALLOC_NULL(var) \ - if(associated(data%var)) then ; \ - deallocate(data%var) ; \ - nullify(data%var) ; \ - endif - - IF_ASSOC_DEALLOC_NULL(T_snow) - IF_ASSOC_DEALLOC_NULL(T_ice) - IF_ASSOC_DEALLOC_NULL(lake_snl2d) - IF_ASSOC_DEALLOC_NULL(lake_h2osno2d) - IF_ASSOC_DEALLOC_NULL(lake_tsfc) - IF_ASSOC_DEALLOC_NULL(lake_savedtke12d) - IF_ASSOC_DEALLOC_NULL(lake_sndpth2d) - IF_ASSOC_DEALLOC_NULL(clm_lakedepth) - IF_ASSOC_DEALLOC_NULL(clm_lake_initialized) - - IF_ASSOC_DEALLOC_NULL(lake_z3d) - IF_ASSOC_DEALLOC_NULL(lake_dz3d) - IF_ASSOC_DEALLOC_NULL(lake_soil_watsat3d) - IF_ASSOC_DEALLOC_NULL(lake_csol3d) - IF_ASSOC_DEALLOC_NULL(lake_soil_tkmg3d) - IF_ASSOC_DEALLOC_NULL(lake_soil_tkdry3d) - IF_ASSOC_DEALLOC_NULL(lake_soil_tksatu3d) - IF_ASSOC_DEALLOC_NULL(lake_snow_z3d) - IF_ASSOC_DEALLOC_NULL(lake_snow_dz3d) - IF_ASSOC_DEALLOC_NULL(lake_snow_zi3d) - IF_ASSOC_DEALLOC_NULL(lake_h2osoi_vol3d) - IF_ASSOC_DEALLOC_NULL(lake_h2osoi_liq3d) - IF_ASSOC_DEALLOC_NULL(lake_h2osoi_ice3d) - IF_ASSOC_DEALLOC_NULL(lake_t_soisno3d) - IF_ASSOC_DEALLOC_NULL(lake_t_lake3d) - IF_ASSOC_DEALLOC_NULL(lake_icefrac3d) - IF_ASSOC_DEALLOC_NULL(lake_clay3d) - IF_ASSOC_DEALLOC_NULL(lake_sand3d) - -#undef IF_ASSOC_DEALLOC_NULL - end subroutine clm_lake_deallocate_data - -end module clm_lake_io diff --git a/io/fv3atm_clm_lake_io.F90 b/io/fv3atm_clm_lake_io.F90 new file mode 100644 index 000000000..5c61a26be --- /dev/null +++ b/io/fv3atm_clm_lake_io.F90 @@ -0,0 +1,521 @@ +!> \file fv3atm_clm_lake_io.F90 +!! This code reads and writes restart files for the CLM Lake Model. The source code of +!! that model can be found in CCPP. Only the fv3atm_restart_io.F90 should ever access +!! these routines. +!! +!! The CLM Lake Model has its own restart code due to its five alternative vertical +!! levels, which don't match the five found in the other surface fields. For the sake +!! of code simplicity, a dedicated file was a better implementation. + +module fv3atm_clm_lake_io + use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, kind_phys + use block_control_mod, only: block_control_type + use fms2_io_mod, only: FmsNetcdfDomainFile_t, register_axis, & + register_restart_field, write_data, & + register_variable_attribute, register_field + use fv3atm_common_io, only: create_2d_field_and_add_to_bundle, & + create_3d_field_and_add_to_bundle + + implicit none + + private + public :: clm_lake_data_type, clm_lake_register_axes, clm_lake_allocate_data, & + clm_lake_register_fields, clm_lake_deallocate_data, clm_lake_write_axes, & + clm_lake_copy_from_grid, clm_lake_copy_to_grid, clm_lake_bundle_fields, & + clm_lake_final + + !>\defgroup CLM Lake Model restart public interface + !> @{ + + !>@ The clm_lake_data_type derived type is a class that stores + !! temporary arrays used to read or write CLM Lake model restart + !! and axis variables. It can safely be declared and unused, but + !! you should only call these routines if the CLM Lake Model was + !! (or will be) used by this execution of the FV3. It is the + !! responsibility of the caller to ensure the necessary data is in + !! Sfc_restart, Sfcprop, and Model. + type clm_lake_data_type + ! All 2D variables needed for a restart + real(kind_phys), pointer, private, dimension(:,:) :: & + T_snow=>null(), T_ice=>null(), & + lake_snl2d=>null(), lake_h2osno2d=>null(), lake_tsfc=>null(), clm_lakedepth=>null(), & + lake_savedtke12d=>null(), lake_sndpth2d=>null(), clm_lake_initialized=>null() + + ! All 3D variables needed for a restart + real(kind_phys), pointer, private, dimension(:,:,:) :: & + lake_z3d=>null(), lake_dz3d=>null(), lake_soil_watsat3d=>null(), & + lake_csol3d=>null(), lake_soil_tkmg3d=>null(), lake_soil_tkdry3d=>null(), & + lake_soil_tksatu3d=>null(), lake_snow_z3d=>null(), lake_snow_dz3d=>null(), & + lake_snow_zi3d=>null(), lake_h2osoi_vol3d=>null(), lake_h2osoi_liq3d=>null(), & + lake_h2osoi_ice3d=>null(), lake_t_soisno3d=>null(), lake_t_lake3d=>null(), & + lake_icefrac3d=>null(), lake_clay3d=>null(), lake_sand3d=>null() + + ! Axis indices in 1-based array, containing non-1-based indices + real(kind_phys), pointer, private, dimension(:) :: & + levlake_clm_lake, levsoil_clm_lake, levsnowsoil_clm_lake, & + levsnowsoil1_clm_lake + contains + + ! register_axes calls registers_axis on Sfc_restart for all required axes + procedure, public :: register_axes => clm_lake_register_axes + + ! allocate_data allocates all of the pointers in this object + procedure, public :: allocate_data => clm_lake_allocate_data + + ! register_fields calls register_field on Sfc_restart for all CLM Lake model restart variables + procedure, public :: register_fields => clm_lake_register_fields + + ! deallocate_data deallocates all pointers, allowing this object to be used repeatedly. + ! It is safe to call deallocate_data if no data has been allocated. + procedure, public :: deallocate_data => clm_lake_deallocate_data + + ! write_axes writes variables to Sfc_restart, with the name of + ! each axis, containing the appropriate information + procedure, public :: write_axes => clm_lake_write_axes + + ! copy_from_grid copies from Sfcprop to internal pointers (declared above) + procedure, public :: copy_from_grid => clm_lake_copy_from_grid + + ! copy_from_grid copies from internal pointers (declared above) to Sfcprop + procedure, public :: copy_to_grid => clm_lake_copy_to_grid + + ! send field bundles in restart quilt server + procedure, public :: bundle_fields => clm_lake_bundle_fields + + ! A fortran 2003 compliant compiler will call clm_lake_final + ! automatically when an object of this type goes out of + ! scope. This will deallocate any arrays via a call to + ! deallocate_data. It is safe to call this routine if no data has + ! been allocated. + final :: clm_lake_final + end type clm_lake_data_type + +CONTAINS + + !>@ This subroutine is clm_lake%alocate_data. It deallocates all + !! data, and reallocate to the size specified in Model + subroutine clm_lake_allocate_data(clm_lake,Model) + implicit none + class(clm_lake_data_type) :: clm_lake + type(GFS_control_type), intent(in) :: Model + + integer :: nx, ny, i + call clm_lake%deallocate_data + + nx=Model%nx + ny=Model%ny + + allocate(clm_lake%T_snow(nx,ny)) + allocate(clm_lake%T_ice(nx,ny)) + allocate(clm_lake%lake_snl2d(nx,ny)) + allocate(clm_lake%lake_h2osno2d(nx,ny)) + allocate(clm_lake%lake_tsfc(nx,ny)) + allocate(clm_lake%lake_savedtke12d(nx,ny)) + allocate(clm_lake%lake_sndpth2d(nx,ny)) + allocate(clm_lake%clm_lakedepth(nx,ny)) + allocate(clm_lake%clm_lake_initialized(nx,ny)) + + allocate(clm_lake%lake_z3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_dz3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_soil_watsat3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_csol3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_soil_tkmg3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_soil_tkdry3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_soil_tksatu3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_snow_z3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(clm_lake%lake_snow_dz3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(clm_lake%lake_snow_zi3d(nx,ny,Model%nlevsnowsoil_clm_lake)) + allocate(clm_lake%lake_h2osoi_vol3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(clm_lake%lake_h2osoi_liq3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(clm_lake%lake_h2osoi_ice3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(clm_lake%lake_t_soisno3d(nx,ny,Model%nlevsnowsoil1_clm_lake)) + allocate(clm_lake%lake_t_lake3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_icefrac3d(nx,ny,Model%nlevlake_clm_lake)) + allocate(clm_lake%lake_clay3d(nx,ny,Model%nlevsoil_clm_lake)) + allocate(clm_lake%lake_sand3d(nx,ny,Model%nlevsoil_clm_lake)) + + allocate(clm_lake%levlake_clm_lake(Model%nlevlake_clm_lake)) + allocate(clm_lake%levsoil_clm_lake(Model%nlevsoil_clm_lake)) + allocate(clm_lake%levsnowsoil_clm_lake(Model%nlevsnowsoil_clm_lake)) + allocate(clm_lake%levsnowsoil1_clm_lake(Model%nlevsnowsoil1_clm_lake)) + + do i=1,Model%nlevlake_clm_lake + clm_lake%levlake_clm_lake(i) = i + enddo + do i=1,Model%nlevsoil_clm_lake + clm_lake%levsoil_clm_lake(i) = i + enddo + do i=-Model%nlevsnow_clm_lake,Model%nlevsoil_clm_lake + clm_lake%levsnowsoil_clm_lake(i+Model%nlevsnow_clm_lake+1) = i + enddo + do i=-Model%nlevsnow_clm_lake+1,Model%nlevsoil_clm_lake + clm_lake%levsnowsoil1_clm_lake(i+Model%nlevsnow_clm_lake) = i + enddo + end subroutine clm_lake_allocate_data + + !>@ This is clm_lake%register_axes. It registers all five axes needed + !! by CLM Lake restart data. + subroutine clm_lake_register_axes(clm_lake,Model,Sfc_restart) + implicit none + class(clm_lake_data_type) :: clm_lake + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + + call register_axis(Sfc_restart, 'levlake_clm_lake', dimension_length=Model%nlevlake_clm_lake) + call register_axis(Sfc_restart, 'levsoil_clm_lake', dimension_length=Model%nlevsoil_clm_lake) + call register_axis(Sfc_restart, 'levsnowsoil_clm_lake', dimension_length=Model%nlevsnowsoil_clm_lake) + call register_axis(Sfc_restart, 'levsnowsoil1_clm_lake', dimension_length=Model%nlevsnowsoil1_clm_lake) + end subroutine clm_lake_register_axes + + !>@ This is clm_lake%write_axes. It creates variables with the name + !! name as each clm_lake axis, and fills the variable with the + !! appropriate indices + subroutine clm_lake_write_axes(clm_lake, Model, Sfc_restart) + implicit none + class(clm_lake_data_type) :: clm_lake + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + integer :: i + call register_field(Sfc_restart, 'levlake_clm_lake', 'double', (/'levlake_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levlake_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call register_field(Sfc_restart, 'levsoil_clm_lake', 'double', (/'levsoil_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levsoil_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call register_field(Sfc_restart, 'levsnowsoil_clm_lake', 'double', (/'levsnowsoil_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levsnowsoil_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call register_field(Sfc_restart, 'levsnowsoil1_clm_lake', 'double', (/'levsnowsoil1_clm_lake'/)) + call register_variable_attribute(Sfc_restart, 'levsnowsoil1_clm_lake', 'cartesian_axis' ,'Z', str_len=1) + + call write_data(Sfc_restart, 'levlake_clm_lake', clm_lake%levlake_clm_lake) + call write_data(Sfc_restart, 'levsoil_clm_lake', clm_lake%levsoil_clm_lake) + call write_data(Sfc_restart, 'levsnowsoil_clm_lake', clm_lake%levsnowsoil_clm_lake) + call write_data(Sfc_restart, 'levsnowsoil1_clm_lake', clm_lake%levsnowsoil1_clm_lake) + end subroutine clm_lake_write_axes + + !>@ This is clm_lake%copy_from_grid. It copies from Sfcprop + !! variables to the corresponding data temporary variables. + !! Terrible things will happen if you don't call + !! clm_lake%allocate_data first. + subroutine clm_lake_copy_from_grid(clm_lake, Model, Atm_block, Sfcprop) + implicit none + class(clm_lake_data_type) :: clm_lake + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_control_type), intent(in) :: Model + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, isc, jsc, i, j + isc = Model%isc + jsc = Model%jsc + + ! Copy data to temporary arrays + + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + + clm_lake%T_snow(i,j) = Sfcprop(nb)%T_snow(ix) + clm_lake%T_ice(i,j) = Sfcprop(nb)%T_ice(ix) + clm_lake%lake_snl2d(i,j) = Sfcprop(nb)%lake_snl2d(ix) + clm_lake%lake_h2osno2d(i,j) = Sfcprop(nb)%lake_h2osno2d(ix) + clm_lake%lake_tsfc(i,j) = Sfcprop(nb)%lake_tsfc(ix) + clm_lake%lake_savedtke12d(i,j) = Sfcprop(nb)%lake_savedtke12d(ix) + clm_lake%lake_sndpth2d(i,j) = Sfcprop(nb)%lake_sndpth2d(ix) + clm_lake%clm_lakedepth(i,j) = Sfcprop(nb)%clm_lakedepth(ix) + clm_lake%clm_lake_initialized(i,j) = Sfcprop(nb)%clm_lake_initialized(ix) + + clm_lake%lake_z3d(i,j,:) = Sfcprop(nb)%lake_z3d(ix,:) + clm_lake%lake_dz3d(i,j,:) = Sfcprop(nb)%lake_dz3d(ix,:) + clm_lake%lake_soil_watsat3d(i,j,:) = Sfcprop(nb)%lake_soil_watsat3d(ix,:) + clm_lake%lake_csol3d(i,j,:) = Sfcprop(nb)%lake_csol3d(ix,:) + clm_lake%lake_soil_tkmg3d(i,j,:) = Sfcprop(nb)%lake_soil_tkmg3d(ix,:) + clm_lake%lake_soil_tkdry3d(i,j,:) = Sfcprop(nb)%lake_soil_tkdry3d(ix,:) + clm_lake%lake_soil_tksatu3d(i,j,:) = Sfcprop(nb)%lake_soil_tksatu3d(ix,:) + clm_lake%lake_snow_z3d(i,j,:) = Sfcprop(nb)%lake_snow_z3d(ix,:) + clm_lake%lake_snow_dz3d(i,j,:) = Sfcprop(nb)%lake_snow_dz3d(ix,:) + clm_lake%lake_snow_zi3d(i,j,:) = Sfcprop(nb)%lake_snow_zi3d(ix,:) + clm_lake%lake_h2osoi_vol3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_vol3d(ix,:) + clm_lake%lake_h2osoi_liq3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_liq3d(ix,:) + clm_lake%lake_h2osoi_ice3d(i,j,:) = Sfcprop(nb)%lake_h2osoi_ice3d(ix,:) + clm_lake%lake_t_soisno3d(i,j,:) = Sfcprop(nb)%lake_t_soisno3d(ix,:) + clm_lake%lake_t_lake3d(i,j,:) = Sfcprop(nb)%lake_t_lake3d(ix,:) + clm_lake%lake_icefrac3d(i,j,:) = Sfcprop(nb)%lake_icefrac3d(ix,:) + clm_lake%lake_clay3d(i,j,:) = Sfcprop(nb)%lake_clay3d(ix,:) + clm_lake%lake_sand3d(i,j,:) = Sfcprop(nb)%lake_sand3d(ix,:) + enddo + enddo + end subroutine clm_lake_copy_from_grid + + !>@ This is clm_lake%copy_to_grid. It copies from data temporary + !! variables to the corresponding Sfcprop variables. Terrible + !! things will happen if you don't call data%allocate_data first. + subroutine clm_lake_copy_to_grid(clm_lake, Model, Atm_block, Sfcprop) + implicit none + class(clm_lake_data_type) :: clm_lake + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_control_type), intent(in) :: Model + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, isc, jsc, i, j + isc = Model%isc + jsc = Model%jsc + + ! Copy data to temporary arrays + + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + + Sfcprop(nb)%T_snow(ix) = clm_lake%T_snow(i,j) + Sfcprop(nb)%T_ice(ix) = clm_lake%T_ice(i,j) + Sfcprop(nb)%lake_snl2d(ix) = clm_lake%lake_snl2d(i,j) + Sfcprop(nb)%lake_h2osno2d(ix) = clm_lake%lake_h2osno2d(i,j) + Sfcprop(nb)%lake_tsfc(ix) = clm_lake%lake_tsfc(i,j) + Sfcprop(nb)%lake_savedtke12d(ix) = clm_lake%lake_savedtke12d(i,j) + Sfcprop(nb)%lake_sndpth2d(ix) = clm_lake%lake_sndpth2d(i,j) + Sfcprop(nb)%clm_lakedepth(ix) = clm_lake%clm_lakedepth(i,j) + Sfcprop(nb)%clm_lake_initialized(ix) = clm_lake%clm_lake_initialized(i,j) + + Sfcprop(nb)%lake_z3d(ix,:) = clm_lake%lake_z3d(i,j,:) + Sfcprop(nb)%lake_dz3d(ix,:) = clm_lake%lake_dz3d(i,j,:) + Sfcprop(nb)%lake_soil_watsat3d(ix,:) = clm_lake%lake_soil_watsat3d(i,j,:) + Sfcprop(nb)%lake_csol3d(ix,:) = clm_lake%lake_csol3d(i,j,:) + Sfcprop(nb)%lake_soil_tkmg3d(ix,:) = clm_lake%lake_soil_tkmg3d(i,j,:) + Sfcprop(nb)%lake_soil_tkdry3d(ix,:) = clm_lake%lake_soil_tkdry3d(i,j,:) + Sfcprop(nb)%lake_soil_tksatu3d(ix,:) = clm_lake%lake_soil_tksatu3d(i,j,:) + Sfcprop(nb)%lake_snow_z3d(ix,:) = clm_lake%lake_snow_z3d(i,j,:) + Sfcprop(nb)%lake_snow_dz3d(ix,:) = clm_lake%lake_snow_dz3d(i,j,:) + Sfcprop(nb)%lake_snow_zi3d(ix,:) = clm_lake%lake_snow_zi3d(i,j,:) + Sfcprop(nb)%lake_h2osoi_vol3d(ix,:) = clm_lake%lake_h2osoi_vol3d(i,j,:) + Sfcprop(nb)%lake_h2osoi_liq3d(ix,:) = clm_lake%lake_h2osoi_liq3d(i,j,:) + Sfcprop(nb)%lake_h2osoi_ice3d(ix,:) = clm_lake%lake_h2osoi_ice3d(i,j,:) + Sfcprop(nb)%lake_t_soisno3d(ix,:) = clm_lake%lake_t_soisno3d(i,j,:) + Sfcprop(nb)%lake_t_lake3d(ix,:) = clm_lake%lake_t_lake3d(i,j,:) + Sfcprop(nb)%lake_icefrac3d(ix,:) = clm_lake%lake_icefrac3d(i,j,:) + Sfcprop(nb)%lake_clay3d(ix,:) = clm_lake%lake_clay3d(i,j,:) + Sfcprop(nb)%lake_sand3d(ix,:) = clm_lake%lake_sand3d(i,j,:) + enddo + enddo + end subroutine clm_lake_copy_to_grid + + !>@ This is clm_lake%register_fields, and it is only used in the + !! non-quilt restart. It registers all restart fields needed by the + !! CLM Lake Model. Terrible things will happen if you don't call + !! clm_lake%allocate_data and clm_lake%register_axes first. + subroutine clm_lake_register_fields(clm_lake, Sfc_restart) + implicit none + class(clm_lake_data_type) :: clm_lake + type(FmsNetcdfDomainFile_t) :: Sfc_restart + + ! Register 2D fields + call register_restart_field(Sfc_restart, 'T_snow', clm_lake%T_snow, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'T_ice', clm_lake%T_ice, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_snl2d', clm_lake%lake_snl2d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_h2osno2d', clm_lake%lake_h2osno2d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_tsfc', clm_lake%lake_tsfc, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_savedtke12d', clm_lake%lake_savedtke12d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_sndpth2d', clm_lake%lake_sndpth2d, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'clm_lakedepth', clm_lake%clm_lakedepth, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'clm_lake_initialized', clm_lake%clm_lake_initialized, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + + ! Register 3D fields + call register_restart_field(Sfc_restart, 'lake_z3d', clm_lake%lake_z3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'lake_dz3d', clm_lake%lake_dz3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_watsat3d', clm_lake%lake_soil_watsat3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_csol3d', clm_lake%lake_csol3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_tkmg3d', clm_lake%lake_soil_tkmg3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_tkdry3d', clm_lake%lake_soil_tkdry3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_soil_tksatu3d', clm_lake%lake_soil_tksatu3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_snow_z3d', clm_lake%lake_snow_z3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_snow_dz3d', clm_lake%lake_snow_dz3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_snow_zi3d', clm_lake%lake_snow_zi3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_h2osoi_vol3d', clm_lake%lake_h2osoi_vol3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_h2osoi_liq3d', clm_lake%lake_h2osoi_liq3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_h2osoi_ice3d', clm_lake%lake_h2osoi_ice3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_t_soisno3d', clm_lake%lake_t_soisno3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsnowsoil1_clm_lake', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_t_lake3d', clm_lake%lake_t_lake3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_icefrac3d', clm_lake%lake_icefrac3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levlake_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_clay3d', clm_lake%lake_clay3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsoil_clm_lake ', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart,'lake_sand3d', clm_lake%lake_sand3d, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'levsoil_clm_lake ', 'Time '/), is_optional=.true.) + end subroutine clm_lake_register_fields + + !>@ This is clm_lake%bundle_fields, and it is only used in the + !! quilt restart. It bundles all fields needed by the CLM Lake + !! Model, which makes them available to ESMF for restart I/O. + !! Terrible things will happen if you don't call + !! clm_lake%allocate_data and clm_lake%register_axes first. + subroutine clm_lake_bundle_fields(clm_lake, bundle, grid, Model, outputfile) + use esmf + use GFS_typedefs, only: GFS_control_type + implicit none + class(Clm_lake_data_type) :: clm_lake + type(ESMF_FieldBundle),intent(inout) :: bundle + type(ESMF_Grid),intent(inout) :: grid + type(GFS_control_type), intent(in) :: Model + character(*), intent(in) :: outputfile + + real(kind_phys),dimension(:,:),pointer :: temp_r2d + real(kind_phys),dimension(:,:,:),pointer :: temp_r3d + integer :: num + + ! Register 2D fields + call create_2d_field_and_add_to_bundle(clm_lake%T_snow, "T_snow", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%T_ice, 'T_ice', trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%lake_snl2d, "lake_snl2d", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%lake_h2osno2d, "lake_h2osno2d", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%lake_tsfc, "lake_tsfc", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%lake_savedtke12d, "lake_savedtke12d", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%lake_sndpth2d, "lake_sndpth2d", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%clm_lakedepth, "clm_lakedepth", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(clm_lake%clm_lake_initialized, "clm_lake_initialized", trim(outputfile), grid, bundle) + + ! Register 3D fields + call create_3d_field_and_add_to_bundle(clm_lake%lake_z3d, 'lake_z3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_dz3d, 'lake_dz3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_soil_watsat3d, 'lake_soil_watsat3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_csol3d, 'lake_csol3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_soil_tkmg3d, 'lake_soil_tkmg3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_soil_tkdry3d, 'lake_soil_tkdry3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_soil_tksatu3d, 'lake_soil_tksatu3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_snow_z3d, 'lake_snow_z3d', 'levsnowsoil1_clm_lake', & + clm_lake%levsnowsoil1_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_snow_dz3d, 'lake_snow_dz3d', 'levsnowsoil1_clm_lake', & + clm_lake%levsnowsoil1_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_snow_zi3d, 'lake_snow_zi3d', 'levsnowsoil_clm_lake', & + clm_lake%levsnowsoil_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_h2osoi_vol3d, 'lake_h2osoi_vol3d', 'levsnowsoil1_clm_lake', & + clm_lake%levsnowsoil1_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_h2osoi_liq3d, 'lake_h2osoi_liq3d', 'levsnowsoil1_clm_lake', & + clm_lake%levsnowsoil1_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_h2osoi_ice3d, 'lake_h2osoi_ice3d', 'levsnowsoil1_clm_lake', & + clm_lake%levsnowsoil1_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_t_soisno3d, 'lake_t_soisno3d', 'levsnowsoil1_clm_lake', & + clm_lake%levsnowsoil1_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_t_lake3d, 'lake_t_lake3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_icefrac3d, 'lake_icefrac3d', 'levlake_clm_lake', & + clm_lake%levlake_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_clay3d, 'lake_clay3d', 'levsoil_clm_lake', & + clm_lake%levsoil_clm_lake, trim(outputfile), grid, bundle) + call create_3d_field_and_add_to_bundle(clm_lake%lake_sand3d, 'lake_sand3d', 'levsoil_clm_lake', & + clm_lake%levsoil_clm_lake, trim(outputfile), grid, bundle) + + end subroutine Clm_lake_bundle_fields + + !>@ Final routine (destructor) for the clm_lake_data_type, called + !! automatically when an object of that type goes out of scope. This + !! is simply a wrapper around clm_lake%deallocate_data(). + subroutine clm_lake_final(clm_lake) + implicit none + type(clm_lake_data_type) :: clm_lake + call clm_lake_deallocate_data(clm_lake) + end subroutine clm_lake_final + + !>@ This is clm_lake%deallocate_data. It deallocates all data used, + !! and nullifies the pointers. The clm_lake object can safely be + !! used again after this call. This is also the implementation of + !! the clm_lake_data_type final routine. + subroutine clm_lake_deallocate_data(clm_lake) + implicit none + class(clm_lake_data_type) :: clm_lake + + ! Deallocate and nullify any associated pointers + + ! This #define reduces code length by a lot +#define IF_ASSOC_DEALLOC_NULL(var) \ + if(associated(clm_lake%var)) then ; \ + deallocate(clm_lake%var) ; \ + nullify(clm_lake%var) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(T_snow) + IF_ASSOC_DEALLOC_NULL(T_ice) + IF_ASSOC_DEALLOC_NULL(lake_snl2d) + IF_ASSOC_DEALLOC_NULL(lake_h2osno2d) + IF_ASSOC_DEALLOC_NULL(lake_tsfc) + IF_ASSOC_DEALLOC_NULL(lake_savedtke12d) + IF_ASSOC_DEALLOC_NULL(lake_sndpth2d) + IF_ASSOC_DEALLOC_NULL(clm_lakedepth) + IF_ASSOC_DEALLOC_NULL(clm_lake_initialized) + + IF_ASSOC_DEALLOC_NULL(lake_z3d) + IF_ASSOC_DEALLOC_NULL(lake_dz3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_watsat3d) + IF_ASSOC_DEALLOC_NULL(lake_csol3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_tkmg3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_tkdry3d) + IF_ASSOC_DEALLOC_NULL(lake_soil_tksatu3d) + IF_ASSOC_DEALLOC_NULL(lake_snow_z3d) + IF_ASSOC_DEALLOC_NULL(lake_snow_dz3d) + IF_ASSOC_DEALLOC_NULL(lake_snow_zi3d) + IF_ASSOC_DEALLOC_NULL(lake_h2osoi_vol3d) + IF_ASSOC_DEALLOC_NULL(lake_h2osoi_liq3d) + IF_ASSOC_DEALLOC_NULL(lake_h2osoi_ice3d) + IF_ASSOC_DEALLOC_NULL(lake_t_soisno3d) + IF_ASSOC_DEALLOC_NULL(lake_t_lake3d) + IF_ASSOC_DEALLOC_NULL(lake_icefrac3d) + IF_ASSOC_DEALLOC_NULL(lake_clay3d) + IF_ASSOC_DEALLOC_NULL(lake_sand3d) + +#undef IF_ASSOC_DEALLOC_NULL + end subroutine clm_lake_deallocate_data + +end module fv3atm_clm_lake_io +!> @} diff --git a/io/fv3atm_common_io.F90 b/io/fv3atm_common_io.F90 new file mode 100644 index 000000000..1143f23ac --- /dev/null +++ b/io/fv3atm_common_io.F90 @@ -0,0 +1,518 @@ +!> \file fv3atm_common_io.F90 +!! A set of routines commonly accessed by other io/fv3atm +!! modules. This should not be accessed by other code. Most of the +!! routines in this file copy data between x-y-z arrays and +!! block-decomposed (nb-ix-z) atmosphere arrays. + +module fv3atm_common_io + use GFS_typedefs, only: kind_phys + + implicit none + private + + public :: copy_from_GFS_Data, copy_to_GFS_Data + public :: copy_from_GFS_Data_2d_phys2phys, copy_from_GFS_Data_3d_phys2phys, & + copy_from_GFS_Data_2d_int2phys, copy_from_GFS_Data_3d_int2phys, & + copy_from_GFS_Data_2d_stack_phys2phys, copy_to_GFS_Data_3d_slice_phys2phys, & + copy_to_GFS_Data_2d_phys2phys, copy_to_GFS_Data_3d_phys2phys, & + copy_to_GFS_Data_2d_int2phys, copy_to_GFS_Data_3d_int2phys + + public :: GFS_data_transfer + public :: GFS_data_transfer_2d_phys2phys, & + GFS_data_transfer_3d_phys2phys, & + GFS_data_transfer_2d_int2phys, & + GFS_data_transfer_3d_int2phys, & + GFS_data_transfer_3d_slice_phys2phys, & + GFS_data_transfer_2d_stack_phys2phys + + public :: create_2d_field_and_add_to_bundle + public :: create_3d_field_and_add_to_bundle + public :: add_zaxis_to_field + + public :: get_nx_ny_from_atm + + !>\defgroup fv3atm_common_io FV3ATM Common I/O Utilities Module + !> @{ + + !>@ These subroutines copy data from x-y-z arrays to nb-ix-z grid arrays. + !! \section copy_from_GFS_Data interface + !! There are different combinations of decomposition, copy methods, + !! and datatypes. All are combined together into copy_from_GFS_Data + !! for convenience + interface copy_from_GFS_Data + module procedure copy_from_GFS_Data_2d_phys2phys, & + copy_from_GFS_Data_3d_phys2phys, & + copy_from_GFS_Data_2d_int2phys, & + copy_from_GFS_Data_3d_int2phys, & + copy_from_GFS_Data_3d_slice_phys2phys, & + copy_from_GFS_Data_2d_stack_phys2phys + end interface copy_from_GFS_Data + + !>@ These subroutines copy data from nb-ix-z grid arrays to x-y-z arrays. + !! \section copy_to_GFS_Data interface + !! There are different combinations of decomposition, copy methods, + !! and datatypes. All are combined together into copy_to_GFS_Data + !! for convenience + interface copy_to_GFS_Data + module procedure copy_to_GFS_Data_2d_phys2phys, & + copy_to_GFS_Data_3d_phys2phys, & + copy_to_GFS_Data_2d_int2phys, & + copy_to_GFS_Data_3d_int2phys, & + copy_to_GFS_Data_3d_slice_phys2phys, & + copy_to_GFS_Data_2d_stack_phys2phys + end interface copy_to_GFS_Data + + !>@brief These subroutines copy data in either direction between nb-ix-z grid arrays and x-y-z arrays. + !> \section GFS_data_transfer interface functions. + !! This interface allows a single subroutine to handle both reading + !! and writing restart files. The direction is controled by the "to" + !! argument (first argument) which is true when copying from x-y-z + !! arrays to nb-ix-z arrays. + !! There are different combinations of decomposition, copy methods, + !! and datatypes. All are combined together into copy_to_GFS_Data + !! for convenience + interface GFS_data_transfer + module procedure GFS_data_transfer_2d_phys2phys, & + GFS_data_transfer_3d_phys2phys, & + GFS_data_transfer_2d_int2phys, & + GFS_data_transfer_3d_int2phys, & + GFS_data_transfer_3d_slice_phys2phys, & + GFS_data_transfer_2d_stack_phys2phys + end interface GFS_data_transfer + +contains + + !>@brief Convenience function to get the x and y dimensions of the grid from Atm_block + pure subroutine get_nx_ny_from_atm(Atm_block, nx, ny) + use block_control_mod, only: block_control_type + implicit none + type(block_control_type), intent(in) :: Atm_block + integer, intent(out), optional :: nx, ny + integer :: isc, iec, jsc, jec + if(present(nx)) then + isc = Atm_block%isc + iec = Atm_block%iec + nx = (iec - isc + 1) + end if + if(present(ny)) then + jsc = Atm_block%jsc + jec = Atm_block%jec + ny = (jec - jsc + 1) + endif + end subroutine get_nx_ny_from_atm + + !>@brief copies from the ix-indexed var_block to the 2d x-y real(kind_phys) var2d array + pure subroutine copy_from_GFS_Data_2d_phys2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(in) :: var_block(:) + real(kind=kind_phys), intent(out) :: var2d(:,:,:) + integer ix + + nt=nt+1 + do ix=1,size(var_block) + var2d(ii1(ix),jj1(ix),nt) = var_block(ix) + enddo + end subroutine copy_from_GFS_Data_2d_phys2phys + + !>@brief copies from the ix-k-indexed var_block to the 3d x-y-z real(kind_phys) var3d array + pure subroutine copy_from_GFS_Data_3d_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(in) :: var_block(:,:) + real(kind=kind_phys), intent(out) :: var3d(:,:,:,:) + integer ix, k + + nt=nt+1 + do k=lbound(var_block,2),ubound(var_block,2) + do ix=1,size(var_block,1) + var3d(ii1(ix),jj1(ix),k,nt) = var_block(ix,k) + enddo + enddo + end subroutine copy_from_GFS_Data_3d_phys2phys + + !>@brief copies from the ix-k-indexed var_block to the 3d x-y-z integer var2d array + pure subroutine copy_from_GFS_Data_2d_int2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc, var_block(:) + integer, intent(inout) :: nt + real(kind=kind_phys), intent(out) :: var2d(:,:,:) + integer ix + + nt=nt+1 + do ix=1,size(var_block) + var2d(ii1(ix),jj1(ix),nt) = var_block(ix) + enddo + end subroutine copy_from_GFS_Data_2d_int2phys + + !>@brief copies a range of levels from the ix-k-indexed var_block to the x-y real(kind_phys) var3d array + pure subroutine copy_from_GFS_Data_2d_stack_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + ! For copying phy_f2d and phy_fctd + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(in) :: var_block(:,:) + real(kind=kind_phys), intent(out) :: var3d(:,:,:) + integer ix, k + + nt=nt+1 + do k=lbound(var_block,2),ubound(var_block,2) + do ix=1,size(var_block,1) + var3d(ii1(ix),jj1(ix),nt) = var_block(ix,k) + enddo + enddo + end subroutine copy_from_GFS_Data_2d_stack_phys2phys + + !>@brief copies from the ix-k-indexed var_block to the x-y integer var3d array + pure subroutine copy_from_GFS_Data_3d_int2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), var_block(:,:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(out) :: var3d(:,:,:,:) + integer ix, k + + nt=nt+1 + do k=lbound(var_block,2),ubound(var_block,2) + do ix=1,size(var_block,1) + var3d(ii1(ix),jj1(ix),k,nt) = real(var_block(ix,k),kind_phys) + enddo + enddo + end subroutine copy_from_GFS_Data_3d_int2phys + + !>@brief copies a range of levels from from the ix-k-indexed var_block to the x-y-z real(kind_phys) var3d array + pure subroutine copy_from_GFS_Data_3d_slice_phys2phys(ii1,jj1,isc,jsc,nt,k1,k2,var3d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc, k1, k2 + integer, intent(inout) :: nt + real(kind=kind_phys), intent(in) :: var_block(:,:) + real(kind=kind_phys), intent(out) :: var3d(:,:,:,:) + integer ix, k + + nt=nt+1 + do k=k1,k2 + do ix=1,size(var_block,1) + var3d(ii1(ix),jj1(ix),k,nt) = var_block(ix,k) + enddo + enddo + end subroutine copy_from_GFS_Data_3d_slice_phys2phys + + !>@brief copies from x-y real(kind_phys) var2d array to the ix-indexed var_block array + pure subroutine copy_to_GFS_Data_2d_phys2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(out) :: var_block(:) + real(kind=kind_phys), intent(in) :: var2d(:,:,:) + integer ix + + nt=nt+1 + do ix=1,size(var_block) + var_block(ix) = var2d(ii1(ix),jj1(ix),nt) + enddo + end subroutine copy_to_GFS_Data_2d_phys2phys + + !>@brief copies from x-y-z real(kind_phys) var3d array to the ix-k-indexed var_block array + pure subroutine copy_to_GFS_Data_3d_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(out) :: var_block(:,:) + real(kind=kind_phys), intent(in) :: var3d(:,:,:,:) + integer ix, k + + nt=nt+1 + do k=lbound(var_block,2),ubound(var_block,2) + do ix=1,size(var_block,1) + var_block(ix,k) = var3d(ii1(ix),jj1(ix),k,nt) + enddo + enddo + end subroutine copy_to_GFS_Data_3d_phys2phys + + !>@brief copies from x-y-z real(kind_phys) var3d array to the ix-k-indexed var_block array + pure subroutine copy_to_GFS_Data_2d_stack_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + ! For copying phy_f2d and phy_fctd + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(out) :: var_block(:,:) + real(kind=kind_phys), intent(in) :: var3d(:,:,:) + integer ix, k + + nt=nt+1 + do k=lbound(var_block,2),ubound(var_block,2) + do ix=1,size(var_block,1) + var_block(ix,k) = var3d(ii1(ix),jj1(ix),nt) + enddo + enddo + end subroutine copy_to_GFS_Data_2d_stack_phys2phys + + !>@brief copies a range of levels from the x-y-z real(kind_phys) var3d array to the ix-k-indexed var_block array + pure subroutine copy_to_GFS_Data_3d_slice_phys2phys(ii1,jj1,isc,jsc,nt,k1,k2,var3d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc, k1, k2 + integer, intent(inout) :: nt + real(kind=kind_phys), intent(out) :: var_block(:,:) + real(kind=kind_phys), intent(in) :: var3d(:,:,:,:) + integer ix, k + + nt=nt+1 + do k=k1,k2 + do ix=1,size(var_block,1) + var_block(ix,k) = var3d(ii1(ix),jj1(ix),k,nt) + enddo + enddo + end subroutine copy_to_GFS_Data_3d_slice_phys2phys + + !>@brief copies from x-y integer var2d array to the ix-indexed var_block array + pure subroutine copy_to_GFS_Data_2d_int2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + integer, intent(out) :: var_block(:) + real(kind=kind_phys), intent(in) :: var2d(:,:,:) + integer ix + + nt=nt+1 + do ix=1,size(var_block) + var_block(ix) = int(var2d(ii1(ix),jj1(ix),nt)) + enddo + end subroutine copy_to_GFS_Data_2d_int2phys + + !>@brief copies from x-y-z integer var3d array to the ix-k-indexed var_block array + pure subroutine copy_to_GFS_Data_3d_int2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + implicit none + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + integer, intent(out) :: var_block(:,:) + real(kind=kind_phys), intent(in) :: var3d(:,:,:,:) + integer ix + + nt=nt+1 + do ix=1,size(var_block,1) + var_block(ix,:) = int(var3d(ii1(ix),jj1(ix),:,nt)) + enddo + end subroutine copy_to_GFS_Data_3d_int2phys + + !>@brief copies between the ix-indexed var_block array and x-y real(kind_phys) var2d array. + !> \section GFS_data_transfer_2d_phys2phys subroutine from the GFS_data_transfer interface + !! This is a wrapper around copy_to_GFS_Data and copy_from_GFS_Data routines. + !! If to=true, then data is copied to var_block (the GFS_Data structures) but if + !! to=false, it is copied from the var_block arrays. This allows the same subroutine + !! to both read and write, preventing error-prone code duplication. + pure subroutine GFS_data_transfer_2d_phys2phys(to,ii1,jj1,isc,jsc,nt,var2d,var_block) + implicit none + logical, intent(in) :: to + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(inout) :: var_block(:) + real(kind=kind_phys), intent(inout) :: var2d(:,:,:) + + if(to) then + call copy_to_GFS_Data_2d_phys2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + else + call copy_from_GFS_Data_2d_phys2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + end if + end subroutine GFS_data_transfer_2d_phys2phys + + !>@brief copies between the ix-k-indexed var_block array and x-y-z real(kind_phys) var3d array. + !> \section GFS_data_transfer_3d_phys2phys subroutine from the GFS_data_transfer interface + !! This is a wrapper around copy_to_GFS_Data and copy_from_GFS_Data routines. + !! If to=true, then data is copied to var_block (the GFS_Data structures) but if + !! to=false, it is copied from the var_block arrays. This allows the same subroutine + !! to both read and write, preventing error-prone code duplication. + pure subroutine GFS_data_transfer_3d_phys2phys(to,ii1,jj1,isc,jsc,nt,var3d,var_block) + implicit none + logical, intent(in) :: to + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(inout) :: var_block(:,:) + real(kind=kind_phys), intent(inout) :: var3d(:,:,:,:) + + if(to) then + call copy_to_GFS_Data_3d_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + else + call copy_from_GFS_Data_3d_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + endif + end subroutine GFS_data_transfer_3d_phys2phys + + !>@brief copies a range of levels between the ix-k-indexed var_block array and x-y-z real(kind_phys) var3d array. + !> \section GFS_data_transfer_3d_slice_phys2phys subroutine from the GFS_data_transfer interface + !! This is a wrapper around copy_to_GFS_Data and copy_from_GFS_Data routines. + !! If to=true, then data is copied to var_block (the GFS_Data structures) but if + !! to=false, it is copied from the var_block arrays. This allows the same subroutine + !! to both read and write, preventing error-prone code duplication. + pure subroutine GFS_data_transfer_3d_slice_phys2phys(to,ii1,jj1,isc,jsc,nt,k1,k2,var3d,var_block) + implicit none + logical, intent(in) :: to + integer, intent(in) :: ii1(:), jj1(:), isc, jsc, k1, k2 + integer, intent(inout) :: nt + real(kind=kind_phys), intent(inout) :: var_block(:,:) + real(kind=kind_phys), intent(inout) :: var3d(:,:,:,:) + + if(to) then + call copy_to_GFS_Data_3d_slice_phys2phys(ii1,jj1,isc,jsc,nt,k1,k2,var3d,var_block) + else + call copy_from_GFS_Data_3d_slice_phys2phys(ii1,jj1,isc,jsc,nt,k1,k2,var3d,var_block) + endif + end subroutine GFS_data_transfer_3d_slice_phys2phys + + !>@brief copies between the ix-indexed var_block array and x-y integer var2d array. + !> \section GFS_data_transfer_2d_int2phys subroutine from the GFS_data_transfer interface + !! This is a wrapper around copy_to_GFS_Data and copy_from_GFS_Data routines. + !! If to=true, then data is copied to var_block (the GFS_Data structures) but if + !! to=false, it is copied from the var_block arrays. This allows the same subroutine + !! to both read and write, preventing error-prone code duplication. + pure subroutine GFS_data_transfer_2d_int2phys(to,ii1,jj1,isc,jsc,nt,var2d,var_block) + implicit none + logical, intent(in) :: to + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + integer, intent(inout) :: var_block(:) + real(kind=kind_phys), intent(inout) :: var2d(:,:,:) + + if(to) then + call copy_to_GFS_Data_2d_int2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + else + call copy_from_GFS_Data_2d_int2phys(ii1,jj1,isc,jsc,nt,var2d,var_block) + endif + end subroutine GFS_data_transfer_2d_int2phys + + !>@brief copies between the ix-k-indexed var_block array and x-y-z integer var3d array. + !> \section GFS_data_transfer_3d_int2phys subroutine from the GFS_data_transfer interface + !! This is a wrapper around copy_to_GFS_Data and copy_from_GFS_Data routines. + !! If to=true, then data is copied to var_block (the GFS_Data structures) but if + !! to=false, it is copied from the var_block arrays. This allows the same subroutine + !! to both read and write, preventing error-prone code duplication. + pure subroutine GFS_data_transfer_3d_int2phys(to,ii1,jj1,isc,jsc,nt,var3d,var_block) + implicit none + logical, intent(in) :: to + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + integer, intent(inout) :: var_block(:,:) + real(kind=kind_phys), intent(inout) :: var3d(:,:,:,:) + + if(to) then + call copy_to_GFS_Data_3d_int2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + else + call copy_from_GFS_Data_3d_int2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + endif + end subroutine GFS_data_transfer_3d_int2phys + + !>@brief copies a range of levels between the ix-k-indexed var_block array and x-y-z real(kind_phys) var3d array. + !> \section GFS_Data_transfer_2d_stack_phys2phys subroutine from the GFS_data_transfer interface + !! This is a wrapper around copy_to_GFS_Data and copy_from_GFS_Data routines. + !! If to=true, then data is copied to var_block (the GFS_Data structures) but if + !! to=false, it is copied from the var_block arrays. This allows the same subroutine + !! to both read and write, preventing error-prone code duplication. + pure subroutine GFS_Data_transfer_2d_stack_phys2phys(to,ii1,jj1,isc,jsc,nt,var3d,var_block) + ! For copying phy_f2d and phy_fctd + implicit none + logical, intent(in) :: to + integer, intent(in) :: ii1(:), jj1(:), isc, jsc + integer, intent(inout) :: nt + real(kind=kind_phys), intent(inout) :: var_block(:,:) + real(kind=kind_phys), intent(inout) :: var3d(:,:,:) + integer ix, k + + if(to) then + call copy_to_GFS_data_2d_stack_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + else + call copy_from_GFS_data_2d_stack_phys2phys(ii1,jj1,isc,jsc,nt,var3d,var_block) + end if + end subroutine GFS_Data_transfer_2d_stack_phys2phys + + !>@brief adds a 2D restart array to an ESMF bundle for quilting restarts. + subroutine create_2d_field_and_add_to_bundle(temp_r2d, field_name, outputfile, grid, bundle) + + use esmf + + implicit none + + real(kind_phys), dimension(:,:), pointer, intent(in) :: temp_r2d + character(len=*), intent(in) :: field_name + character(len=*), intent(in) :: outputfile + type(ESMF_Grid), intent(in) :: grid + type(ESMF_FieldBundle), intent(inout) :: bundle + + type(ESMF_Field) :: field + + integer :: rc, i + + field = ESMF_FieldCreate(grid, temp_r2d, datacopyflag=ESMF_DATACOPY_REFERENCE, & + name=trim(field_name), indexFlag=ESMF_INDEX_DELOCAL, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU,line=__LINE__, file=__FILE__)) & + call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", name='output_file', value=trim(outputfile), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_FieldBundleAdd(bundle, (/field/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + end subroutine create_2d_field_and_add_to_bundle + + !>@brief adds a 3D restart array and its vertical axis to an ESMF bundle for quilting restarts. + subroutine create_3d_field_and_add_to_bundle(temp_r3d, field_name, axis_name, axis_values, outputfile, grid, bundle) + + use esmf + + implicit none + + real(kind_phys), dimension(:,:,:), pointer, intent(in) :: temp_r3d + character(len=*), intent(in) :: field_name + character(len=*), intent(in) :: axis_name + real(kind_phys), dimension(:), intent(in) :: axis_values + character(len=*), intent(in) :: outputfile + type(ESMF_Grid), intent(in) :: grid + type(ESMF_FieldBundle), intent(inout) :: bundle + + type(ESMF_Field) :: field + + integer :: rc, i + + field = ESMF_FieldCreate(grid, temp_r3d, datacopyflag=ESMF_DATACOPY_REFERENCE, & + name=trim(field_name), indexFlag=ESMF_INDEX_DELOCAL, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU,line=__LINE__, file=__FILE__)) & + call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", name='output_file', value=trim(outputfile), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call add_zaxis_to_field(field, axis_name, axis_values) + + call ESMF_FieldBundleAdd(bundle, (/field/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + end subroutine create_3d_field_and_add_to_bundle + + !>@brief adds a vertical axis to an ESMF bundle for quilting restarts. + subroutine add_zaxis_to_field(field, axis_name, axis_values) + + use esmf + + implicit none + + type(ESMF_Field), intent(inout) :: field + character(len=*), intent(in) :: axis_name + real(kind_phys), dimension(:), intent(in) :: axis_values + + integer :: rc + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name="ESMF:ungridded_dim_labels", valueList=(/trim(axis_name)/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3-dim", & + name=trim(axis_name), valueList=axis_values, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3-dim", & + name=trim(axis_name)//"cartesian_axis", value="Z", rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + end subroutine add_zaxis_to_field + +end module fv3atm_common_io +!> @} diff --git a/io/fv3atm_history_io.F90 b/io/fv3atm_history_io.F90 new file mode 100644 index 000000000..7c73fe296 --- /dev/null +++ b/io/fv3atm_history_io.F90 @@ -0,0 +1,1184 @@ +!> \file fv3atm_history_io.F90 +!! This file defines routines used to output atmosphere diagnostic +!! (history) data from the physics and surface fields, both for quilt +!! and non-quilt output. +module fv3atm_history_io_mod + + ! + !--- FMS/GFDL modules + use block_control_mod, only: block_control_type + use mpp_mod, only: mpp_error, mpp_pe, mpp_root_pe, FATAL + use mpp_domains_mod, only: domain1d, domainUG + use time_manager_mod, only: time_type + use diag_manager_mod, only: register_diag_field, send_data + use diag_axis_mod, only: get_axis_global_length, get_diag_axis, & + get_diag_axis_name + use diag_data_mod, only: output_fields, max_output_fields + use diag_util_mod, only: find_input_field + use constants_mod, only: grav, rdgas + ! + !--- GFS_typedefs + use GFS_typedefs, only: GFS_control_type, kind_phys + use GFS_diagnostics, only: GFS_externaldiag_type + + ! + !----------------------------------------------------------------------- + implicit none + private + + !--- public interfaces --- + public fv3atm_diag_register, fv3atm_diag_output +#ifdef use_WRTCOMP + public fv_phys_bundle_setup +#endif + + !>\defgroup fv3atm_history_io_mod FV3ATM History I/O Module + !> @{ + + !>@ The maximum allowed number of diagnostic fields that can be defined in any given model run. + !! This does not include rrfs-sd or clm lake, which have their own data structures. + integer, parameter, public :: DIAG_SIZE = 800 + + real, parameter :: missing_value = 9.99e20_kind_phys + real, parameter :: stndrd_atmos_ps = 101325.0_kind_phys + real, parameter :: stndrd_atmos_lapse = 0.0065_kind_phys + real, parameter :: drythresh = 1.e-4_kind_phys + real, parameter :: zero = 0.0_kind_phys, one = 1.0_kind_phys + + !>@ Storage type for temporary data during output of diagnostic (history) files + type history_type + integer :: tot_diag_idx = 0 + + integer :: isco=0,ieco=0,jsco=0,jeco=0,levo=0,num_axes_phys=0 + integer :: fhzero=0, ncld=0, nsoil=0, imp_physics=0, landsfcmdl=0 + real(4) :: dtp=0 + integer,dimension(:), pointer :: nstt => null() + integer,dimension(:), pointer :: nstt_vctbl => null() + integer,dimension(:), pointer :: all_axes => null() + character(20),dimension(:), pointer :: axis_name => null() + real(4), dimension(:,:,:), pointer :: buffer_phys_bl => null() + real(4), dimension(:,:,:), pointer :: buffer_phys_nb => null() + real(4), dimension(:,:,:,:), pointer :: buffer_phys_windvect => null() + real(kind=kind_phys),dimension(:,:),pointer :: lon => null() + real(kind=kind_phys),dimension(:,:),pointer :: lat => null() + real(kind=kind_phys),dimension(:,:),pointer :: uwork => null() + real(kind=kind_phys),dimension(:,:,:),pointer:: uwork3d => null() + logical :: uwork_set = .false. + character(128) :: uwindname = "(noname)" + + !--- miscellaneous other variables + logical :: use_wrtgridcomp_output = .FALSE. + contains + procedure :: register => history_type_register + procedure :: output => history_type_output + procedure :: store_data => history_type_store_data + procedure :: store_data3D => history_type_store_data3D +#ifdef use_WRTCOMP + procedure :: bundle_setup => history_type_bundle_setup + procedure :: add_field_to_phybundle => history_type_add_field_to_phybundle + procedure :: find_output_name => history_type_find_output_name +#endif + end type history_type + + !>@ This shared_history_data instance of history_type is shared between all calls to public module subroutines. + type(history_type) :: shared_history_data + +CONTAINS + + !>@brief Registers diagnostic variables with the FMS diagnostic manager. + !> \section fv3atm_diag_register subroutine + !! Creates and populates a data type which is then used to "register" + !! diagnostic variables with the GFDL FMS diagnostic manager. + !! includes short & long names, units, conversion factors, etc. + !! there is no copying of data, but instead a clever use of pointers. + !! calls a GFDL FMS routine to register diagnositcs and compare against + !! the diag_table to determine what variables are to be output. + subroutine fv3atm_diag_register(Diag, Time, Atm_block, Model, xlon, xlat, axes) + use physcons, only: con_g + implicit none + !--- subroutine interface variable definitions + type(GFS_externaldiag_type), intent(inout) :: Diag(:) + type(time_type), intent(in) :: Time + type (block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + real(kind=kind_phys), intent(in) :: xlon(:,:) + real(kind=kind_phys), intent(in) :: xlat(:,:) + integer, dimension(4), intent(in) :: axes + + call shared_history_data%register(Diag, Time, Atm_block, Model, xlon, xlat, axes) + end subroutine fv3atm_diag_register + + !>@brief Transfers diagnostic data to the FMS diagnostic manager + !> \section fv3atm_diag_output subroutine + !! This routine transfers diagnostic data to the FMS diagnostic + !! manager for eventual output to the history files. + subroutine fv3atm_diag_output(time, diag, atm_block, nx, ny, levs, ntcw, ntoz, & + dt, time_int, time_intfull, time_radsw, time_radlw) + !--- subroutine interface variable definitions + type(time_type), intent(in) :: time + type(GFS_externaldiag_type), intent(in) :: diag(:) + type (block_control_type), intent(in) :: atm_block + integer, intent(in) :: nx, ny, levs, ntcw, ntoz + real(kind=kind_phys), intent(in) :: dt + real(kind=kind_phys), intent(in) :: time_int + real(kind=kind_phys), intent(in) :: time_intfull + real(kind=kind_phys), intent(in) :: time_radsw + real(kind=kind_phys), intent(in) :: time_radlw + + call shared_history_data%output(time, diag, atm_block, nx, ny, levs, ntcw, ntoz, & + dt, time_int, time_intfull, time_radsw, time_radlw) + + end subroutine fv3atm_diag_output + +#ifdef use_WRTCOMP + !>@brief Sets up the ESMF bundle to use for quilt diagnostic output + !> \section fv_phys_bundle_setup subroutine + !! This part of the write component (quilt) sets up the ESMF bundles + !! to use for writing diagnostic output. It is only defined when the + !! write component is enabled at compile time. + subroutine fv_phys_bundle_setup(Diag, axes, phys_bundle, fcst_grid, quilting, nbdlphys, rc) + ! + !------------------------------------------------------------- + !*** set esmf bundle for phys output fields + !------------------------------------------------------------ + ! + use esmf + use diag_data_mod, ONLY: diag_atttype + ! + implicit none + ! + type(GFS_externaldiag_type),intent(in) :: Diag(:) + integer, intent(in) :: axes(:) + type(ESMF_FieldBundle),intent(inout) :: phys_bundle(:) + type(ESMF_Grid),intent(inout) :: fcst_grid + logical,intent(in) :: quilting + integer, intent(in) :: nbdlphys + integer,intent(out) :: rc + + call shared_history_data%bundle_setup(Diag, axes, phys_bundle, fcst_grid, quilting, nbdlphys, rc) + end subroutine fv_phys_bundle_setup +#endif + + !>@brief Private implementation of fv3atm_diag_register. Do not call directly. + !> \section history_type%register procedure + !! This is the history_type%register procedure, which provides the internal + !! implementation of fv3atm_diag_register. Do not call this directly. + subroutine history_type_register(hist, Diag, Time, Atm_block, Model, xlon, xlat, axes) + use physcons, only: con_g + implicit none + !--- subroutine interface variable definitions + class(history_type) :: hist + type(GFS_externaldiag_type), intent(inout) :: Diag(:) + type(time_type), intent(in) :: Time + type (block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + real(kind=kind_phys), intent(in) :: xlon(:,:) + real(kind=kind_phys), intent(in) :: xlat(:,:) + integer, dimension(4), intent(in) :: axes + !--- local variables + integer :: idx, nrgst_bl, nrgst_nb, nrgst_vctbl + + hist%isco = Atm_block%isc + hist%ieco = Atm_block%iec + hist%jsco = Atm_block%jsc + hist%jeco = Atm_block%jec + hist%levo = model%levs + hist%fhzero = nint(Model%fhzero) + ! hist%ncld = Model%ncld + hist%ncld = Model%imp_physics + hist%nsoil = Model%lsoil + hist%dtp = Model%dtp + hist%imp_physics = Model%imp_physics + hist%landsfcmdl = Model%lsm + ! print *,'in fv3atm_diag_register,hist%ncld=',Model%ncld,Model%lsoil,Model%imp_physics, & + ! ' hist%dtp=',hist%dtp,' hist%landsfcmdl=',Model%lsm + ! + !save lon/lat for vector interpolation + allocate(hist%lon(hist%isco:hist%ieco,hist%jsco:hist%jeco)) + allocate(hist%lat(hist%isco:hist%ieco,hist%jsco:hist%jeco)) + hist%lon = xlon + hist%lat = xlat + + do idx = 1,DIAG_SIZE + if (trim(Diag(idx)%name) == '') exit + hist%tot_diag_idx = idx + enddo + + if (hist%tot_diag_idx == DIAG_SIZE) then + call mpp_error(fatal, 'fv3atm_io::fv3atm_diag_register - need to increase parameter DIAG_SIZE') + endif + + allocate(hist%nstt(hist%tot_diag_idx), hist%nstt_vctbl(hist%tot_diag_idx)) + hist%nstt = 0 + hist%nstt_vctbl = 0 + nrgst_bl = 0 + nrgst_nb = 0 + nrgst_vctbl = 0 + hist%num_axes_phys = 2 + do idx = 1,hist%tot_diag_idx + if (diag(idx)%axes == -99) then + call mpp_error(fatal, 'gfs_driver::gfs_diag_register - attempt to register an undefined variable') + endif + Diag(idx)%id = register_diag_field (trim(Diag(idx)%mod_name), trim(Diag(idx)%name), & + axes(1:Diag(idx)%axes), Time, trim(Diag(idx)%desc), & + trim(Diag(idx)%unit), missing_value=real(missing_value)) + if(Diag(idx)%id > 0) then + if (Diag(idx)%axes == 2) then + if( index(trim(Diag(idx)%intpl_method),'bilinear') > 0 ) then + nrgst_bl = nrgst_bl + 1 + hist%nstt(idx) = nrgst_bl + else if (trim(Diag(idx)%intpl_method) == 'nearest_stod' ) then + nrgst_nb = nrgst_nb + 1 + hist%nstt(idx) = nrgst_nb + endif + if(trim(Diag(idx)%intpl_method) == 'vector_bilinear') then + if(Diag(idx)%name(1:1) == 'v' .or. Diag(idx)%name(1:1) == 'V') then + nrgst_vctbl = nrgst_vctbl + 1 + hist%nstt_vctbl(idx) = nrgst_vctbl + ! print *,'in phy_setup, vector_bilinear, name=', trim(Diag(idx)%name),' nstt_vctbl=', hist%nstt_vctbl(idx), 'idx=',idx + endif + endif + else if (diag(idx)%axes == 3) then + if( index(trim(diag(idx)%intpl_method),'bilinear') > 0 ) then + hist%nstt(idx) = nrgst_bl + 1 + nrgst_bl = nrgst_bl + hist%levo + else if (trim(diag(idx)%intpl_method) == 'nearest_stod' ) then + hist%nstt(idx) = nrgst_nb + 1 + nrgst_nb = nrgst_nb + hist%levo + endif + if(trim(diag(idx)%intpl_method) == 'vector_bilinear') then + if(diag(idx)%name(1:1) == 'v' .or. diag(idx)%name(1:1) == 'V') then + hist%nstt_vctbl(idx) = nrgst_vctbl + 1 + nrgst_vctbl = nrgst_vctbl + hist%levo + ! print *,'in phy_setup, vector_bilinear, name=', trim(diag(idx)%name),' nstt_vctbl=', hist%nstt_vctbl(idx), 'idx=',idx + endif + endif + hist%num_axes_phys = 3 + endif + endif + + enddo + + allocate(hist%buffer_phys_bl(hist%isco:hist%ieco,hist%jsco:hist%jeco,nrgst_bl)) + allocate(hist%buffer_phys_nb(hist%isco:hist%ieco,hist%jsco:hist%jeco,nrgst_nb)) + allocate(hist%buffer_phys_windvect(3,hist%isco:hist%ieco,hist%jsco:hist%jeco,nrgst_vctbl)) + hist%buffer_phys_bl = zero + hist%buffer_phys_nb = zero + hist%buffer_phys_windvect = zero + if(mpp_pe() == mpp_root_pe()) print *,'in fv3atm_diag_register, nrgst_bl=',nrgst_bl,' nrgst_nb=',nrgst_nb, & + ' nrgst_vctbl=',nrgst_vctbl, 'hist%isco=',hist%isco,hist%ieco,'hist%jsco=',hist%jsco,hist%jeco,' hist%num_axes_phys=', hist%num_axes_phys + + end subroutine history_type_register + + !>@brief Internal implementation of fv3atm_diag_output + !> \section history_type%output procedure + !! This is history_type%output, which provides the internal + !! implementation of the public fv3atm_diag_output routine. Never + !! call this directly. + subroutine history_type_output(hist, time, diag, atm_block, nx, ny, levs, ntcw, ntoz, & + dt, time_int, time_intfull, time_radsw, time_radlw) + !--- subroutine interface variable definitions + class(history_type) :: hist + type(time_type), intent(in) :: time + type(GFS_externaldiag_type), intent(in) :: diag(:) + type (block_control_type), intent(in) :: atm_block + integer, intent(in) :: nx, ny, levs, ntcw, ntoz + real(kind=kind_phys), intent(in) :: dt + real(kind=kind_phys), intent(in) :: time_int + real(kind=kind_phys), intent(in) :: time_intfull + real(kind=kind_phys), intent(in) :: time_radsw + real(kind=kind_phys), intent(in) :: time_radlw + !--- local variables + integer :: i, j, k, idx, nb, ix, ii, jj + character(len=2) :: xtra +#ifdef CCPP_32BIT + real, dimension(nx,ny) :: var2 + real, dimension(nx,ny,levs) :: var3 +#else + real(kind=kind_phys), dimension(nx,ny) :: var2 + real(kind=kind_phys), dimension(nx,ny,levs) :: var3 +#endif + real(kind=kind_phys) :: rtime_int, rtime_intfull, lcnvfac + real(kind=kind_phys) :: rtime_radsw, rtime_radlw + + rtime_int = one/time_int + rtime_intfull = one/time_intfull + rtime_radsw = one/time_radsw + rtime_radlw = one/time_radlw + + ! if(mpp_pe()==mpp_root_pe())print *,'in,fv3atm_io. time avg, time_int=',time_int + history_loop: do idx = 1,hist%tot_diag_idx + has_id: if (diag(idx)%id > 0) then + lcnvfac = diag(idx)%cnvfac + if (diag(idx)%time_avg) then + if ( trim(diag(idx)%time_avg_kind) == 'full' ) then + lcnvfac = lcnvfac*rtime_intfull + ! if(mpp_pe()==mpp_root_pe())print *,'in,fv3atm_io. full time avg, field=',trim(Diag(idx)%name),' time=',time_intfull + else if ( trim(diag(idx)%time_avg_kind) == 'rad_lw' ) then + lcnvfac = lcnvfac*min(rtime_radlw,rtime_int) + ! if(mpp_pe()==mpp_root_pe())print *,'in,fv3atm_io. rad longwave avg, field=',trim(Diag(idx)%name),' time=',time_radlw + else if ( trim(diag(idx)%time_avg_kind) == 'rad_sw' ) then + lcnvfac = lcnvfac*min(rtime_radsw,rtime_int) + ! if(mpp_pe()==mpp_root_pe())print *,'in,fv3atm_io. rad shortwave avg, field=',trim(Diag(idx)%name),' time=',time_radsw + else if ( trim(diag(idx)%time_avg_kind) == 'rad_swlw_min' ) then + lcnvfac = lcnvfac*min(max(rtime_radsw,rtime_radlw),rtime_int) + ! if(mpp_pe()==mpp_root_pe())print *,'in,fv3atm_io. rad swlw min avg, field=',trim(Diag(idx)%name),' time=',time_radlw,time_radsw,time_int + else + lcnvfac = lcnvfac*rtime_int + endif + endif + if_2d: if (diag(idx)%axes == 2) then + ! Integer data + int_or_real: if (associated(Diag(idx)%data(1)%int2)) then + if (trim(Diag(idx)%intpl_method) == 'nearest_stod') then + var2(1:nx,1:ny) = 0._kind_phys + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + var2(i,j) = real(Diag(idx)%data(nb)%int2(ix), kind=kind_phys) + enddo + enddo + call hist%store_data(Diag(idx)%id, var2, Time, idx, Diag(idx)%intpl_method, Diag(idx)%name) + else + call mpp_error(FATAL, 'Interpolation method ' // trim(Diag(idx)%intpl_method) // ' for integer variable ' & + // trim(Diag(idx)%name) // ' not supported.') + endif + ! Real data + else ! int_or_real + if_mask: if (trim(diag(idx)%mask) == 'positive_flux') then + !--- albedos are actually a ratio of two radiation surface properties + var2(1:nx,1:ny) = 0._kind_phys + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + if (Diag(idx)%data(nb)%var21(ix) > 0._kind_phys) & + var2(i,j) = max(0._kind_phys,min(1._kind_phys,Diag(idx)%data(nb)%var2(ix)/Diag(idx)%data(nb)%var21(ix)))*lcnvfac + enddo + enddo + elseif (trim(Diag(idx)%mask) == 'land_ice_only') then + !--- need to "mask" gflux to output valid data over land/ice only + var2(1:nx,1:ny) = missing_value + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + if (Diag(idx)%data(nb)%var21(ix) /= 0) var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac + enddo + enddo + elseif (trim(Diag(idx)%mask) == 'land_only') then + !--- need to "mask" soilm to have value only over land + var2(1:nx,1:ny) = missing_value + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + if (Diag(idx)%data(nb)%var21(ix) == 1) var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac + enddo + enddo + elseif (trim(Diag(idx)%mask) == 'cldmask') then + !--- need to "mask" soilm to have value only over land + var2(1:nx,1:ny) = missing_value + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + if (Diag(idx)%data(nb)%var21(ix)*100. > 0.5) var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac + enddo + enddo + elseif (trim(Diag(idx)%mask) == 'cldmask_ratio') then + !--- need to "mask" soilm to have value only over land + var2(1:nx,1:ny) = missing_value + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + if (Diag(idx)%data(nb)%var21(ix)*100.*lcnvfac > 0.5) var2(i,j) = Diag(idx)%data(nb)%var2(ix)/ & + Diag(idx)%data(nb)%var21(ix) + enddo + enddo + elseif (trim(Diag(idx)%mask) == 'pseudo_ps') then + if ( hist%use_wrtgridcomp_output ) then + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + var2(i,j) = (Diag(idx)%data(nb)%var2(ix)/stndrd_atmos_ps)**(rdgas/grav*stndrd_atmos_lapse) + enddo + enddo + else + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + var2(i,j) = Diag(idx)%data(nb)%var2(ix) + enddo + enddo + endif + elseif (trim(Diag(idx)%mask) == '') then + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + var2(i,j) = Diag(idx)%data(nb)%var2(ix)*lcnvfac + enddo + enddo + endif if_mask + endif int_or_real + ! used=send_data(Diag(idx)%id, var2, Time) + ! print *,'in phys, after store_data, idx=',idx,' var=', trim(Diag(idx)%name) + call hist%store_data(Diag(idx)%id, var2, Time, idx, Diag(idx)%intpl_method, Diag(idx)%name) + ! if(trim(Diag(idx)%name) == 'totprcp_ave' ) print *,'in gfs_io, totprcp=',Diag(idx)%data(1)%var2(1:3), & + ! ' lcnvfac=', lcnvfac + elseif (Diag(idx)%axes == 3) then + !--- + !--- skipping other 3D variables with the following else statement + !--- + ! if(mpp_pe()==mpp_root_pe())print *,'in,fv3atm_io. 3D fields, idx=',idx,'varname=',trim(diag(idx)%name), & + ! 'lcnvfac=',lcnvfac, 'hist%levo=',hist%levo,'nx=',nx,'ny=',ny + do k=1, hist%levo + do j = 1, ny + jj = j + Atm_block%jsc -1 + do i = 1, nx + ii = i + Atm_block%isc -1 + nb = Atm_block%blkno(ii,jj) + ix = Atm_block%ixp(ii,jj) + ! if(mpp_pe()==mpp_root_pe())print *,'in,fv3atm_io,sze(Diag(idx)%data(nb)%var3)=', & + ! size(Diag(idx)%data(nb)%var3,1),size(Diag(idx)%data(nb)%var3,2) + var3(i,j,k) = Diag(idx)%data(nb)%var3(ix,hist%levo-k+1)*lcnvfac + enddo + enddo + enddo + call hist%store_data3D(Diag(idx)%id, var3, Time, idx, Diag(idx)%intpl_method, Diag(idx)%name) + endif if_2d + endif has_id + end do history_loop + end subroutine history_type_output + + !>@brief Part of the internal implementation of history_type_output (history_type%output) + !> \section history_type%store_data procedure + !! This routine copies data from an x-y array to internal buffers for later output. + !! Never call this subroutine directly; call fv3atm_diag_output instead. + subroutine history_type_store_data(hist,id, work, Time, idx, intpl_method, fldname) + implicit none + class(history_type) :: hist + integer, intent(in) :: id + integer, intent(in) :: idx +#ifdef CCPP_32BIT + real, intent(in) :: work(:,:) +#else + real(kind=kind_phys), intent(in) :: work(hist%ieco-hist%isco+1,hist%jeco-hist%jsco+1) +#endif + type(time_type), intent(in) :: Time + character(*), intent(in) :: intpl_method + character(*), intent(in) :: fldname + ! + real(kind=kind_phys) :: sinlat, sinlon, coslon + integer j,i,nv,i1,j1 + logical used + ! + if_has_id: if( id > 0 ) then + if_gridcomp: if( hist%use_wrtgridcomp_output ) then + if_interp: if( trim(intpl_method) == 'bilinear') then + !$omp parallel do default(shared) private(i,j) + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%buffer_phys_bl(i,j,hist%nstt(idx)) = work(i-hist%isco+1,j-hist%jsco+1) + enddo + enddo + else if(trim(intpl_method) == 'nearest_stod') then + !$omp parallel do default(shared) private(i,j) + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%buffer_phys_nb(i,j,hist%nstt(idx)) = work(i-hist%isco+1,j-hist%jsco+1) + enddo + enddo + else if(trim(intpl_method) == 'vector_bilinear') then + !first save the data + !$omp parallel do default(shared) private(i,j) + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%buffer_phys_bl(i,j,hist%nstt(idx)) = work(i-hist%isco+1,j-hist%jsco+1) + enddo + enddo + if_u_wind: if( fldname(1:1) == 'u' .or. fldname(1:1) == 'U') then + if(.not.associated(hist%uwork)) allocate(hist%uwork(hist%isco:hist%ieco,hist%jsco:hist%jeco)) + !$omp parallel do default(shared) private(i,j) + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%uwork(i,j) = work(i-hist%isco+1,j-hist%jsco+1) + enddo + enddo + hist%uwindname = fldname + hist%uwork_set = .true. + endif if_u_wind + if_v_wind: if( fldname(1:1) == 'v' .or. fldname(1:1) == 'V') then + !set up wind vector + if( hist%uwork_set .and. trim(hist%uwindname(2:)) == trim(fldname(2:))) then + nv = hist%nstt_vctbl(idx) + !$omp parallel do default(shared) private(i,j,i1,j1,sinlat,sinlon,coslon) + do j= hist%jsco,hist%jeco + j1 = j-hist%jsco+1 + do i= hist%isco,hist%ieco + i1 = i-hist%isco+1 + sinlat = sin(hist%lat(i,j)) + sinlon = sin(hist%lon(i,j)) + coslon = cos(hist%lon(i,j)) + hist%buffer_phys_windvect(1,i,j,nv) = hist%uwork(i,j)*coslon - work(i1,j1)*sinlat*sinlon + hist%buffer_phys_windvect(2,i,j,nv) = hist%uwork(i,j)*sinlon + work(i1,j1)*sinlat*coslon + hist%buffer_phys_windvect(3,i,j,nv) = work(i1,j1)*cos(hist%lat(i,j)) + enddo + enddo + endif + hist%uwork = zero + hist%uwindname = '' + hist%uwork_set = .false. + endif if_v_wind + + endif if_interp + else + used = send_data(id, work, Time) + endif if_gridcomp + endif if_has_id + ! + end subroutine history_type_store_data + + !>@brief Part of the internal implementation of history_type_output (history_type%output) + !> \section history_type%store_data3D procedure + !! This routine copies data from an x-y-z array to internal buffers for later output. + !! Never call this subroutine directly; call fv3atm_diag_output instead. + subroutine history_type_store_data3D(hist, id, work, Time, idx, intpl_method, fldname) + implicit none + class(history_type) :: hist + integer, intent(in) :: id + integer, intent(in) :: idx +#ifdef CCPP_32BIT + real, intent(in) :: work(:,:,:) +#else + real(kind=kind_phys), intent(in) :: work(hist%ieco-hist%isco+1,hist%jeco-hist%jsco+1,hist%levo) +#endif + type(time_type), intent(in) :: Time + character(*), intent(in) :: intpl_method + character(*), intent(in) :: fldname + ! + real(kind=kind_phys), allocatable, dimension(:,:) :: sinlon, coslon, sinlat, coslat + integer k,j,i,nv,i1,j1 + logical used + ! + if( id > 0 ) then + if( hist%use_wrtgridcomp_output ) then + if( trim(intpl_method) == 'bilinear') then + !$omp parallel do default(shared) private(i,j,k) + do k= 1,hist%levo + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%buffer_phys_bl(i,j,hist%nstt(idx)+k-1) = work(i-hist%isco+1,j-hist%jsco+1,k) + enddo + enddo + enddo + else if(trim(intpl_method) == 'nearest_stod') then + !$omp parallel do default(shared) private(i,j,k) + do k= 1,hist%levo + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%buffer_phys_nb(i,j,hist%nstt(idx)+k-1) = work(i-hist%isco+1,j-hist%jsco+1,k) + enddo + enddo + enddo + else if(trim(intpl_method) == 'vector_bilinear') then + !first save the data + !$omp parallel do default(shared) private(i,j,k) + do k= 1,hist%levo + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%buffer_phys_bl(i,j,hist%nstt(idx)+k-1) = work(i-hist%isco+1,j-hist%jsco+1,k) + enddo + enddo + enddo + if( fldname(1:1) == 'u' .or. fldname(1:1) == 'U') then + if(.not.associated(hist%uwork3d)) allocate(hist%uwork3d(hist%isco:hist%ieco,hist%jsco:hist%jeco,hist%levo)) + !$omp parallel do default(shared) private(i,j,k) + do k= 1, hist%levo + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + hist%uwork3d(i,j,k) = work(i-hist%isco+1,j-hist%jsco+1,k) + enddo + enddo + enddo + hist%uwindname = fldname + hist%uwork_set = .true. + endif + if( fldname(1:1) == 'v' .or. fldname(1:1) == 'V') then + !set up wind vector + if( hist%uwork_set .and. trim(hist%uwindname(2:)) == trim(fldname(2:))) then + allocate (sinlon(hist%isco:hist%ieco,hist%jsco:hist%jeco), coslon(hist%isco:hist%ieco,hist%jsco:hist%jeco), & + sinlat(hist%isco:hist%ieco,hist%jsco:hist%jeco), coslat(hist%isco:hist%ieco,hist%jsco:hist%jeco)) + !$omp parallel do default(shared) private(i,j) + do j= hist%jsco,hist%jeco + do i= hist%isco,hist%ieco + sinlon(i,j) = sin(hist%lon(i,j)) + coslon(i,j) = cos(hist%lon(i,j)) + sinlat(i,j) = sin(hist%lat(i,j)) + coslat(i,j) = cos(hist%lat(i,j)) + enddo + enddo + !$omp parallel do default(shared) private(i,j,k,nv,i1,j1) + do k= 1, hist%levo + nv = hist%nstt_vctbl(idx)+k-1 + do j= hist%jsco,hist%jeco + j1 = j-hist%jsco+1 + do i= hist%isco,hist%ieco + i1 = i-hist%isco+1 + hist%buffer_phys_windvect(1,i,j,nv) = hist%uwork3d(i,j,k)*coslon(i,j) & + - work(i1,j1,k)*sinlat(i,j)*sinlon(i,j) + hist%buffer_phys_windvect(2,i,j,nv) = hist%uwork3d(i,j,k)*sinlon(i,j) & + + work(i1,j1,k)*sinlat(i,j)*coslon(i,j) + hist%buffer_phys_windvect(3,i,j,nv) = work(i1,j1,k)*coslat(i,j) + enddo + enddo + enddo + deallocate (sinlon, coslon, sinlat, coslat) + endif + hist%uwork3d = zero + hist%uwindname = '' + hist%uwork_set = .false. + endif + + endif + else + used = send_data(id, work, Time) + endif + endif + ! + end subroutine history_type_store_data3D + +#ifdef use_WRTCOMP + !>@brief Sets up the ESMF bundle to use for quilt diagnostic output + !> \section history_type%bundle_setup procedure + !! This part of the write component (quilt) sets up the ESMF bundles + !! to use for writing diagnostic output. It is only defined when the + !! write component is enabled at compile time. + + subroutine history_type_bundle_setup(hist, Diag, axes, phys_bundle, fcst_grid, quilting, nbdlphys, rc) + ! set esmf bundle for phys output fields + use esmf + use diag_data_mod, ONLY: diag_atttype + ! + implicit none + ! + class(history_type) :: hist + type(GFS_externaldiag_type),intent(in) :: Diag(:) + integer, intent(in) :: axes(:) + type(ESMF_FieldBundle),intent(inout) :: phys_bundle(:) + type(ESMF_Grid),intent(inout) :: fcst_grid + logical,intent(in) :: quilting + integer, intent(in) :: nbdlphys + integer,intent(out) :: rc + + ! + !*** local variables + integer i, idx, ibdl + integer id, axis_length, direction, edges + integer num_attributes + character(255) :: units, long_name, cart_name, axis_direct, edgesS + character(128) :: output_name, physbdl_name, outputfile1 + logical :: lput2physbdl, loutputfile, l2dvector + type(domain1d) :: Domain + type(domainUG) :: DomainU + real,dimension(:),allocatable :: axis_data + character(128),dimension(:), allocatable :: bdl_intplmethod, outputfile + type(diag_atttype),dimension(:),allocatable :: attributes + ! + logical isPresent + integer udimCount + character(80),dimension(:),allocatable :: udimList + character(20),dimension(:), allocatable :: axis_name_vert + ! + !------------------------------------------------------------ + !--- use wrte grid component for output + hist%use_wrtgridcomp_output = quilting + ! if(mpp_pe()==mpp_root_pe())print *,'in fv_phys bundle,use_wrtgridcomp_output=',hist%use_wrtgridcomp_output, & + ! print *,'in fv_phys bundle,use_wrtgridcomp_output=',hist%use_wrtgridcomp_output, & + ! 'hist%isco=',hist%isco,hist%ieco,'hist%jsco=',hist%jsco,hist%jeco,'hist%tot_diag_idx=',hist%tot_diag_idx + ! + !------------------------------------------------------------ + !*** add attributes to the bundle such as subdomain limtis, + !*** axes, output time, etc + !------------------------------------------------------------ + ! + allocate(bdl_intplmethod(nbdlphys), outputfile(nbdlphys)) + if(mpp_pe()==mpp_root_pe()) print *,'in fv_phys bundle,nbdl=',nbdlphys + do ibdl = 1, nbdlphys + loutputfile = .false. + call ESMF_FieldBundleGet(phys_bundle(ibdl), name=physbdl_name,rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + idx = index(physbdl_name,'_bilinear') + if(idx > 0) then + outputfile(ibdl) = physbdl_name(1:idx-1) + bdl_intplmethod(ibdl) = 'bilinear' + loutputfile = .true. + endif + idx = index(physbdl_name,'_nearest_stod') + if(idx > 0) then + outputfile(ibdl) = physbdl_name(1:idx-1) + bdl_intplmethod(ibdl) = 'nearest_stod' + loutputfile = .true. + endif + if( .not. loutputfile) then + outputfile(ibdl) = 'phy' + bdl_intplmethod(ibdl) = 'nearest_stod' + endif + ! print *,'in fv_phys bundle,i=',ibdl,'outputfile=',trim(outputfile(ibdl)), & + ! 'bdl_intplmethod=',trim(bdl_intplmethod(ibdl)) + + call ESMF_AttributeAdd(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & + attrList=(/"fhzero ", "ncld ", "nsoil ",& + "imp_physics", "dtp ", "landsfcmdl "/), rc=rc) + + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & + name="fhzero", value=hist%fhzero, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & + name="ncld", value=hist%ncld, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & + name="nsoil", value=hist%nsoil, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & + name="imp_physics", value=hist%imp_physics, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & + name="dtp", value=hist%dtp, rc=rc) + ! print *,'in fcst gfdl diag, hist%dtp=',hist%dtp,' ibdl=',ibdl + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(phys_bundle(ibdl), convention="NetCDF", purpose="FV3", & + name="landsfcmdl", value=hist%landsfcmdl, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + !end ibdl + enddo + ! + !*** get axis names + allocate(hist%axis_name(hist%num_axes_phys)) + do id = 1,hist%num_axes_phys + call get_diag_axis_name( axes(id), hist%axis_name(id)) + enddo + isPresent = .false. + if( hist%num_axes_phys>2 ) then + allocate(axis_name_vert(hist%num_axes_phys-2)) + do id=3,hist%num_axes_phys + axis_name_vert(id-2) = hist%axis_name(id) + enddo + ! + call ESMF_AttributeGet(fcst_grid, convention="NetCDF", purpose="FV3", & + name="vertical_dim_labels", isPresent=isPresent, & + itemCount=udimCount, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + if (isPresent .and. (udimCount>hist%num_axes_phys-2) ) then + allocate(udimList(udimCount)) + call ESMF_AttributeGet(fcst_grid, convention="NetCDF", purpose="FV3", & + name="vertical_dim_labels", valueList=udimList, rc=rc) + ! if(mpp_pe()==mpp_root_pe()) print *,'in fv3atmio, vertical + ! list=',udimList(1:udimCount),'rc=',rc + + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + else + + if(mpp_pe()==mpp_root_pe()) print *,'in fv_dyn bundle,axis_name_vert=',axis_name_vert + call ESMF_AttributeAdd(fcst_grid, convention="NetCDF", purpose="FV3", & + attrList=(/"vertical_dim_labels"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & + name="vertical_dim_labels", valueList=axis_name_vert, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + endif + deallocate(axis_name_vert) + endif + + !*** add attributes + if(associated(hist%all_axes)) then + deallocate(hist%all_axes) + nullify(hist%all_axes) + endif + allocate(hist%all_axes(hist%num_axes_phys)) + hist%all_axes(1:hist%num_axes_phys) = axes(1:hist%num_axes_phys) + if (.not. isPresent .or. (udimCount2 ) then + ! if(mpp_pe()==mpp_root_pe()) print *,' in dyn add grid, axis_name=', & + ! trim(hist%axis_name(id)),'axis_data=',axis_data + if(trim(edgesS)/='') then + call ESMF_AttributeAdd(fcst_grid, convention="NetCDF", purpose="FV3", & + attrList=(/trim(hist%axis_name(id)),trim(hist%axis_name(id))//":long_name", & + trim(hist%axis_name(id))//":units", trim(hist%axis_name(id))//":cartesian_axis", & + trim(hist%axis_name(id))//":positive", trim(hist%axis_name(id))//":edges"/), rc=rc) + else + call ESMF_AttributeAdd(fcst_grid, convention="NetCDF", purpose="FV3", & + attrList=(/trim(hist%axis_name(id)),trim(hist%axis_name(id))//":long_name", & + trim(hist%axis_name(id))//":units", trim(hist%axis_name(id))//":cartesian_axis", & + trim(hist%axis_name(id))//":positive"/), rc=rc) + endif + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & + name=trim(hist%axis_name(id)), valueList=axis_data, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & + name=trim(hist%axis_name(id))//":long_name", value=trim(long_name), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & + name=trim(hist%axis_name(id))//":units", value=trim(units), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & + name=trim(hist%axis_name(id))//":cartesian_axis", value=trim(cart_name), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + if(direction > 0) then + axis_direct = "up" + else + axis_direct = "down" + endif + call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & + name=trim(hist%axis_name(id))//":positive", value=trim(axis_direct), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + if(trim(edgesS)/='') then + call ESMF_AttributeSet(fcst_grid, convention="NetCDF", purpose="FV3", & + name=trim(hist%axis_name(id))//":edges", value=trim(edgesS), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + endif + + endif + ! + deallocate(axis_data) + enddo + endif + ! print *,'in setup fieldbundle_phys, hist%num_axes_phys=',hist%num_axes_phys,'hist%tot_diag_idx=',hist%tot_diag_idx, & + ! 'nbdlphys=',nbdlphys + ! + !----------------------------------------------------------------------------------------- + !*** add esmf fields + ! + do idx= 1,hist%tot_diag_idx + + lput2physbdl = .false. + do ibdl = 1, nbdlphys + + if( index(trim(Diag(idx)%intpl_method),trim(bdl_intplmethod(ibdl))) > 0) then + lput2physbdl = .true. + if( Diag(idx)%id > 0 ) then + call hist%find_output_name(trim(Diag(idx)%mod_name),trim(Diag(idx)%name),output_name) + + !add origin field + call hist%add_field_to_phybundle(trim(output_name),trim(Diag(idx)%desc),trim(Diag(idx)%unit), "time: point", & + axes(1:Diag(idx)%axes), fcst_grid, hist%nstt(idx), phys_bundle(ibdl), outputfile(ibdl), & + bdl_intplmethod(ibdl), rcd=rc) + ! if( mpp_pe() == mpp_root_pe()) print *,'phys, add field,',trim(Diag(idx)%name),'idx=',idx,'ibdl=',ibdl + ! + if( index(trim(Diag(idx)%intpl_method), "vector") > 0) then + l2dvector = .true. + if (hist%nstt_vctbl(idx) > 0) then + output_name = 'wind'//trim(output_name)//'vector' + outputfile1 = 'none' + call hist%add_field_to_phybundle(trim(output_name),trim(Diag(idx)%desc),trim(Diag(idx)%unit), "time: point", & + axes(1:Diag(idx)%axes), fcst_grid, hist%nstt_vctbl(idx),phys_bundle(ibdl), outputfile1, & + bdl_intplmethod(ibdl),l2dvector=l2dvector, rcd=rc) + ! if( mpp_pe() == mpp_root_pe()) print *,'in phys, add vector field,',trim(Diag(idx)%name),' idx=',idx,' ibdl=',ibdl + endif + endif + + endif + endif + enddo + if( .not. lput2physbdl ) then + if( mpp_pe() == mpp_root_pe()) print *,'WARNING: not matching interpolation method, field ',trim(Diag(idx)%name), & + ' is not added to phys bundle ' + endif + + enddo + deallocate(hist%axis_name) + deallocate(hist%all_axes) + nullify(hist%axis_name) + nullify(hist%all_axes) + + end subroutine history_type_bundle_setup + + !>@brief Adds one field to an ESMF field bundle for later output. Internal subroutine; do not call this directly. + !> \section history_type%add_field_to_phybundle procedure + !! This is part of the internal implementation of history_type_bundle_setup (history_type%bundle_setup). + !! It sets attributes for and logs information about a single ESMF field. Do not call this subroutine directly. + !! Call fv_phys_bundle_setup instead. + subroutine history_type_add_field_to_phybundle(hist,var_name,long_name,units,cell_methods, axes,phys_grid, & + kstt,phys_bundle,output_file,intpl_method,range,l2dvector,rcd) + ! + use esmf + ! + implicit none + class(history_type) :: hist + character(*), intent(in) :: var_name, long_name, units, cell_methods + character(*), intent(in) :: output_file, intpl_method + integer, intent(in) :: axes(:) + type(esmf_grid), intent(in) :: phys_grid + integer, intent(in) :: kstt + type(esmf_fieldbundle),intent(inout) :: phys_bundle + real, intent(in), optional :: range(2) + logical, intent(in), optional :: l2dvector + integer, intent(out), optional :: rcd + ! + !*** local variable + type(ESMF_Field) :: field + type(ESMF_DataCopy_Flag) :: copyflag=ESMF_DATACOPY_REFERENCE + integer rc, i, j, idx + real(4),dimension(:,:),pointer :: temp_r2d + real(4),dimension(:,:,:),pointer :: temp_r3d + logical :: l2dvector_local + ! + ! fix for non-standard compilers (e.g. PGI) + l2dvector_local = .false. + if (present(l2dvector)) then + if (l2dvector) then + l2dvector_local = .true. + end if + end if + ! + !*** create esmf field + if (l2dvector_local .and. size(axes)==2) then + temp_r3d => hist%buffer_phys_windvect(1:3,hist%isco:hist%ieco,hist%jsco:hist%jeco,kstt) + ! if( mpp_root_pe() == 0) print *,'phys, create wind vector esmf field' + call ESMF_LogWrite('bf create winde vector esmf field '//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + !datacopyflag=ESMF_DATACOPY_VALUE, & + field = ESMF_FieldCreate(phys_grid, temp_r3d, datacopyflag=ESMF_DATACOPY_REFERENCE, & + gridToFieldMap=(/2,3/), ungriddedLBound=(/1/), ungriddedUBound=(/3/), & + name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) + + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + call ESMF_LogWrite('af winde vector esmf field create '//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) + + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"output_file"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name='output_file',value=trim(output_file),rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_LogWrite('before winde vector esmf field add output_file', ESMF_LOGMSG_INFO, rc=rc) + + ! if( mpp_root_pe() == 0)print *,'phys, aftercreate wind vector esmf field' + call ESMF_FieldBundleAdd(phys_bundle,(/field/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + if( present(rcd)) rcd=rc + call ESMF_LogWrite('aft winde vector esmf field add to fieldbundle'//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) + return + else if( trim(intpl_method) == 'nearest_stod' ) then + if(size(axes) == 2) then + temp_r2d => hist%buffer_phys_nb(hist%isco:hist%ieco,hist%jsco:hist%jeco,kstt) + field = ESMF_FieldCreate(phys_grid, temp_r2d, datacopyflag=copyflag, & + name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + else if(size(axes) == 3) then + temp_r3d => hist%buffer_phys_nb(hist%isco:hist%ieco,hist%jsco:hist%jeco,kstt:kstt+hist%levo-1) + field = ESMF_FieldCreate(phys_grid, temp_r3d, datacopyflag=copyflag, & + name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + if( mpp_pe() == mpp_root_pe()) print *,'add 3D field to after nearest_stod, fld=', trim(var_name) + endif + else if( trim(intpl_method) == 'bilinear' ) then + if(size(axes) == 2) then + temp_r2d => hist%buffer_phys_bl(hist%isco:hist%ieco,hist%jsco:hist%jeco,kstt) + field = ESMF_FieldCreate(phys_grid, temp_r2d, datacopyflag=copyflag, & + name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + else if(size(axes) == 3) then + temp_r3d => hist%buffer_phys_bl(hist%isco:hist%ieco,hist%jsco:hist%jeco,kstt:kstt+hist%levo-1) + field = ESMF_FieldCreate(phys_grid, temp_r3d, datacopyflag=copyflag, & + name=var_name, indexFlag=ESMF_INDEX_DELOCAL, rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + if( mpp_pe() == mpp_root_pe()) print *,'add field to after bilinear, fld=', trim(var_name) + endif + endif + ! + !*** add field attributes + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"long_name"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name='long_name',value=trim(long_name),rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"units"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name='units',value=trim(units),rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"missing_value"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name='missing_value',value=real(missing_value,kind=4),rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"_FillValue"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name='_FillValue',value=real(missing_value,kind=4),rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"cell_methods"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name='cell_methods',value=trim(cell_methods),rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + ! + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"output_file"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name='output_file',value=trim(output_file),rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, & + line=__LINE__, file=__FILE__)) call ESMF_Finalize(endflag=ESMF_END_ABORT) + + ! + !*** add vertical coord attribute: + if( size(axes) > 2) then + do i=3,size(axes) + idx=0 + do j=1,size(hist%all_axes) + if (axes(i)==hist%all_axes(j)) then + idx=j + exit + endif + enddo + if (idx>0) then + call ESMF_AttributeAdd(field, convention="NetCDF", purpose="FV3", & + attrList=(/"ESMF:ungridded_dim_labels"/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + call ESMF_AttributeSet(field, convention="NetCDF", purpose="FV3", & + name="ESMF:ungridded_dim_labels", valueList=(/trim(hist%axis_name(idx))/), rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + endif + enddo + endif + + !*** add field into bundle + call ESMF_FieldBundleAdd(phys_bundle,(/field/), rc=rc) + if( present(rcd)) rcd=rc + ! + call ESMF_LogWrite('phys field add to fieldbundle '//trim(var_name), ESMF_LOGMSG_INFO, rc=rc) + + end subroutine history_type_add_field_to_phybundle + + !>@brief Private subroutine to search a field list for a specific name. + !> \section history_type%find_output_name procedure + !! Searches the GFS_Diagnostic-generated field list for a + !! specific name and retrieves the name that should be used for + !! outputting the variable. This is part of the internal + !! implementation of history_type_bundle_setup + !! (history_type%bundle_setup) and should not be called + !! directly. Call fv_phys_bundle_setup instead. + subroutine history_type_find_output_name(hist,module_name,field_name,output_name) + implicit none + class(history_type) :: hist + character(*), intent(in) :: module_name + character(*), intent(in) :: field_name + character(*), intent(out) :: output_name + ! + integer i,in_num + integer tile_count + ! + tile_count = 1 + in_num = find_input_field(module_name, field_name, tile_count) + ! + output_name = '' + do i=1, max_output_fields + if(output_fields(i)%input_field == in_num) then + output_name = output_fields(i)%output_name + exit + endif + enddo + if(output_name == '') then +19 format("Error: can't find output name for model field ",'"',A,'"') + print 19,trim(field_name) + endif + + end subroutine history_type_find_output_name +#endif + !------------------------------------------------------------------------- + +end module fv3atm_history_io_mod +!> @} diff --git a/io/fv3atm_oro_io.F90 b/io/fv3atm_oro_io.F90 new file mode 100644 index 000000000..493cfd4c4 --- /dev/null +++ b/io/fv3atm_oro_io.F90 @@ -0,0 +1,333 @@ +!> \file fv3atm_oro_io.F90 +!! This file defines routines to read orography files for the fv3atm. +module fv3atm_oro_io + + use block_control_mod, only: block_control_type + use fms2_io_mod, only: FmsNetcdfDomainFile_t, & + register_axis, register_restart_field + use fv3atm_common_io, only: get_nx_ny_from_atm + use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, kind_phys + + implicit none + private + + public :: Oro_io_data_type, Oro_io_register, Oro_io_copy, Oro_io_final + public :: Oro_scale_io_data_type, Oro_scale_io_register, Oro_scale_io_copy, Oro_scale_io_final + + !>\defgroup fv3atm_oro_io FV3ATM Orography I/O Module + !> @{ + !>@ Storage of working arrays for reading orography data. + type Oro_io_data_type + character(len=32), pointer, private, dimension(:) :: name2 => null() + real(kind=kind_phys), pointer, private, dimension(:,:,:) :: var2 => null() + real(kind=kind_phys), pointer, private, dimension(:,:,:) :: var3v => null() + real(kind=kind_phys), pointer, private, dimension(:,:,:) :: var3s => null() + contains + procedure, public :: register => Oro_io_register + procedure, public :: copy => Oro_io_copy + final :: Oro_io_final + end type Oro_io_data_type + + !>@ Storage of working arrays for reading large-scale and small-scale orography data for gravity wave drag schemes. + type Oro_scale_io_data_type + character(len=32), pointer, private, dimension(:) :: name => null() + real(kind=kind_phys), pointer, private, dimension(:,:,:) :: var => null() + contains + procedure, public :: register => Oro_scale_io_register + procedure, public :: copy => Oro_scale_io_copy + final :: Oro_scale_io_final + end type Oro_scale_io_data_type + + !>@ Number of two-dimensional orography fields (excluding large- and small-scale) + integer, parameter :: nvar_oro_2d = 19 + + !>@ Number of large-scale and small-scale orography fields + integer, parameter :: nvar_oro_scale = 10 + +contains + + !>@brief Registers axes and fields for non-quilt restart reading of non-scaled orography variables. + !> \section oro_io_data_type%register procedure + !! Calls FMS restart register functions for axes and + !! variables in the non-scaled orography data. The scaled data is + !! handled by another function. This includes both 2D and 3D fields. + subroutine Oro_io_register(oro, Model, Oro_restart, Atm_block) + implicit none + class(Oro_io_data_type) :: oro + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Oro_restart + type(block_control_type), intent(in) :: Atm_block + + real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_fr => NULL() + integer :: nx, ny + + integer :: nvar_vegfr, nvar_soilfr, n, num + + call get_nx_ny_from_atm(Atm_block, nx, ny) + + ! This #define reduces code length by a lot +#define WARN_DISASSOCIATE(name) \ + if(associated(name)) then ; \ + write(0,*) 'Internal error. Called oro%register twice. Will try to keep going anyway.' ; \ + deallocate(name); \ + nullify(name) ; \ + endif + + WARN_DISASSOCIATE(oro%name2) + WARN_DISASSOCIATE(oro%var2) + WARN_DISASSOCIATE(oro%var3v) + WARN_DISASSOCIATE(oro%var3s) +#undef WARN_DISASSOCIATE + + nvar_vegfr = Model%nvegcat + nvar_soilfr = Model%nsoilcat + + allocate(oro%name2(nvar_oro_2d)) + allocate(oro%var2(nx,ny,nvar_oro_2d)) + + allocate(oro%var3v(nx,ny,nvar_vegfr)) + allocate(oro%var3s(nx,ny,nvar_soilfr)) + + oro%var2 = -9999._kind_phys + + num = 1 ; oro%name2(num) = 'stddev' ! hprime(ix,1) + num = num + 1 ; oro%name2(num) = 'convexity' ! hprime(ix,2) + num = num + 1 ; oro%name2(num) = 'oa1' ! hprime(ix,3) + num = num + 1 ; oro%name2(num) = 'oa2' ! hprime(ix,4) + num = num + 1 ; oro%name2(num) = 'oa3' ! hprime(ix,5) + num = num + 1 ; oro%name2(num) = 'oa4' ! hprime(ix,6) + num = num + 1 ; oro%name2(num) = 'ol1' ! hprime(ix,7) + num = num + 1 ; oro%name2(num) = 'ol2' ! hprime(ix,8) + num = num + 1 ; oro%name2(num) = 'ol3' ! hprime(ix,9) + num = num + 1 ; oro%name2(num) = 'ol4' ! hprime(ix,10) + num = num + 1 ; oro%name2(num) = 'theta' ! hprime(ix,11) + num = num + 1 ; oro%name2(num) = 'gamma' ! hprime(ix,12) + num = num + 1 ; oro%name2(num) = 'sigma' ! hprime(ix,13) + num = num + 1 ; oro%name2(num) = 'elvmax' ! hprime(ix,14) + num = num + 1 ; oro%name2(num) = 'orog_filt' ! oro + num = num + 1 ; oro%name2(num) = 'orog_raw' ! oro_uf + num = num + 1 ; oro%name2(num) = 'land_frac' ! land fraction [0:1] + !--- variables below here are optional + num = num + 1 ; oro%name2(num) = 'lake_frac' ! lake fraction [0:1] + num = num + 1 ; oro%name2(num) = 'lake_depth' ! lake depth(m) + + !--- register axis + call register_axis( Oro_restart, "lon", 'X' ) + call register_axis( Oro_restart, "lat", 'Y' ) + !--- register the 2D fields + do n = 1,num + var2_p => oro%var2(:,:,n) + if (trim(oro%name2(n)) == 'lake_frac' .or. trim(oro%name2(n)) == 'lake_depth' ) then + call register_restart_field(Oro_restart, oro%name2(n), var2_p, dimensions=(/'lat','lon'/), is_optional=.true.) + else + call register_restart_field(Oro_restart, oro%name2(n), var2_p, dimensions=(/'lat','lon'/)) + endif + enddo + + !--- register 3D vegetation and soil fractions + var3_fr => oro%var3v(:,:,:) + call register_restart_field(Oro_restart, 'vegetation_type_pct', var3_fr, dimensions=(/'num_veg_cat','lat ','lon '/) , is_optional=.true.) + var3_fr => oro%var3s(:,:,:) + call register_restart_field(Oro_restart, 'soil_type_pct', var3_fr, dimensions=(/'num_soil_cat','lat ','lon '/) , is_optional=.true.) + + end subroutine Oro_io_register + + !>@brief Copies orography data from temporary arrays back to Sfcprop grid arrays. + !> \section oro_io_data_type%copy procedure + !! After reading the restart, data is on temporary arrays with x-y data storage. + !! This subroutine copies the x-y fields to Sfcprop's blocked grid storage arrays. + subroutine Oro_io_copy(oro, Model, Sfcprop, Atm_block) + implicit none + class(Oro_io_data_type) :: oro + type(GFS_control_type), intent(in) :: Model + type(GFS_sfcprop_type) :: Sfcprop(:) + type(FmsNetcdfDomainFile_t) :: Oro_restart + type(block_control_type), intent(in) :: Atm_block + + integer :: i,j,nb,ix,num + + !$omp parallel do default(shared) private(i, j, nb, ix, num) + do nb = 1, Atm_block%nblks + !--- 2D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + !--- stddev + ! Sfcprop(nb)%hprim(ix) = oro%var2(i,j,1) + !--- hprime(1:14) + num = 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%hprime(ix,num) = oro%var2(i,j,num) + !--- oro + num = num + 1 ; Sfcprop(nb)%oro(ix) = oro%var2(i,j,num) + num = num + 1 ; Sfcprop(nb)%oro_uf(ix) = oro%var2(i,j,num) + + Sfcprop(nb)%landfrac(ix) = -9999.0 + Sfcprop(nb)%lakefrac(ix) = -9999.0 + + num = num + 1 ; Sfcprop(nb)%landfrac(ix) = oro%var2(i,j,num) !land frac [0:1] + if (Model%lkm > 0 ) then + if(oro%var2(i,j,num+1)>Model%lakefrac_threshold .and. & + oro%var2(i,j,num+2)>Model%lakedepth_threshold) then + Sfcprop(nb)%lakefrac(ix) = oro%var2(i,j,num+1) !lake frac [0:1] + Sfcprop(nb)%lakedepth(ix) = oro%var2(i,j,num+2) !lake depth [m] !YWu + else + Sfcprop(nb)%lakefrac(ix) = 0 + Sfcprop(nb)%lakedepth(ix) = -9999 + endif + else + Sfcprop(nb)%lakefrac(ix) = oro%var2(i,j,num+1) !lake frac [0:1] + Sfcprop(nb)%lakedepth(ix) = oro%var2(i,j,num+2) !lake depth [m] !YWu + endif + num = num + 2 ! To account for lakefrac and lakedepth + + Sfcprop(nb)%vegtype_frac(ix,:) = -9999.0 + Sfcprop(nb)%soiltype_frac(ix,:) = -9999.0 + + Sfcprop(nb)%vegtype_frac(ix,:) = oro%var3v(i,j,:) ! vegetation type fractions, [0:1] + Sfcprop(nb)%soiltype_frac(ix,:) = oro%var3s(i,j,:) ! soil type fractions, [0:1] + + enddo + enddo + + !--- deallocate containers and free restart container + deallocate(oro%name2) + deallocate(oro%var2) + deallocate(oro%var3v) + deallocate(oro%var3s) + + nullify(oro%name2) + nullify(oro%var2) + nullify(oro%var3v) + nullify(oro%var3s) + + end subroutine Oro_io_copy + + !>@brief Destructor for Oro_io_data_type + subroutine Oro_io_final(oro) + implicit none + type(Oro_io_data_type) :: oro + + ! This #define reduces code length by a lot +#define IF_ASSOC_DEALLOC_NULL(var) \ + if(associated(oro%var)) then ; \ + deallocate(oro%var) ; \ + nullify(oro%var) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(name2) + IF_ASSOC_DEALLOC_NULL(var2) + IF_ASSOC_DEALLOC_NULL(var3s) + IF_ASSOC_DEALLOC_NULL(var3v) + +#undef IF_ASSOC_DEALLOC_NULL + end subroutine Oro_io_final + + !>@brief Registers axes and fields for non-quilt restart reading of scaled orography variables. + !> \section Calls FMS restart register functions for axes and + !! variables in the large-scale or small-scale orography data. The + !! scaled data is handled by another function. Each scale needs its + !! own instance of oro_scale_io_data_type. + subroutine Oro_scale_io_register(oro_scale, Model, Oro_scale_restart, Atm_block) + implicit none + class(Oro_scale_io_data_type) :: oro_scale + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Oro_scale_restart + type(block_control_type), intent(in) :: Atm_block + + real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() + integer :: num, nx, ny + +#define WARN_DISASSOCIATE(name) \ + if(associated(name)) then ; \ + write(0,*) 'Internal error. Called oro_scale%register twice. Will try to keep going anyway.' ; \ + deallocate(name); \ + nullify(name) ; \ + endif + + WARN_DISASSOCIATE(oro_scale%name) + WARN_DISASSOCIATE(oro_scale%var) +#undef WARN_DISASSOCIATE + + call get_nx_ny_from_atm(Atm_block, nx, ny) + + !--- allocate the various containers needed for orography data + allocate(oro_scale%name(nvar_oro_scale)) + allocate(oro_scale%var(nx,ny,nvar_oro_scale)) + + oro_scale%name(1) = 'stddev' + oro_scale%name(2) = 'convexity' + oro_scale%name(3) = 'oa1' + oro_scale%name(4) = 'oa2' + oro_scale%name(5) = 'oa3' + oro_scale%name(6) = 'oa4' + oro_scale%name(7) = 'ol1' + oro_scale%name(8) = 'ol2' + oro_scale%name(9) = 'ol3' + oro_scale%name(10) = 'ol4' + + call register_axis(Oro_scale_restart, "lon", 'X') + call register_axis(Oro_scale_restart, "lat", 'Y') + + do num = 1,nvar_oro_scale + var2_p => oro_scale%var(:,:,num) + call register_restart_field(Oro_scale_restart, oro_scale%name(num), var2_p, dimensions=(/'lon','lat'/)) + enddo + end subroutine Oro_scale_io_register + + !>@brief Copies scaled orography data from temporary arrays back to Sfcprop grid arrays. + !> \section Oro_scale_io_data_type%copy procedure + !! After reading the restart, data is on temporary arrays with x-y data storage. + !! This subroutine copies the x-y fields to Sfcprop's blocked grid storage arrays. + subroutine Oro_scale_io_copy(oro_scale, Sfcprop, Atm_block, first_index) + implicit none + class(Oro_scale_io_data_type) :: oro_scale + type(GFS_sfcprop_type) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + integer, intent(in) :: first_index + + integer :: i,j,nb,ix,num,v + + !$OMP PARALLEL DO PRIVATE(nb,ix,i,j,v) + do nb = 1, Atm_block%nblks + !--- 2D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + do v=1,nvar_oro_scale + Sfcprop(nb)%hprime(ix,first_index-1+v) = oro_scale%var(i,j,v) + enddo + enddo + enddo + end subroutine Oro_scale_io_copy + + !>@brief Oro_scale_io_data_type destructor + subroutine Oro_scale_io_final(oro_scale) + implicit none + type(Oro_scale_io_data_type) :: oro_scale + +#define IF_ASSOC_DEALLOC_NULL(vvarr) \ + if(associated(oro_scale%vvarr)) then ; \ + deallocate(oro_scale%vvarr) ; \ + nullify(oro_scale%vvarr) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(name) + IF_ASSOC_DEALLOC_NULL(var) + +#undef IF_ASSOC_DEALLOC_NULL + end subroutine Oro_scale_io_final +end module fv3atm_oro_io +!> @} diff --git a/io/fv3atm_restart_io.F90 b/io/fv3atm_restart_io.F90 new file mode 100644 index 000000000..d5cfb9734 --- /dev/null +++ b/io/fv3atm_restart_io.F90 @@ -0,0 +1,1282 @@ +!> \file fv3atm_restart_io.F90 +!! This file contains the restart reading and writing code, for quilt and non-quilt +!! of the Sfcprop and physics data. + +module fv3atm_restart_io_mod + + use block_control_mod, only: block_control_type + use mpp_mod, only: mpp_error, mpp_chksum, NOTE, FATAL + use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, kind_phys, GFS_data_type + use GFS_restart, only: GFS_restart_type + use fms_mod, only: stdout + use fms2_io_mod, only: FmsNetcdfDomainFile_t, unlimited, & + open_file, close_file, & + register_axis, register_restart_field, & + register_variable_attribute, register_field, & + read_restart, write_restart, write_data, & + get_global_io_domain_indices + use mpp_domains_mod, only: domain2d + use fv3atm_common_io, only: create_2d_field_and_add_to_bundle, & + create_3d_field_and_add_to_bundle, copy_from_gfs_data + use fv3atm_sfc_io + use fv3atm_rrfs_sd_io + use fv3atm_clm_lake_io + use fv3atm_oro_io + + implicit none + private + + public fv3atm_checksum + public fv3atm_restart_read + public fv3atm_restart_write + public fv3atm_restart_register + public fv_phy_restart_output + public fv_phy_restart_bundle_setup + public fv_sfc_restart_output + public fv_sfc_restart_bundle_setup + + !>\defgroup fv3atm_restart_io_mod module + !> @{ + + !>@Internal storage for reading and writing physics restart files. + type phy_data_type + real(kind=kind_phys), pointer, dimension(:,:,:) :: var2 => null() + real(kind=kind_phys), pointer, dimension(:,:,:,:) :: var3 => null() + character(len=32),dimension(:),pointer :: var2_names => null() + character(len=32),dimension(:),pointer :: var3_names => null() + integer :: nvar2d = 0, nvar3d = 0, npz = 0 + contains + procedure :: alloc => phy_data_alloc + procedure :: transfer_data => phy_data_transfer_data + final phy_data_final + end type phy_data_type + + !--- GFDL filenames + + !>@ Filename template for orography data. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_oro = 'oro_data.nc' + + !>@ Filename template for gravity wave drag large-scale orography data. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_oro_ls = 'oro_data_ls.nc' + + !>@ Filename template for gravity wave drag small-scale orography data. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_oro_ss = 'oro_data_ss.nc' + + !>@ Filename template for surface data that doesn't fall under other categories. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_srf = 'sfc_data.nc' + + !>@ Filename template for physics diagnostic data. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_phy = 'phy_data.nc' + + !>@ Filename template for monthly dust data for RRFS_SD. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_dust12m= 'dust12m_data.nc' + + !>@ Filename template for RRFS-SD emissions data. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_emi = 'emi_data.nc' + + !>@ Filename template for RRFS-SD smoke data. FMS may add grid and tile information to the name + character(len=32), parameter :: fn_rrfssd = 'SMOKE_RRFS_data.nc' + + real(kind_phys), parameter:: zero = 0.0, one = 1.0 + + !>@ Instance of phy_data_type for quilt output of physics diagnostic data + type(phy_data_type) :: phy_quilt + + !>@ Instance of clm_lake_data_type for quilt output of CLM Lake model restart data + type(clm_lake_data_type) :: clm_lake_quilt + + !>@ Instance of Sfc_io_data_type for quilt output of surface restart data + type(Sfc_io_data_type) :: sfc_quilt + + !>@ Instance of rrfs_sd_state_type for quilt output of RRFS-SD scheme restart data + type(rrfs_sd_state_type) :: rrfs_sd_quilt + +contains + + !>@brief Reads physics and surface fields. + !> \section fv3atm_restart_read subroutine + !! Calls sfc_prop_restart_read and phys_restart_read to read all surface and physics restart files. + subroutine fv3atm_restart_read (GFS_Data, GFS_Restart, Atm_block, Model, fv_domain, warm_start, ignore_rst_cksum) + implicit none + type(GFS_data_type), intent(inout) :: GFS_Data(:) + type(GFS_restart_type), intent(inout) :: GFS_Restart + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(inout) :: Model + type(domain2d), intent(in) :: fv_domain + logical, intent(in) :: warm_start + logical, intent(in) :: ignore_rst_cksum + + !--- read in surface data from chgres + call sfc_prop_restart_read (GFS_Data%Sfcprop, Atm_block, Model, fv_domain, warm_start, ignore_rst_cksum) + + !--- read in physics restart data + call phys_restart_read (GFS_Restart, Atm_block, Model, fv_domain, ignore_rst_cksum) + + end subroutine fv3atm_restart_read + + !>@brief Writes surface and physics restart fields without using the write component (quilt). + !> \section fv3atm_restart_write subroutine + !! Calls sfc_prop_restart_write and phys_restart_write to write + !! surface and physics restart fields. This pauses the model to + !! write; it does not use the write component (quilt). + subroutine fv3atm_restart_write (GFS_Data, GFS_Restart, Atm_block, Model, fv_domain, timestamp) + implicit none + type(GFS_data_type), intent(inout) :: GFS_Data(:) + type(GFS_restart_type), intent(inout) :: GFS_Restart + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + type(domain2d), intent(in) :: fv_domain + character(len=32), optional, intent(in) :: timestamp + + !--- write surface data from chgres + call sfc_prop_restart_write (GFS_Data%Sfcprop, Atm_block, Model, fv_domain, timestamp) + + !--- write physics restart data + call phys_restart_write (GFS_Restart, Atm_block, Model, fv_domain, timestamp) + + end subroutine fv3atm_restart_write + + !---------------- + ! fv3atm_checksum + !---------------- + subroutine fv3atm_checksum (Model, GFS_Data, Atm_block) + implicit none + !--- interface variables + type(GFS_control_type), intent(in) :: Model + type(GFS_data_type), intent(in) :: GFS_Data(:) + type (block_control_type), intent(in) :: Atm_block + !--- local variables + integer :: outunit, i, ix, nb, isc, iec, jsc, jec, lev, ntr, k + integer :: nsfcprop2d, nt + real(kind=kind_phys), allocatable :: temp2d(:,:,:) + real(kind=kind_phys), allocatable :: temp3d(:,:,:,:) + real(kind=kind_phys), allocatable :: temp3dlevsp1(:,:,:,:) + integer, allocatable :: ii1(:), jj1(:) + character(len=32) :: name + + isc = Model%isc + iec = Model%isc+Model%nx-1 + jsc = Model%jsc + jec = Model%jsc+Model%ny-1 + lev = Model%levs + + ntr = size(GFS_Data(1)%Statein%qgrs,3) + + nsfcprop2d = 93 + if (Model%lsm == Model%lsm_noahmp) then + nsfcprop2d = nsfcprop2d + 49 + if (Model%use_cice_alb) then + nsfcprop2d = nsfcprop2d + 4 + endif + elseif (Model%lsm == Model%lsm_ruc) then + nsfcprop2d = nsfcprop2d + 4 + 12 + if (Model%rdlai) then + nsfcprop2d = nsfcprop2d + 1 + endif + else + if (Model%use_cice_alb) then + nsfcprop2d = nsfcprop2d + 4 + endif + endif + + if (Model%nstf_name(1) > 0) then + nsfcprop2d = nsfcprop2d + 16 + endif + + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + nsfcprop2d = nsfcprop2d + 10 + endif + + allocate (temp2d(isc:iec,jsc:jec,nsfcprop2d+Model%ntot2d+Model%nctp)) + allocate (temp3d(isc:iec,jsc:jec,1:lev,14+Model%ntot3d+2*ntr)) + allocate (temp3dlevsp1(isc:iec,jsc:jec,1:lev+1,3)) + + temp2d = zero + temp3d = zero + temp3dlevsp1 = zero + + !$omp parallel do default(shared) private(i, k, nb, ix, nt, ii1, jj1) + block_loop: do nb = 1, Atm_block%nblks + allocate(ii1(Atm_block%blksz(nb))) + allocate(jj1(Atm_block%blksz(nb))) + ii1=Atm_block%index(nb)%ii - isc + 1 + jj1=Atm_block%index(nb)%jj - jsc + 1 + + ! Copy into temp2d + nt=0 + + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Statein%pgr) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%slmsk) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsfc) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tisfc) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zorl) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%fice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%hprime(:,1)) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sncovr) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snoalb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alvsf) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alnsf) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alvwf) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alnwf) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%facsf) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%facwf) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%slope) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%shdmin) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%shdmax) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tg3) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%vfrac) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%vtype) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stype) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%uustar) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%oro) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%oro_uf) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%hice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%weasd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%canopy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%ffmm) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%ffhh) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%f10m) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tprcp) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%srflag) + lsm_choice: if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%slc) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smc) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stc) + elseif (Model%lsm == Model%lsm_ruc) then + do k=1,3 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sh2o(:,k)) + enddo + ! Combine levels 4 to lsoil_lsm (9 for RUC) into one + nt=nt+1 + do ix=1,Atm_block%blksz(nb) + temp2d(ii1(ix),jj1(ix),nt) = sum(GFS_Data(nb)%Sfcprop%sh2o(ix,4:Model%lsoil_lsm)) + enddo + do k=1,3 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smois(:,k)) + enddo + ! Combine levels 4 to lsoil_lsm (9 for RUC) into one + nt=nt+1 + do ix=1,Atm_block%blksz(nb) + temp2d(ii1(ix),jj1(ix),nt) = sum(GFS_Data(nb)%Sfcprop%smois(ix,4:Model%lsoil_lsm)) + enddo + do k=1,3 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tslb(:,k)) + enddo + ! Combine levels 4 to lsoil_lsm (9 for RUC) into one + nt=nt+1 + do ix=1,Atm_block%blksz(nb) + temp2d(ii1(ix),jj1(ix),nt) = sum(GFS_Data(nb)%Sfcprop%tslb(ix,4:Model%lsoil_lsm)) + enddo + endif lsm_choice + + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t2m) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%q2m) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirbmdi) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirdfdi) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visbmdi) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visdfdi) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirbmui) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%nirdfui) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visbmui) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%visdfui) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%sfcdsw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%sfcnsw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Coupling%sfcdlw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%xlon) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%xlat) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%xlat_d) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%sinlat) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%coslat) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%area) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%dx) + if (Model%ntoz > 0) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%ddy_o3) + endif + if (Model%h2o_phys) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Grid%ddy_h) + endif + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Cldprop%cv) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Cldprop%cvt) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Cldprop%cvb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%sfalb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%coszen) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%tsflw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%semis) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Radtend%coszdg) + + ! Radtend%sfcfsw is an array of derived type, so we copy all + ! eight elements of the type in one loop + do ix=1,Atm_block%blksz(nb) + temp2d(ii1(ix),jj1(ix),nt+1) = GFS_Data(nb)%Radtend%sfcfsw(ix)%upfxc + temp2d(ii1(ix),jj1(ix),nt+2) = GFS_Data(nb)%Radtend%sfcfsw(ix)%upfx0 + temp2d(ii1(ix),jj1(ix),nt+3) = GFS_Data(nb)%Radtend%sfcfsw(ix)%dnfxc + temp2d(ii1(ix),jj1(ix),nt+4) = GFS_Data(nb)%Radtend%sfcfsw(ix)%dnfx0 + temp2d(ii1(ix),jj1(ix),nt+5) = GFS_Data(nb)%Radtend%sfcflw(ix)%upfxc + temp2d(ii1(ix),jj1(ix),nt+6) = GFS_Data(nb)%Radtend%sfcflw(ix)%upfx0 + temp2d(ii1(ix),jj1(ix),nt+7) = GFS_Data(nb)%Radtend%sfcflw(ix)%dnfxc + temp2d(ii1(ix),jj1(ix),nt+8) = GFS_Data(nb)%Radtend%sfcflw(ix)%dnfx0 + enddo + nt = nt + 8 + + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tiice(:,1)) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tiice(:,2)) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirvis_lnd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirnir_lnd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifvis_lnd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifnir_lnd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%emis_lnd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%emis_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sncovr_ice) + + if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirvis_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdirnir_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifvis_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%albdifnir_ice) + endif + + lsm_choice_2: if (Model%lsm == Model%lsm_noahmp) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tvxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tgxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%canicexy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%canliqxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%eahxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tahxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%cmxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%chxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%fwetxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sneqvoxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%alboldxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qsnowxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%wslakexy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zwtxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%waxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%wtxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%lfmassxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%rtmassxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stmassxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%woodxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%stblcpxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%fastcpxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xsaixy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xlaixy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%taussxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smcwtdxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%deeprechxy) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%rechxy) + + ! These five arrays use bizarre indexing, so we use loops: + do k=-2,0 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snicexy(:,k)) + enddo + + do k=-2,0 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snliqxy(:,k)) + enddo + + do k=-2,0 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsnoxy(:,k)) + enddo + + do k=1,4 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%smoiseq(:,k)) + enddo + + do k=-2,4 + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zsnsoxy(:,k)) + enddo + elseif (Model%lsm == Model%lsm_ruc) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%wetness) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%clw_surf_land) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%clw_surf_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qwv_surf_land) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qwv_surf_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsnow_land) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tsnow_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowfallac_land) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%snowfallac_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sfalb_lnd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sfalb_lnd_bck) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%sfalb_ice) + if (Model%rdlai) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xlaixy) + endif + endif lsm_choice_2 + + nstf_name_choice: if (Model%nstf_name(1) > 0) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%tref) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%z_c) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%c_0) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%c_d) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%w_0) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%w_d) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xt) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xs) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xu) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xz) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%zm) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xtts) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%xzts) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%ifd) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%dt_cool) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%qrain) + endif nstf_name_choice + + ! Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%T_snow) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%T_ice) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%h_ML) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_ML) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_mnw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%h_talb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_talb) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_bot1) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%t_bot2) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Sfcprop%c_t) + endif + + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Tbd%phy_f2d) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp2d,GFS_Data(nb)%Tbd%phy_fctd) + + ! Copy to temp3dlevsp1 + nt=0 + + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3dlevsp1, GFS_Data(nb)%Statein%phii) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3dlevsp1, GFS_Data(nb)%Statein%prsi) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3dlevsp1, GFS_Data(nb)%Statein%prsik) + + ! Copy to temp3d + nt=0 + + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%phil) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%prsl) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%prslk) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%ugrs) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%vgrs) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%vvl) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%tgrs) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gu0) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gv0) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gt0) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%htrsw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%htrlw) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%swhc) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Radtend%lwhc) + do k = 1,Model%ntot3d + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Tbd%phy_f3d(:,:,k)) + enddo + do k = 1,ntr + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Statein%qgrs(:,:,k)) + call copy_from_GFS_Data(ii1,jj1,isc,jsc,nt,temp3d,GFS_Data(nb)%Stateout%gq0(:,:,k)) + enddo + enddo block_loop + + + outunit = stdout() + do i = 1,nsfcprop2d+Model%ntot2d+Model%nctp + write (name, '(i3.3,3x,4a)') i, ' 2d ' + write(outunit,100) name, mpp_chksum(temp2d(:,:,i:i)) + enddo + do i = 1,3 + write (name, '(i2.2,3x,4a)') i, ' 3d levsp1' + write(outunit,100) name, mpp_chksum(temp3dlevsp1(:,:,:,i:i)) + enddo + do i = 1,14+Model%ntot3d+2*ntr + write (name, '(i2.2,3x,4a)') i, ' 3d levs' + write(outunit,100) name, mpp_chksum(temp3d(:,:,:,i:i)) + enddo +100 format("CHECKSUM::",A32," = ",Z20) + + deallocate(temp2d) + deallocate(temp3d) + deallocate(temp3dlevsp1) + end subroutine fv3atm_checksum + + !>@brief Reads surface, orography, CLM Lake, and RRFS-SD data. + !> \section sfc_prop_restart_read subroutine + !! Creates and populates a data type which is then used to "register" + !! restart variables with the FMS restart subsystem. + !! Calls an FMS routine to restore the data from a restart file. + !! Also calculates sncovr if it is not present in the restart file. + subroutine sfc_prop_restart_read (Sfcprop, Atm_block, Model, fv_domain, warm_start, ignore_rst_cksum) + use fv3atm_rrfs_sd_io + implicit none + !--- interface variable definitions + type(GFS_sfcprop_type), intent(inout) :: Sfcprop(:) + type (block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(inout) :: Model + type (domain2d), intent(in) :: fv_domain + logical, intent(in) :: warm_start + logical, intent(in) :: ignore_rst_cksum + !--- directory of the input files + character(5) :: indir='INPUT' + character(37) :: infile + !--- fms2_io file open logic + logical :: amiopen + logical :: override_frac_grid + + type(clm_lake_data_type) :: clm_lake + type(rrfs_sd_state_type) :: rrfs_sd_state + type(rrfs_sd_emissions_type) :: rrfs_sd_emis + type(Oro_scale_io_data_type) :: oro_ss + type(Oro_scale_io_data_type) :: oro_ls + type(Sfc_io_data_type) :: sfc + type(Oro_io_data_type) :: oro + + type(FmsNetcdfDomainFile_t) :: Oro_restart, Sfc_restart, dust12m_restart, emi_restart, rrfssd_restart + type(FmsNetcdfDomainFile_t) :: Oro_ls_restart, Oro_ss_restart + + !--- OROGRAPHY FILE + + !--- open file + infile=trim(indir)//'/'//trim(fn_oro) + amiopen=open_file(Oro_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file '//trim(infile) ) + + call oro%register(Model,Oro_restart,Atm_block) + + !--- read the orography restart/data + call mpp_error(NOTE,'reading topographic/orographic information from INPUT/oro_data.tile*.nc') + call read_restart(Oro_restart, ignore_checksum=ignore_rst_cksum) + call close_file(Oro_restart) + + !--- copy data into GFS containers + call oro%copy(Model, Sfcprop, Atm_block) + + if_smoke: if(Model%rrfs_sd) then ! for RRFS-SD + + !--- Dust input FILE + !--- open file + infile=trim(indir)//'/'//trim(fn_dust12m) + amiopen=open_file(dust12m_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) + + !--- Register axes and variables, allocate memory: + call rrfs_sd_emis%register_dust12m(dust12m_restart, Atm_block) + + !--- read new GSL created dust12m restart/data + call mpp_error(NOTE,'reading dust12m information from INPUT/dust12m_data.tile*.nc') + call read_restart(dust12m_restart) + call close_file(dust12m_restart) + + !--- Copy to Sfcprop and free temporary arrays: + call rrfs_sd_emis%copy_dust12m(Sfcprop, Atm_block) + + !---------------------------------------------- + + !--- open anthropogenic emission file + infile=trim(indir)//'/'//trim(fn_emi) + amiopen=open_file(emi_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) + + ! Register axes and variables, allocate memory + call rrfs_sd_emis%register_emi(emi_restart, Atm_block) + + !--- read anthropogenic emi restart/data + call mpp_error(NOTE,'reading emi information from INPUT/emi_data.tile*.nc') + call read_restart(emi_restart) + call close_file(emi_restart) + + !--- Copy to Sfcprop and free temporary arrays: + call rrfs_sd_emis%copy_emi(Sfcprop, Atm_block) + + !---------------------------------------------- + + !--- Dust input FILE + !--- open file + infile=trim(indir)//'/'//trim(fn_rrfssd) + amiopen=open_file(rrfssd_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if (.not.amiopen) call mpp_error( FATAL, 'Error with opening file'//trim(infile) ) + + ! Register axes and variables, allocate memory + call rrfs_sd_emis%register_fire(rrfssd_restart, Atm_block) + + !--- read new GSL created rrfssd restart/data + call mpp_error(NOTE,'reading rrfssd information from INPUT/SMOKE_RRFS_data.nc') + call read_restart(rrfssd_restart) + call close_file(rrfssd_restart) + + !--- Copy to Sfcprop and free temporary arrays: + call rrfs_sd_emis%copy_fire(Sfcprop, Atm_block) + + endif if_smoke ! RRFS_SD + + !--- Modify/read-in additional orographic static fields for GSL drag suite + if (Model%gwd_opt==3 .or. Model%gwd_opt==33 .or. & + Model%gwd_opt==2 .or. Model%gwd_opt==22 ) then + + if ( (Model%gwd_opt==3 .or. Model%gwd_opt==33) .or. & + ( (Model%gwd_opt==2 .or. Model%gwd_opt==22) .and. & + Model%do_gsl_drag_ls_bl ) ) then + !--- open restart file + infile=trim(indir)//'/'//trim(fn_oro_ls) + amiopen=open_file(Oro_ls_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if( .not.amiopen ) call mpp_error( FATAL, 'Error with opening file '//trim(infile) ) + call oro_ls%register(Model,Oro_ls_restart,Atm_block) + !--- read new GSL created orography restart/data + call mpp_error(NOTE,'reading topographic/orographic information from & + &INPUT/oro_data_ls.tile*.nc') + call read_restart(Oro_ls_restart, ignore_checksum=ignore_rst_cksum) + call close_file(Oro_ls_restart) + call oro_ls%copy(Sfcprop,Atm_block,1) + endif + + !--- open restart file + infile=trim(indir)//'/'//trim(fn_oro_ss) + amiopen=open_file(Oro_ss_restart, trim(infile), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if( .not.amiopen ) call mpp_error( FATAL, 'Error with opening file '//trim(infile) ) + call oro_ss%register(Model,Oro_ss_restart,Atm_block) + call mpp_error(NOTE,'reading topographic/orographic information from & + &INPUT/oro_data_ss.tile*.nc') + call read_restart(Oro_ss_restart, ignore_checksum=ignore_rst_cksum) + call close_file(Oro_ss_restart) + call oro_ss%copy(Sfcprop,Atm_block,15) + end if + + !--- SURFACE FILE + + !--- open file + infile=trim(indir)//'/'//trim(fn_srf) + amiopen=open_file(Sfc_restart, trim(infile), "read", domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if( .not.amiopen ) call mpp_error(FATAL, 'Error opening file'//trim(infile)) + + if(sfc%allocate_arrays(Model, Atm_block, .true., warm_start)) then + call sfc%fill_2d_names(Model, warm_start) + call sfc%register_axes(Model, Sfc_restart, .true., warm_start) + + ! Tell CLM Lake to allocate data, and register its axes and fields + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%allocate_data(Model) + call clm_lake%copy_from_grid(Model,Atm_block,Sfcprop) + call clm_lake%register_axes(Model, Sfc_restart) + call clm_lake%register_fields(Sfc_restart) + endif + + if(Model%rrfs_sd) then + call rrfs_sd_state%allocate_data(Model) + call rrfs_sd_state%fill_data(Model, Atm_block, Sfcprop) + call rrfs_sd_state%register_axis(Model, Sfc_restart) + call rrfs_sd_state%register_fields(Sfc_restart) + endif + + call sfc%register_2d_fields(Model,Sfc_restart,.true.,warm_start) + endif ! if not allocated + + call sfc%fill_3d_names(Model,warm_start) + call sfc%register_3d_fields(Model,Sfc_restart,.true.,warm_start) + call sfc%init_fields(Model) + + !--- read the surface restart/data + call mpp_error(NOTE,'reading surface properties data from INPUT/sfc_data.tile*.nc') + call read_restart(Sfc_restart, ignore_checksum=ignore_rst_cksum) + call close_file(Sfc_restart) + + ! Tell clm_lake to copy data to temporary arrays + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%copy_to_grid(Model,Atm_block,Sfcprop) + endif + + if(Model%rrfs_sd) then + call rrfs_sd_state%copy_to_grid(Model,Atm_block,Sfcprop) + end if + + ! write(0,*)' stype read in min,max=',minval(sfc%var2(:,:,35)),maxval(sfc%var2(:,:,35)),' sfc%name2=',sfc%name2(35) + ! write(0,*)' stype read in min,max=',minval(sfc%var2(:,:,18)),maxval(sfc%var2(:,:,18)) + ! write(0,*)' sfc%var2=',sfc%var2(:,:,12) + + !--- place the data into the block GFS containers + override_frac_grid=Model%frac_grid + call sfc%copy_to_grid(Model, Atm_block, Sfcprop, warm_start, override_frac_grid) + Model%frac_grid=override_frac_grid + + call mpp_error(NOTE, 'gfs_driver:: - after put to container ') + + call sfc%apply_safeguards(Model, Atm_block, Sfcprop) + + ! A standard-compliant Fortran 2003 compiler will call clm_lake_final and rrfs_sd_final here. + + end subroutine sfc_prop_restart_read + + !>@brief Writes surface restart data without using the write component. + !> \section sfc_prop_restart_write procedure + !! Routine to write out GFS surface restarts via the FMS restart + !! subsystem. Takes an optional argument to append timestamps for intermediate + !! restarts. + subroutine sfc_prop_restart_write (Sfcprop, Atm_block, Model, fv_domain, timestamp) + use fv3atm_rrfs_sd_io + implicit none + !--- interface variable definitions + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + type(domain2d), intent(in) :: fv_domain + character(len=32), optional, intent(in) :: timestamp + !--- directory of the input files + character(7) :: indir='RESTART' + character(72) :: infile + !--- fms2_io file open logic + logical :: amiopen + !--- variables used for fms2_io register axis + + type(clm_lake_data_type), target :: clm_lake + type(rrfs_sd_state_type) :: rrfs_sd_state + type(Sfc_io_data_type) :: sfc + type(FmsNetcdfDomainFile_t) :: Sfc_restart + + !--- set filename + infile=trim(indir)//'/'//trim(fn_srf) + if( present(timestamp) ) infile=trim(indir)//'/'//trim(timestamp)//'.'//trim(fn_srf) + + !--- register axis + amiopen=open_file(Sfc_restart, trim(infile), 'overwrite', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if_amiopen: if( amiopen ) then + call sfc%register_axes(Model, Sfc_restart, .false., .true.) + call sfc%write_axes(Model, Sfc_restart) + else + call mpp_error(FATAL, 'Error in opening file'//trim(infile) ) + end if if_amiopen + + ! Tell clm_lake to allocate data, register its axes, and call write_data for each axis's variable + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%allocate_data(Model) + call clm_lake%register_axes(Model, Sfc_restart) + call clm_lake%write_axes(Model, Sfc_restart) + endif + + if(Model%rrfs_sd) then + call rrfs_sd_state%allocate_data(Model) + call rrfs_sd_state%register_axis(Model,Sfc_restart) + call rrfs_sd_state%write_axis(Model,Sfc_restart) + end if + + if (sfc%allocate_arrays(Model, Atm_block, .false., .true.)) then + call sfc%fill_2d_names(Model,.true.) + end if + + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + ! Tell clm_lake to register all of its fields + call clm_lake%register_fields(Sfc_restart) + endif + + if(Model%rrfs_sd) then + call rrfs_sd_state%register_fields(Sfc_restart) + endif + + ! Register 2D surface property fields (except lake, smoke, and dust) + call sfc%register_2d_fields(Model, Sfc_restart, .false., .true.) + + ! Determine list of 3D surface property fields names: + call sfc%fill_3d_names(Model, .true.) + + ! Register 3D surface property fields (except lake, smoke, and dust) + call sfc%register_3d_fields(Model, Sfc_restart, .false., .true.) + + ! Tell clm_lake to copy Sfcprop data to its internal temporary arrays. + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_clm) then + call clm_lake%copy_from_grid(Model,Atm_block,Sfcprop) + endif + + if(Model%rrfs_sd) then + call rrfs_sd_state%copy_from_grid(Model,Atm_block,Sfcprop) + endif + + call sfc%copy_from_grid(Model, Atm_block, Sfcprop) + + call write_restart(Sfc_restart) + call close_file(Sfc_restart) + + ! A standard-compliant Fortran 2003 compiler will call rrfs_sd_final and clm_lake_final here + + end subroutine sfc_prop_restart_write + + !>@brief Reads the physics restart data. + !> \section phys_restart_read subroutine + !! Creates and populates a data type which is then used to "register" + !! restart variables with the GFDL FMS restart subsystem. + !! Calls a GFDL FMS routine to restore the data from a restart file. + subroutine phys_restart_read (GFS_Restart, Atm_block, Model, fv_domain, ignore_rst_cksum) + implicit none + !--- interface variable definitions + type(GFS_restart_type), intent(in) :: GFS_Restart + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + type(domain2d), intent(in) :: fv_domain + logical, intent(in) :: ignore_rst_cksum + !--- local variables + integer :: i, j, k, nb, ix, num + integer :: isc, iec, jsc, jec, nx, ny + character(len=64) :: fname + real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() + !--- directory of the input files + character(5) :: indir='INPUT' + logical :: amiopen, was_allocated + + type(phy_data_type) :: phy + type(FmsNetcdfDomainFile_t) :: Phy_restart + + isc = Atm_block%isc + iec = Atm_block%iec + jsc = Atm_block%jsc + jec = Atm_block%jec + nx = (iec - isc + 1) + ny = (jec - jsc + 1) + + was_allocated = phy%alloc(GFS_Restart, Atm_block) + + !--- open restart file and register axes + fname = trim(indir)//'/'//trim(fn_phy) + amiopen=open_file(Phy_restart, trim(fname), 'read', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if( amiopen ) then + call register_axis(Phy_restart, 'xaxis_1', 'X') + call register_axis(Phy_restart, 'yaxis_1', 'Y') + call register_axis(Phy_restart, 'zaxis_1', phy%npz) + call register_axis(Phy_restart, 'Time', unlimited) + else + call mpp_error(NOTE,'No physics restarts - cold starting physical parameterizations') + return + endif + + !--- register the restart fields + if(was_allocated) then + + do num = 1,phy%nvar2d + var2_p => phy%var2(:,:,num) + call register_restart_field(Phy_restart, trim(GFS_Restart%name2d(num)), var2_p, dimensions=(/'xaxis_1','yaxis_1','Time '/),& + &is_optional=.true.) + enddo + do num = 1,phy%nvar3d + var3_p => phy%var3(:,:,:,num) + call register_restart_field(Phy_restart, trim(GFS_restart%name3d(num)), var3_p, dimensions=(/'xaxis_1','yaxis_1','zaxis_1','Time '/), is_optional=.true.) + enddo + nullify(var2_p) + nullify(var3_p) + endif + + !--- read the surface restart/data + call mpp_error(NOTE,'reading physics restart data from INPUT/phy_data.tile*.nc') + call read_restart(Phy_restart, ignore_checksum=ignore_rst_cksum) + call close_file(Phy_restart) + + call phy%transfer_data(.true., GFS_Restart, Atm_block, Model) + + end subroutine phys_restart_read + + !>@brief Writes the physics restart file without using the write component + !> \section phys_restart_write subroutine + !! Routine to write out GFS surface restarts via the FMS restart + !! subsystem. Takes an optional argument to append timestamps for intermediate + !! restarts. + subroutine phys_restart_write (GFS_Restart, Atm_block, Model, fv_domain, timestamp) + implicit none + !--- interface variable definitions + type(GFS_restart_type), intent(in) :: GFS_Restart + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + type(domain2d), intent(in) :: fv_domain + character(len=32), optional, intent(in) :: timestamp + !--- local variables + integer :: i, j, k, nb, ix, num + integer :: isc, iec, jsc, jec, nx, ny + real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() + !--- used for axis data for fms2_io + integer :: is, ie + integer, allocatable, dimension(:) :: buffer + character(7) :: indir='RESTART' + character(72) :: infile + logical :: amiopen, allocated_something + + type(phy_data_type) :: phy + type(FmsNetcdfDomainFile_t) :: Phy_restart + + isc = Atm_block%isc + iec = Atm_block%iec + jsc = Atm_block%jsc + jec = Atm_block%jec + nx = (iec - isc + 1) + ny = (jec - jsc + 1) + + !--- register the restart fields + allocated_something = phy%alloc(GFS_Restart, Atm_block) + + !--- set file name + infile=trim(indir)//'/'//trim(fn_phy) + if( present(timestamp) ) infile=trim(indir)//'/'//trim(timestamp)//'.'//trim(fn_phy) + !--- register axis + amiopen=open_file(Phy_restart, trim(infile), 'overwrite', domain=fv_domain, is_restart=.true., dont_add_res_to_filename=.true.) + if( amiopen ) then + call register_axis(Phy_restart, 'xaxis_1', 'X') + call register_field(Phy_restart, 'xaxis_1', 'double', (/'xaxis_1'/)) + call register_variable_attribute(Phy_restart, 'xaxis_1', 'cartesian_axis', 'X', str_len=1) + call get_global_io_domain_indices(Phy_restart, 'xaxis_1', is, ie, indices=buffer) + call write_data(Phy_restart, "xaxis_1", buffer) + deallocate(buffer) + + call register_axis(Phy_restart, 'yaxis_1', 'Y') + call register_field(Phy_restart, 'yaxis_1', 'double', (/'yaxis_1'/)) + call register_variable_attribute(Phy_restart, 'yaxis_1', 'cartesian_axis', 'Y', str_len=1) + call get_global_io_domain_indices(Phy_restart, 'yaxis_1', is, ie, indices=buffer) + call write_data(Phy_restart, "yaxis_1", buffer) + deallocate(buffer) + + call register_axis(Phy_restart, 'zaxis_1', phy%npz) + call register_field(Phy_restart, 'zaxis_1', 'double', (/'zaxis_1'/)) + call register_variable_attribute(Phy_restart, 'zaxis_1', 'cartesian_axis', 'Z', str_len=1) + allocate( buffer(phy%npz) ) + do i=1, phy%npz + buffer(i)=i + end do + call write_data(Phy_restart, "zaxis_1", buffer) + deallocate(buffer) + + call register_axis(Phy_restart, 'Time', unlimited) + call register_field(Phy_restart, 'Time', 'double', (/'Time'/)) + call register_variable_attribute(Phy_restart, 'Time', 'cartesian_axis', 'T', str_len=1) + call write_data(Phy_restart, "Time", 1) + else + call mpp_error(FATAL, 'Error opening file '//trim(infile)) + end if + + do num = 1,phy%nvar2d + var2_p => phy%var2(:,:,num) + call register_restart_field(Phy_restart, trim(GFS_Restart%name2d(num)), var2_p, dimensions=(/'xaxis_1','yaxis_1','Time '/),& + &is_optional=.true.) + enddo + do num = 1,phy%nvar3d + var3_p => phy%var3(:,:,:,num) + call register_restart_field(Phy_restart, trim(GFS_Restart%name3d(num)), var3_p, dimensions=(/'xaxis_1','yaxis_1','zaxis_1','Time '/),& + &is_optional=.true.) + enddo + nullify(var2_p) + nullify(var3_p) + + call phy%transfer_data(.false., GFS_Restart, Atm_block, Model) + + call write_restart(Phy_restart) + call close_file(Phy_restart) + + end subroutine phys_restart_write + + !>@brief Allocates buffers and registers fields for a quilting (write component) restart. + !> \section fv3atm_restart_register subroutine + !! Allocates all data buffers and sets variable names for surface and physics restarts. + subroutine fv3atm_restart_register (Sfcprop, GFS_restart, Atm_block, Model) + implicit none + + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_restart_type), intent(in) :: GFS_Restart + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + + logical was_changed + + !--------------- phy + was_changed = phy_quilt%alloc(GFS_Restart, Atm_block) + + !--------------- sfc + was_changed = sfc_quilt%allocate_arrays(Model, Atm_block, .false., .true.) + call sfc_quilt%fill_2d_names(Model, .true.) + call sfc_quilt%fill_3d_names(Model, .true.) + + if(Model%iopt_lake == 2 .and. Model%lkm > 0) then + call clm_lake_quilt%allocate_data(Model) + endif + + if(Model%rrfs_sd) then + call rrfs_sd_quilt%allocate_data(Model) + endif + + end subroutine fv3atm_restart_register + + !>@Copies physics restart fields from write component data structures to the model grid. + subroutine fv_phy_restart_output(GFS_Restart, Atm_block) + + implicit none + + type(GFS_restart_type), intent(in) :: GFS_Restart + type(block_control_type), intent(in) :: Atm_block + + call phy_quilt%transfer_data(.false., GFS_Restart, Atm_block) + + end subroutine fv_phy_restart_output + + !>@Copies physics restart fields from the model grid to write component data structures + subroutine fv_sfc_restart_output(Sfcprop, Atm_block, Model) + !--- interface variable definitions + implicit none + + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + + call sfc_quilt%copy_from_grid(Model, Atm_block, Sfcprop) + if(Model%iopt_lake == 2 .and. Model%lkm > 0) then + call clm_lake_quilt%copy_from_grid(Model, Atm_block, Sfcprop) + endif + if(Model%rrfs_sd) then + call rrfs_sd_quilt%copy_from_grid(Model, Atm_block, Sfcprop) + endif + + end subroutine fv_sfc_restart_output + + !>@ Creates the ESMF bundle for physics restart data + subroutine fv_phy_restart_bundle_setup(bundle, grid, rc) + use esmf + + implicit none + + type(ESMF_FieldBundle),intent(inout) :: bundle + type(ESMF_Grid),intent(inout) :: grid + integer,intent(out) :: rc + + !*** local variables + integer i + character(128) :: bdl_name + character(128) :: outputfile + real(kind_phys),dimension(:,:),pointer :: temp_r2d + real(kind_phys),dimension(:,:,:),pointer :: temp_r3d + integer :: num + real(kind_phys), allocatable :: axis_values(:) + + if (.not. associated(phy_quilt%var2)) then + write(0,*)'ERROR phy_quilt%var2, NOT allocated' + endif + if (.not. associated(phy_quilt%var3)) then + write(0,*)'ERROR phy_quilt%var3 NOT allocated' + endif + + call ESMF_FieldBundleGet(bundle, name=bdl_name,rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + outputfile = trim(bdl_name) + + !*** add esmf fields + + do num = 1,phy_quilt%nvar2d + temp_r2d => phy_quilt%var2(:,:,num) + call create_2d_field_and_add_to_bundle(temp_r2d, trim(phy_quilt%var2_names(num)), trim(outputfile), grid, bundle) + enddo + + allocate(axis_values(phy_quilt%npz)) + axis_values = (/ (i, i=1,phy_quilt%npz) /) + + do num = 1,phy_quilt%nvar3d + temp_r3d => phy_quilt%var3(:,:,:,num) + call create_3d_field_and_add_to_bundle(temp_r3d, trim(phy_quilt%var3_names(num)), "zaxis_1", axis_values, trim(outputfile), grid, bundle) + enddo + + deallocate(axis_values) + + end subroutine fv_phy_restart_bundle_setup + + !>@ Creates the ESMF bundle for surface restart data + subroutine fv_sfc_restart_bundle_setup(bundle, grid, Model, rc) + use esmf + + implicit none + + type(ESMF_FieldBundle),intent(inout) :: bundle + type(ESMF_Grid),intent(inout) :: grid + type(GFS_control_type), intent(in) :: Model + integer,intent(out) :: rc + + !*** local variables + character(128) :: sfcbdl_name + character(128) :: outputfile + + call ESMF_FieldBundleGet(bundle, name=sfcbdl_name,rc=rc) + if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, line=__LINE__, file=__FILE__)) return + + outputfile = trim(sfcbdl_name) + + !*** add esmf fields + + call sfc_quilt%bundle_2d_fields(bundle, grid, Model, outputfile) + call sfc_quilt%bundle_3d_fields(bundle, grid, Model, outputfile) + + if(Model%iopt_lake == 2 .and. Model%lkm > 0) then + call clm_lake_quilt%bundle_fields(bundle, grid, Model, outputfile) + endif + if(Model%rrfs_sd) then + call rrfs_sd_quilt%bundle_fields(bundle, grid, Model, outputfile) + endif + + end subroutine fv_sfc_restart_bundle_setup + + !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + ! + ! PRIVATE SUBROUTINES + ! + !%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + !>@brief Allocates and fills internal data structures for quilt or non-quilt physics restart I/O + !> \section phy_data_type%alloc procedure + !! Allocates the variable and variable name data structures in the phy_data_type. + !! Also, copies the GFS_Restart names to the phy_data_type arrays. + !! Do not call from outside this module; it is part of the internal implementation. + logical function phy_data_alloc(phy, GFS_Restart, Atm_block) + use fv3atm_common_io, only: get_nx_ny_from_atm + implicit none + class(phy_data_type) :: phy + type(GFS_restart_type), intent(in) :: GFS_Restart + type(block_control_type), intent(in) :: Atm_block + + integer :: nx, ny, num + + phy_data_alloc = .false. + + if(associated(phy%var2)) return + + call get_nx_ny_from_atm(Atm_block, nx, ny) + + phy%npz = Atm_block%npz + phy%nvar2d = GFS_Restart%num2d + phy%nvar3d = GFS_Restart%num3d + + allocate (phy%var2(nx,ny,phy%nvar2d), phy%var2_names(phy%nvar2d)) + allocate (phy%var3(nx,ny,phy%npz,phy%nvar3d), phy%var3_names(phy%nvar3d)) + phy%var2 = zero + phy%var3 = zero + do num = 1,phy%nvar2d + phy%var2_names(num) = trim(GFS_Restart%name2d(num)) + enddo + do num = 1,phy%nvar3d + phy%var3_names(num) = trim(GFS_Restart%name3d(num)) + enddo + + phy_data_alloc = .true. + end function phy_data_alloc + + !>@brief Copies data between the internal physics restart data structures and the model grid + !> \section phy_data_type%transfer_data procedure + !! Restart I/O stores data in temporary arrays while interfacing with ESMF or FMS. This procedure + !! copies between the temporary arrays and the model grid. The "reading" flag controls the + !! direction of the copy. For reading=.true., data is copied from the temporary arrays to the + !! model grid (during restart read). For reading=.false., data is copied from the model grid to + !! temporary arrays (for writing the restart). + subroutine phy_data_transfer_data(phy, reading, GFS_Restart, Atm_block, Model) + use mpp_mod, only: FATAL, mpp_error + implicit none + class(phy_data_type) :: phy + logical, intent(in) :: reading + type(GFS_restart_type) :: GFS_Restart + type(block_control_type) :: Atm_block + type(GFS_control_type), optional, intent(in) :: Model + + integer :: i, j, k, num, nb, ix + + !--- register the restart fields + if (.not. associated(phy%var2)) then + call mpp_error(FATAL,'phy%var2 must be allocated') + return ! should never get here + endif + if (.not. associated(phy%var3)) then + call mpp_error(FATAL,'phy%var3 must be allocated') + return ! should never get here + endif + + ! Copy 2D Vars + + if(reading) then + !--- place the data into the block GFS containers + !--- phy%var* variables + do num = 1,phy%nvar2d + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1,Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + GFS_Restart%data(nb,num)%var2p(ix) = phy%var2(i,j,num) + enddo + enddo + enddo + else + !--- 2D variables + do num = 1,phy%nvar2d + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1,Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + phy%var2(i,j,num) = GFS_Restart%data(nb,num)%var2p(ix) + enddo + enddo + enddo + endif + + !-- if restart from init time, reset accumulated diag fields + + if(reading .and. present(Model)) then + if(Model%phour < 1.e-7) then + do num = GFS_Restart%fdiag,GFS_Restart%ldiag + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1,Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + GFS_Restart%data(nb,num)%var2p(ix) = zero + enddo + enddo + enddo + endif + endif + + ! Copy 3D Vars + + if(reading) then + do num = 1,phy%nvar3d + !$omp parallel do default(shared) private(i, j, k, nb, ix) + do nb = 1,Atm_block%nblks + do k=1,phy%npz + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + GFS_Restart%data(nb,num)%var3p(ix,k) = phy%var3(i,j,k,num) + enddo + enddo + enddo + enddo + else + !--- 3D variables + do num = 1,phy%nvar3d + !$omp parallel do default(shared) private(i, j, k, nb, ix) + do nb = 1,Atm_block%nblks + do k=1,phy%npz + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + phy%var3(i,j,k,num) = GFS_Restart%data(nb,num)%var3p(ix,k) + enddo + enddo + enddo + enddo + endif + + end subroutine phy_data_transfer_data + + !>@ Destructor for phy_data_type + subroutine phy_data_final(phy) + implicit none + type(phy_data_type) :: phy + + ! This #define reduces code length by a lot +#define IF_ASSOC_DEALLOC_NULL(var) \ + if(associated(phy%var)) then ; \ + deallocate(phy%var) ; \ + nullify(phy%var) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(var2) + IF_ASSOC_DEALLOC_NULL(var3) + IF_ASSOC_DEALLOC_NULL(var2_names) + IF_ASSOC_DEALLOC_NULL(var3_names) + +#undef IF_ASSOC_DEALLOC_NULL + end subroutine phy_data_final + +end module fv3atm_restart_io_mod +!> @} diff --git a/io/fv3atm_rrfs_sd_io.F90 b/io/fv3atm_rrfs_sd_io.F90 new file mode 100644 index 000000000..c6dc44e34 --- /dev/null +++ b/io/fv3atm_rrfs_sd_io.F90 @@ -0,0 +1,607 @@ +!> \file fv3atm_rrfs_sd_io.F90 +!! This file contains derived types and subroutines for RRFS-SD scheme I/O. +!! They read and write restart files, and read emissions data. + +module fv3atm_rrfs_sd_io + use block_control_mod, only: block_control_type + use fms2_io_mod, only: FmsNetcdfDomainFile_t, write_data, & + register_axis, register_restart_field, & + register_variable_attribute, register_field + use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, kind_phys + use fv3atm_common_io, only: get_nx_ny_from_atm, create_2d_field_and_add_to_bundle, & + create_3d_field_and_add_to_bundle + + implicit none + + private + + public :: rrfs_sd_state_type, rrfs_sd_state_register_axis, rrfs_sd_state_write_axis, & + rrfs_sd_state_fill_data, rrfs_sd_state_register_fields, rrfs_sd_state_deallocate_data, & + rrfs_sd_state_copy_from_grid, rrfs_sd_state_copy_to_grid, & + rrfs_sd_state_final + + public :: rrfs_sd_emissions_type, rrfs_sd_emissions_final, & + rrfs_sd_emissions_register_dust12m, rrfs_sd_emissions_copy_dust12m, & + rrfs_sd_emissions_register_emi, rrfs_sd_emissions_copy_emi, & + rrfs_sd_emissions_register_fire, rrfs_sd_emissions_copy_fire + + !>\defgroup fv3atm_rrfs_sd_io module + !> @{ + + !>@ Temporary data storage for reading and writing restart data for the RRFS-SD scheme. + type rrfs_sd_state_type + ! The rrfs_sd_state_type stores temporary arrays used to read or + ! write RRFS-SD restart and axis variables. + + real(kind_phys), pointer, private, dimension(:,:) :: & ! i,j variables + emdust=>null(), emseas=>null(), emanoc=>null(), fhist=>null(), coef_bb_dc=>null() + + real(kind_phys), pointer, private, dimension(:,:,:) :: & + fire_in=>null() ! i, j, fire_aux_data_levels + + real(kind_phys), pointer, private, dimension(:) :: & + fire_aux_data_levels=>null() ! 1:Model%fire_aux_data_levels index array for metadata write + + contains + procedure, public :: register_axis => rrfs_sd_state_register_axis ! register fire_aux_data_levels axis + procedure, public :: write_axis => rrfs_sd_state_write_axis ! write fire_aux_data_levels variable + procedure, public :: allocate_data => rrfs_sd_state_allocate_data ! allocate all pointers + procedure, public :: fill_data => rrfs_sd_state_fill_data ! fill data with default values + procedure, public :: register_fields => rrfs_sd_state_register_fields ! register rrfs_sd fields + procedure, public :: deallocate_data => rrfs_sd_state_deallocate_data ! deallocate pointers + procedure, public :: copy_from_grid => rrfs_sd_state_copy_from_grid ! Copy Sfcprop to arrays + procedure, public :: copy_to_grid => rrfs_sd_state_copy_to_grid ! Copy arrays to Sfcprop + procedure, public :: bundle_fields => rrfs_sd_bundle_fields ! Point esmf bundles to arrays + final :: rrfs_sd_state_final ! Destructor; calls deallocate_data + end type rrfs_sd_state_type + + ! -------------------------------------------------------------------- + + !>@ Temporary data storage for reading RRFS-SD emissions data + type rrfs_sd_emissions_type + integer, private :: nvar_dust12m = 5 + integer, private :: nvar_emi = 1 + integer, private :: nvar_fire = 3 + + character(len=32), pointer, dimension(:), private :: dust12m_name => null() + character(len=32), pointer, dimension(:), private :: emi_name => null() + character(len=32), pointer, dimension(:), private :: fire_name => null() + + real(kind=kind_phys), pointer, dimension(:,:,:,:), private :: dust12m_var => null() + real(kind=kind_phys), pointer, dimension(:,:,:,:), private :: emi_var => null() + real(kind=kind_phys), pointer, dimension(:,:,:,:), private :: fire_var => null() + + contains + + procedure, public :: register_dust12m => rrfs_sd_emissions_register_dust12m + procedure, public :: copy_dust12m => rrfs_sd_emissions_copy_dust12m + + procedure, public :: register_emi => rrfs_sd_emissions_register_emi + procedure, public :: copy_emi => rrfs_sd_emissions_copy_emi + + procedure, public :: register_fire => rrfs_sd_emissions_register_fire + procedure, public :: copy_fire => rrfs_sd_emissions_copy_fire + + final :: rrfs_sd_emissions_final + end type rrfs_sd_emissions_type + + ! -------------------------------------------------------------------- + +contains + + + ! -------------------------------------------------------------------- + ! -- RRFS_SD_STATE IMPLEMENTATION ------------------------------------ + ! -------------------------------------------------------------------- + + !>@ Registers the fire_aux_data_levels axis for restart I/O + subroutine rrfs_sd_state_register_axis(data,Model,Sfc_restart) + implicit none + class(rrfs_sd_state_type) :: data + type(FmsNetcdfDomainFile_t) :: Sfc_restart + type(GFS_control_type), intent(in) :: Model + call register_axis(Sfc_restart, 'fire_aux_data_levels', & + dimension_length=Model%fire_aux_data_levels) + end subroutine rrfs_sd_state_register_axis + + ! -------------------------------------------------------------------- + + !>@ Registers and writes the axis indices for the fire_aux_data_levels axis + subroutine rrfs_sd_state_write_axis(data,Model,Sfc_restart) + implicit none + class(rrfs_sd_state_type) :: data + type(FmsNetcdfDomainFile_t) :: Sfc_restart + type(GFS_control_type), intent(in) :: Model + + call register_field(Sfc_restart, 'fire_aux_data_levels', 'double', (/'fire_aux_data_levels'/)) + call register_variable_attribute(Sfc_restart, 'fire_aux_data_levels', 'cartesian_axis' ,'Z', str_len=1) + call write_data(Sfc_restart, 'fire_aux_data_levels', data%fire_aux_data_levels) + end subroutine rrfs_sd_state_write_axis + + ! -------------------------------------------------------------------- + + !>@ Allocates temporary arrays for RRFS-SD scheme I/O and stores fire_aux_data_levels axis indices + subroutine rrfs_sd_state_allocate_data(data,Model) + implicit none + class(rrfs_sd_state_type) :: data + type(GFS_control_type), intent(in) :: Model + integer :: nx, ny, i + + call data%deallocate_data + + nx=Model%nx + ny=Model%ny + + allocate(data%emdust(nx,ny)) + allocate(data%emseas(nx,ny)) + allocate(data%emanoc(nx,ny)) + allocate(data%fhist(nx,ny)) + allocate(data%coef_bb_dc(nx,ny)) + allocate(data%fire_aux_data_levels(Model%fire_aux_data_levels)) + allocate(data%fire_in(nx,ny,Model%fire_aux_data_levels)) + + do i=1,Model%fire_aux_data_levels + data%fire_aux_data_levels(i) = i + enddo + + end subroutine rrfs_sd_state_allocate_data + + ! -------------------------------------------------------------------- + + !>@brief Fills RRFS-SD temporary arrays with reasonable defaults. + !> \section rrfs_sd_state_type%fill_data() procedure + !! Fills all temporary variables with default values. + !! Terrible things will happen if you don't call data%allocate_data first. + subroutine rrfs_sd_state_fill_data(data, Model, Atm_block, Sfcprop) + implicit none + class(rrfs_sd_state_type) :: data + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_control_type), intent(in) :: Model + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, isc, jsc, i, j + + isc = Model%isc + jsc = Model%jsc + + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - isc + 1 + j = Atm_block%index(nb)%jj(ix) - jsc + 1 + + data%emdust(i,j) = 0 + data%emseas(i,j) = 0 + data%emanoc(i,j) = 0 + data%fhist(i,j) = 1. + data%coef_bb_dc(i,j) = 0 + + data%fire_in(i,j,:) = 0 + end do + end do + end subroutine rrfs_sd_state_fill_data + + ! -------------------------------------------------------------------- + + !>@brief Registers RRFS-SD restart variables (for read or write) + !> \section rrfs_sd_state_type%register_fields() procedure + !! Registers all restart fields needed by the RRFS-SD + !! Terrible things will happen if you don't call data%allocate_data + !! and data%register_axes first. + subroutine rrfs_sd_state_register_fields(data,Sfc_restart) + implicit none + class(rrfs_sd_state_type) :: data + type(FmsNetcdfDomainFile_t) :: Sfc_restart + + ! Register 2D fields + call register_restart_field(Sfc_restart, 'emdust', data%emdust, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'emseas', data%emseas, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'emanoc', data%emanoc, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'fhist', data%fhist, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + call register_restart_field(Sfc_restart, 'coef_bb_dc', data%coef_bb_dc, & + dimensions=(/'xaxis_1', 'yaxis_1', 'Time '/), is_optional=.true.) + + ! Register 3D field + call register_restart_field(Sfc_restart, 'fire_in', data%fire_in, & + dimensions=(/'xaxis_1 ', 'yaxis_1 ', & + 'fire_aux_data_levels', 'Time '/), & + is_optional=.true.) + end subroutine rrfs_sd_state_register_fields + + ! -------------------------------------------------------------------- + + !>@brief Creates ESMF bundles for writing RRFS-SD restarts via the write component (quilt) + !> \section rrfs_sd_state_type%bundle_fields() procedure + !! Registers all restart fields needed by the RRFS-SD + !! Terrible things will happen if you don't call data%allocate_data + !! and data%register_axes first. + subroutine rrfs_sd_bundle_fields(data, bundle, grid, Model, outputfile) + use esmf + use GFS_typedefs, only: GFS_control_type + implicit none + class(rrfs_sd_state_type) :: data + type(ESMF_FieldBundle),intent(inout) :: bundle + type(ESMF_Grid),intent(inout) :: grid + type(GFS_control_type), intent(in) :: Model + character(*), intent(in) :: outputfile + + ! Register 2D fields + call create_2d_field_and_add_to_bundle(data%emdust, "emdust", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(data%emseas, "emseas", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(data%emanoc, "emanoc", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(data%fhist, "fhist", trim(outputfile), grid, bundle) + call create_2d_field_and_add_to_bundle(data%coef_bb_dc, "coef_bb_dc", trim(outputfile), grid, bundle) + + ! Register 3D field + call create_3d_field_and_add_to_bundle(data%fire_in, 'fire_in', 'fire_aux_data_levels', & + data%fire_aux_data_levels, trim(outputfile), grid, bundle) + end subroutine rrfs_sd_bundle_fields + + ! -------------------------------------------------------------------- + + !>@brief Destructor for the rrfs_sd_state_type + !> \section rrfs_sd_state_type destructor() procedure + !! Final routine for rrfs_sd_state_type, called automatically when + !! an object of that type goes out of scope. This is a wrapper + !! around data%deallocate_data() with necessary syntactic + !! differences. + subroutine rrfs_sd_state_final(data) + implicit none + type(rrfs_sd_state_type) :: data + call rrfs_sd_state_deallocate_data(data) + end subroutine rrfs_sd_state_final + + ! -------------------------------------------------------------------- + + !>@brief Deallocates internal arrays in an rrfs_sd_state_type + !> \section rrfs_sd_state_type%deallocate_data() procedure + !! Deallocates all data used, and nullifies the pointers. The data + !! object can safely be used again after this call. This is also + !! the implementation of the rrfs_sd_state_deallocate_data final routine. + subroutine rrfs_sd_state_deallocate_data(data) + implicit none + class(rrfs_sd_state_type) :: data + + ! This #define reduces code length by a lot +#define IF_ASSOC_DEALLOC_NULL(var) \ + if(associated(data%var)) then ; \ + deallocate(data%var) ; \ + nullify(data%var) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(emdust) + IF_ASSOC_DEALLOC_NULL(emseas) + IF_ASSOC_DEALLOC_NULL(emanoc) + IF_ASSOC_DEALLOC_NULL(fhist) + IF_ASSOC_DEALLOC_NULL(coef_bb_dc) + + IF_ASSOC_DEALLOC_NULL(fire_in) + + ! Undefine this to avoid cluttering the cpp scope: +#undef IF_ASSOC_DEALLOC_NULL + end subroutine rrfs_sd_state_deallocate_data + + ! -------------------------------------------------------------------- + + !>@brief Copies from rrfs_sd_state_type internal arrays to the model grid. + !> \section rrfs_sd_state_type%copy_to_grid() procedure + !! This procedure is called after reading a restart, to copy restart data + !! from the rrfs_sd_state_type to the model grid. + subroutine rrfs_sd_state_copy_to_grid(data, Model, Atm_block, Sfcprop) + implicit none + class(rrfs_sd_state_type) :: data + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_control_type), intent(in) :: Model + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, i, j + + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + + Sfcprop(nb)%emdust(ix) = data%emdust(i,j) + Sfcprop(nb)%emseas(ix) = data%emseas(i,j) + Sfcprop(nb)%emanoc(ix) = data%emanoc(i,j) + Sfcprop(nb)%fhist(ix) = data%fhist(i,j) + Sfcprop(nb)%coef_bb_dc(ix) = data%coef_bb_dc(i,j) + + Sfcprop(nb)%fire_in(ix,:) = data%fire_in(i,j,:) + enddo + enddo + end subroutine rrfs_sd_state_copy_to_grid + + ! -------------------------------------------------------------------- + + !>@brief Copies from the model grid to rrfs_sd_state_type internal arrays + !> \section rrfs_sd_state_type%copy_from_grid() procedure + !! This procedure is called before writing the restart, to copy data from + !! the model grid to rrfs_sd_state_type internal arrays. The ESMF or FMS + !! restart code will write data from those arrays, not the model grid. + subroutine rrfs_sd_state_copy_from_grid(data, Model, Atm_block, Sfcprop) + implicit none + class(rrfs_sd_state_type) :: data + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(GFS_control_type), intent(in) :: Model + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, i, j + + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + + data%emdust(i,j) = Sfcprop(nb)%emdust(ix) + data%emseas(i,j) = Sfcprop(nb)%emseas(ix) + data%emanoc(i,j) = Sfcprop(nb)%emanoc(ix) + data%fhist(i,j) = Sfcprop(nb)%fhist(ix) + data%coef_bb_dc(i,j) = Sfcprop(nb)%coef_bb_dc(ix) + + data%fire_in(i,j,:) = Sfcprop(nb)%fire_in(ix,:) + enddo + enddo + end subroutine rrfs_sd_state_copy_from_grid + + ! -------------------------------------------------------------------- + ! -- RRFS_SD_EMISSIONS IMPLEMENTATION -------------------------------- + ! -------------------------------------------------------------------- + + !>@ Allocates temporary arrays and registers variables for reading the dust12m file. + subroutine rrfs_sd_emissions_register_dust12m(data, restart, Atm_block) + implicit none + class(rrfs_sd_emissions_type) :: data + type(FmsNetcdfDomainFile_t) :: restart + type(block_control_type), intent(in) :: Atm_block + + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p2 => NULL() + integer :: num, nx, ny + + if(associated(data%dust12m_name)) then + deallocate(data%dust12m_name) + nullify(data%dust12m_name) + endif + if(associated(data%dust12m_var)) then + deallocate(data%dust12m_var) + nullify(data%dust12m_var) + endif + + call get_nx_ny_from_atm(Atm_block, nx, ny) + allocate(data%dust12m_name(data%nvar_dust12m)) + allocate(data%dust12m_var(nx,ny,12,data%nvar_dust12m)) + + data%dust12m_name(1) = 'clay' + data%dust12m_name(2) = 'rdrag' + data%dust12m_name(3) = 'sand' + data%dust12m_name(4) = 'ssm' + data%dust12m_name(5) = 'uthr' + + !--- register axis + call register_axis(restart, 'lon', 'X') + call register_axis(restart, 'lat', 'Y') + call register_axis(restart, 'time', 12) + !--- register the 3D fields + do num = 1,data%nvar_dust12m + var3_p2 => data%dust12m_var(:,:,:,num) + call register_restart_field(restart, data%dust12m_name(num), var3_p2, & + dimensions=(/'time', 'lat ', 'lon '/),& + &is_optional=.true.) + ! That was "is_optional=.not.mand" in the original, but mand was never initialized. + enddo + end subroutine rrfs_sd_emissions_register_dust12m + + ! -------------------------------------------------------------------- + + !>@ Called after register_dust12m() to copy data from internal arrays to the model grid and deallocate arrays + subroutine rrfs_sd_emissions_copy_dust12m(data, Sfcprop, Atm_block) + implicit none + type(GFS_sfcprop_type), intent(inout) :: Sfcprop(:) + class(rrfs_sd_emissions_type) :: data + type(block_control_type), intent(in) :: Atm_block + + integer :: num, nb, i, j, ix, k + + if(.not.associated(data%dust12m_name) .or. .not.associated(data%dust12m_var)) then + write(0,*) 'ERROR: Called copy_dust12m before register_dust12m' + return + endif + + !$omp parallel do default(shared) private(i, j, nb, ix, k) + do nb = 1, Atm_block%nblks + !--- 3D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + do k = 1, 12 + Sfcprop(nb)%dust12m_in(ix,k,1) = data%dust12m_var(i,j,k,1) + Sfcprop(nb)%dust12m_in(ix,k,2) = data%dust12m_var(i,j,k,2) + Sfcprop(nb)%dust12m_in(ix,k,3) = data%dust12m_var(i,j,k,3) + Sfcprop(nb)%dust12m_in(ix,k,4) = data%dust12m_var(i,j,k,4) + Sfcprop(nb)%dust12m_in(ix,k,5) = data%dust12m_var(i,j,k,5) + enddo + enddo + enddo + + deallocate(data%dust12m_name) + nullify(data%dust12m_name) + deallocate(data%dust12m_var) + nullify(data%dust12m_var) + end subroutine rrfs_sd_emissions_copy_dust12m + + ! -------------------------------------------------------------------- + + !>@ Allocates temporary arrays and registers variables for reading the emissions file. + subroutine rrfs_sd_emissions_register_emi(data, restart, Atm_block) + implicit none + class(rrfs_sd_emissions_type) :: data + type(FmsNetcdfDomainFile_t) :: restart + type(block_control_type), intent(in) :: Atm_block + + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p2 => NULL() + integer :: num, nx, ny + + if(associated(data%emi_name)) then + deallocate(data%emi_name) + nullify(data%emi_name) + endif + + if(associated(data%emi_var)) then + deallocate(data%emi_var) + nullify(data%emi_var) + endif + + call get_nx_ny_from_atm(Atm_block, nx, ny) + allocate(data%emi_name(data%nvar_emi)) + allocate(data%emi_var(nx,ny,1,data%nvar_emi)) + + data%emi_name(1) = 'e_oc' + !--- register axis + call register_axis( restart, 'time', 1) ! only read first time level, even if multiple are present + call register_axis( restart, "grid_xt", 'X' ) + call register_axis( restart, "grid_yt", 'Y' ) + !--- register the 2D fields + do num = 1,data%nvar_emi + var3_p2 => data%emi_var(:,:,:,num) + call register_restart_field(restart, data%emi_name(num), var3_p2, & + dimensions=(/'time ','grid_yt','grid_xt'/)) + enddo + end subroutine rrfs_sd_emissions_register_emi + + ! -------------------------------------------------------------------- + + !>@ Called after register_emi() to copy data from internal arrays to the model grid and deallocate arrays + subroutine rrfs_sd_emissions_copy_emi(data, Sfcprop, Atm_block) + implicit none + type(GFS_sfcprop_type), intent(inout) :: Sfcprop(:) + class(rrfs_sd_emissions_type) :: data + type(block_control_type), intent(in) :: Atm_block + + integer :: num, nb, i, j, ix + + if(.not.associated(data%emi_name) .or. .not.associated(data%emi_var)) then + write(0,*) 'ERROR: Called copy_emi before register_emi' + return + endif + + do num=1,data%nvar_emi + !$omp parallel do default(shared) private(i, j, nb, ix) + do nb = 1, Atm_block%nblks + !--- 2D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + Sfcprop(nb)%emi_in(ix,num) = data%emi_var(i,j,1,num) + enddo + enddo + enddo + + deallocate(data%emi_name) + nullify(data%emi_name) + deallocate(data%emi_var) + nullify(data%emi_var) + end subroutine rrfs_sd_emissions_copy_emi + + ! -------------------------------------------------------------------- + + !>@ Allocates temporary arrays and registers variables for reading the fire data file. + subroutine rrfs_sd_emissions_register_fire(data, restart, Atm_block) + implicit none + class(rrfs_sd_emissions_type) :: data + type(FmsNetcdfDomainFile_t) :: restart + type(block_control_type), intent(in) :: Atm_block + + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p2 => NULL() + integer :: num, nx, ny + + if(associated(data%fire_name)) then + deallocate(data%fire_name) + nullify(data%fire_name) + endif + + if(associated(data%fire_var)) then + deallocate(data%fire_var) + nullify(data%fire_var) + endif + + !--- allocate the various containers needed for rrfssd fire data + call get_nx_ny_from_atm(Atm_block, nx, ny) + allocate(data%fire_name(data%nvar_fire)) + allocate(data%fire_var(nx,ny,24,data%nvar_fire)) + + data%fire_name(1) = 'ebb_smoke_hr' + data%fire_name(2) = 'frp_avg_hr' + data%fire_name(3) = 'frp_std_hr' + + !--- register axis + call register_axis(restart, 'lon', 'X') + call register_axis(restart, 'lat', 'Y') + call register_axis(restart, 't', 24) + !--- register the 3D fields + do num = 1,data%nvar_fire + var3_p2 => data%fire_var(:,:,:,num) + call register_restart_field(restart, data%fire_name(num), var3_p2, & + dimensions=(/'t ', 'lat', 'lon'/), is_optional=.true.) + enddo + + end subroutine rrfs_sd_emissions_register_fire + + ! -------------------------------------------------------------------- + + !>@ Called after register_fire() to copy data from internal arrays to the model grid and deallocate arrays + subroutine rrfs_sd_emissions_copy_fire(data, Sfcprop, Atm_block) + implicit none + class(rrfs_sd_emissions_type) :: data + type(GFS_sfcprop_type), intent(inout) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + + integer :: nb, ix, k, i, j + + !$omp parallel do default(shared) private(i, j, nb, ix, k) + do nb = 1, Atm_block%nblks + !--- 3D variables + do ix = 1, Atm_block%blksz(nb) + i = Atm_block%index(nb)%ii(ix) - Atm_block%isc + 1 + j = Atm_block%index(nb)%jj(ix) - Atm_block%jsc + 1 + !--- assign hprime(1:10) and hprime(15:24) with new oro stat data + do k = 1, 24 + Sfcprop(nb)%smoke_RRFS(ix,k,1) = data%fire_var(i,j,k,1) + Sfcprop(nb)%smoke_RRFS(ix,k,2) = data%fire_var(i,j,k,2) + Sfcprop(nb)%smoke_RRFS(ix,k,3) = data%fire_var(i,j,k,3) + enddo + enddo + enddo + end subroutine rrfs_sd_emissions_copy_fire + + !>@ Destructor for rrfs_sd_emissions_type + subroutine rrfs_sd_emissions_final(data) + implicit none + type(rrfs_sd_emissions_type) :: data + + ! This #define reduces code length by a lot +#define IF_ASSOC_DEALLOC_NULL(var) \ + if(associated(data%var)) then ; \ + deallocate(data%var) ; \ + nullify(data%var) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(dust12m_name) + IF_ASSOC_DEALLOC_NULL(emi_name) + IF_ASSOC_DEALLOC_NULL(fire_name) + IF_ASSOC_DEALLOC_NULL(dust12m_var) + IF_ASSOC_DEALLOC_NULL(emi_var) + IF_ASSOC_DEALLOC_NULL(fire_var) + + ! Undefine this to avoid cluttering the cpp scope: +#undef IF_ASSOC_DEALLOC_NULL + end subroutine rrfs_sd_emissions_final + +end module fv3atm_rrfs_sd_io + +!> @} diff --git a/io/fv3atm_sfc_io.F90 b/io/fv3atm_sfc_io.F90 new file mode 100644 index 000000000..cff249370 --- /dev/null +++ b/io/fv3atm_sfc_io.F90 @@ -0,0 +1,1625 @@ +!> \file fv3atm_sfc_io.F90 +!! This file contains a derived type and subroutines to read and write restart files for +!! most FV3ATM surface fields. It works both for quilt (via ESMF) and non-quilt (via FMS) +!! restarts. Certain fields are handled by other files: fv3atm_oro_io.F90, fv3atm_rrfs_sd_io.F90, +!! and fv3atm_clm_lake_io.F90. +module fv3atm_sfc_io + + use block_control_mod, only: block_control_type + use fms2_io_mod, only: FmsNetcdfDomainFile_t, unlimited, write_data,& + register_axis, register_restart_field, & + register_variable_attribute, register_field, & + get_global_io_domain_indices, variable_exists + use fv3atm_common_io, only: GFS_Data_transfer, & + create_2d_field_and_add_to_bundle, create_3d_field_and_add_to_bundle + use GFS_typedefs, only: GFS_sfcprop_type, GFS_control_type, kind_phys + use mpp_mod, only: mpp_error, NOTE + use physcons, only: con_tice !saltwater freezing temp (K) + + implicit none + private + + public :: Sfc_io_data_type + public :: Sfc_io_fill_2d_names, Sfc_io_fill_3d_names, Sfc_io_allocate_arrays, & + Sfc_io_register_axes, Sfc_io_write_axes, Sfc_io_register_2d_fields, & + Sfc_io_register_3d_fields, Sfc_io_copy_to_grid, Sfc_io_copy_from_grid, & + Sfc_io_apply_safeguards, Sfc_io_transfer, Sfc_io_final + + !> \defgroup fv3atm_sfc_io module + !> @{ + + !>@ Minimum temperature allowed for snow/ice + real(kind=kind_phys), parameter :: timin = 173.0_kind_phys + + real(kind_phys), parameter:: min_lake_orog = 200.0_kind_phys + real(kind_phys), parameter:: zero = 0, one = 1 + + !> Internal data storage type for reading and writing surface restart files + type Sfc_io_data_type + integer, public :: nvar2o = 0 + integer, public :: nvar3 = 0 + integer, public :: nvar2r = 0 + integer, public :: nvar2mp = 0 + integer, public :: nvar3mp = 0 + integer, public :: nvar2l = 0 + integer, public :: nvar2m = 0 + integer, public :: nvar_before_lake = 0 + + ! The lsoil flag is only meaningful when reading:; + logical, public :: is_lsoil = .false. + + ! SYNONYMS: Some nvar variables had two names in fv3atm_io.F90. They have + ! only one name here. The "_s" is redundant because this file only has + ! surface restart variables. + ! + ! - nvar2m = nvar_s2m + ! - nvar2o = nvar_s2o + ! - nvar2r = nvar_s2r + ! - nvar2mp = nvar_s2mp + ! - nvar3mp = nvar_s3mp + + real(kind=kind_phys), pointer, dimension(:,:,:), public :: var2 => null() + real(kind=kind_phys), pointer, dimension(:,:,:), public :: var3ice => null() + real(kind=kind_phys), pointer, dimension(:,:,:,:), public :: var3 => null() + real(kind=kind_phys), pointer, dimension(:,:,:,:), public :: var3sn => null() + real(kind=kind_phys), pointer, dimension(:,:,:,:), public :: var3eq => null() + real(kind=kind_phys), pointer, dimension(:,:,:,:), public :: var3zn => null() + + character(len=32), pointer, dimension(:), public :: name2 => null() + character(len=32), pointer, dimension(:), public :: name3 => null() + + contains + + procedure, public :: allocate_arrays => Sfc_io_allocate_arrays + procedure, public :: register_axes => Sfc_io_register_axes + procedure, public :: write_axes => Sfc_io_write_axes + procedure, public :: register_2d_fields => Sfc_io_register_2d_fields + procedure, public :: register_3d_fields => Sfc_io_register_3d_fields + procedure, public :: bundle_2d_fields => Sfc_io_bundle_2d_fields + procedure, public :: bundle_3d_fields => Sfc_io_bundle_3d_fields + procedure, public :: fill_2d_names => Sfc_io_fill_2d_names + procedure, public :: fill_3d_names => Sfc_io_fill_3d_names + procedure, public :: init_fields => Sfc_io_init_fields + procedure, public :: transfer => Sfc_io_transfer + procedure, public :: copy_to_grid => Sfc_io_copy_to_grid + procedure, public :: copy_from_grid => Sfc_io_copy_from_grid + procedure, public :: apply_safeguards => Sfc_io_apply_safeguards + + procedure, private :: calculate_indices => Sfc_io_calculate_indices + + final :: Sfc_io_final + end type Sfc_io_data_type + +contains + + !>@brief Calculates all nvar indices in the Sfc_io_data_type + !> \section Sfc_io_data_type%calculate_indices() procedure + !! Calculates all nvar counts, which record the number of fields + !! of various types. These determine array sizes. + !! Returns .true. if any nvar counts changed, or .false. otherwise. + function Sfc_io_calculate_indices(sfc, Model, reading, warm_start) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + logical :: Sfc_io_calculate_indices + logical, intent(in) :: reading, warm_start + + integer :: nvar2m, nvar2o, nvar3, nvar2r, nvar2mp, nvar3mp, nvar2l + integer :: nvar_before_lake + + nvar2m = 48 + if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then + nvar2m = nvar2m + 4 + !nvar2m = nvar2m + 5 + endif + if (Model%cplwav) then + nvar2m = nvar2m + 1 + endif + if (Model%nstf_name(1) > 0) then + nvar2o = 18 + else + nvar2o = 0 + endif + if (Model%lsm == Model%lsm_ruc .and. warm_start) then + if (Model%rdlai) then + nvar2r = 13 + else + nvar2r = 12 + endif + nvar3 = 5 + else + if(.not.reading .and. Model%rdlai) then + nvar2r = 1 + else + nvar2r = 0 + endif + nvar3 = 3 + endif + if (Model%lsm == Model%lsm_noahmp) then + nvar2mp = 29 + nvar3mp = 5 + else + nvar2mp = 0 + nvar3mp = 0 + endif + !CLM Lake and Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + nvar2l = 10 + else + nvar2l = 0 + endif + + nvar_before_lake=nvar2m+nvar2o+nvar2r+nvar2mp + + Sfc_io_calculate_indices = & + nvar2m /= sfc%nvar2m .or. & + nvar2o /= sfc%nvar2o .or. & + nvar3 /= sfc%nvar3 .or. & + nvar2r /= sfc%nvar2r .or. & + nvar2mp /= sfc%nvar2mp .or. & + nvar3mp /= sfc%nvar3mp .or. & + nvar2l /= sfc%nvar2l .or. & + nvar2m /= sfc%nvar2m .or. & + nvar_before_lake /= sfc%nvar_before_lake + + sfc%nvar2m = nvar2m + sfc%nvar2o = nvar2o + sfc%nvar3 = nvar3 + sfc%nvar2r = nvar2r + sfc%nvar2mp = nvar2mp + sfc%nvar3mp = nvar3mp + sfc%nvar2l = nvar2l + sfc%nvar2m = nvar2m + sfc%nvar_before_lake = nvar_before_lake + + end function Sfc_io_calculate_indices + + !>@brief Allocates internal Sfc_io_data_type arrays if array sizes should change. + !> \section Sfc_io_data_type%allocate_arrays() procedure + !! Calls calculate_arrays() to determine if any nvar counts have changed, based + !! on the new arguments. If they have changed, then arrays are reallocated. + !! The arrays will need to be filled with new data at that point, as the contents + !! will be unknown. Returns .true. if arrays were reallocated, and .false. otherwise. + function Sfc_io_allocate_arrays(sfc, Model, Atm_block, reading, warm_start) + implicit none + class(Sfc_io_data_type) :: sfc + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + logical :: Sfc_io_allocate_arrays + logical, intent(in) :: reading, warm_start + + integer :: isc, iec, jsc, jec, npz, nx, ny + + isc = Atm_block%isc + iec = Atm_block%iec + jsc = Atm_block%jsc + jec = Atm_block%jec + npz = Atm_block%npz + nx = (iec - isc + 1) + ny = (jec - jsc + 1) + + Sfc_io_allocate_arrays = sfc%calculate_indices(Model, reading, warm_start) + Sfc_io_allocate_arrays = Sfc_io_allocate_arrays .or. .not. associated(sfc%name2) + + if(Sfc_io_allocate_arrays) then + !--- allocate the various containers needed for restarts + allocate(sfc%name2(sfc%nvar2m+sfc%nvar2o+sfc%nvar2mp+sfc%nvar2r+sfc%nvar2l)) + allocate(sfc%name3(0:sfc%nvar3+sfc%nvar3mp)) + allocate(sfc%var2(nx,ny,sfc%nvar2m+sfc%nvar2o+sfc%nvar2mp+sfc%nvar2r+sfc%nvar2l)) + + ! Note that this may cause problems with RUC LSM for coldstart runs from GFS data + ! if the initial conditions do contain this variable, because Model%kice is 9 for + ! RUC LSM, but tiice in the initial conditions will only have two vertical layers + allocate(sfc%var3ice(nx,ny,Model%kice)) + + if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp .or. (.not.warm_start)) then + allocate(sfc%var3(nx,ny,Model%lsoil,sfc%nvar3)) + elseif (Model%lsm == Model%lsm_ruc) then + allocate(sfc%var3(nx,ny,Model%lsoil_lsm,sfc%nvar3)) + endif + + sfc%var2 = -9999.0_kind_phys + sfc%var3 = -9999.0_kind_phys + sfc%var3ice= -9999.0_kind_phys + + if (Model%lsm == Model%lsm_noahmp) then + allocate(sfc%var3sn(nx,ny,-2:0,4:6)) + allocate(sfc%var3eq(nx,ny,1:4,7:7)) + allocate(sfc%var3zn(nx,ny,-2:4,8:8)) + + sfc%var3sn = -9999.0_kind_phys + sfc%var3eq = -9999.0_kind_phys + sfc%var3zn = -9999.0_kind_phys + endif + endif + + if(Model%lkm>0 .and. Model%iopt_lake==Model%iopt_lake_flake .and. Model%me==0) then + if(size(sfc%name2)/=sfc%nvar_before_lake+10) then +3814 format("ERROR: size mismatch size(sfc%name2)=",I0," /= nvar_before_lake+10=",I0) + write(0,3814) size(sfc%name2),sfc%nvar_before_lake+10 + endif + endif + end function Sfc_io_allocate_arrays + + !>@ Registers all axes for reading or writing restarts using FMS (non-quilt) + subroutine Sfc_io_register_axes(sfc, Model, Sfc_restart, reading, warm_start) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + logical, intent(in) :: reading, warm_start + + if(reading) then + sfc%is_lsoil = .false. + endif + + if(.not.warm_start .and. reading) then + if( variable_exists(Sfc_restart,"lsoil") ) then + if(reading) then + sfc%is_lsoil=.true. + endif + call register_axis(Sfc_restart, 'lon', 'X') + call register_axis(Sfc_restart, 'lat', 'Y') + call register_axis(Sfc_restart, 'lsoil', dimension_length=Model%lsoil) + else + call register_axis(Sfc_restart, 'xaxis_1', 'X') + call register_axis(Sfc_restart, 'yaxis_1', 'Y') + call register_axis(Sfc_restart, 'zaxis_1', dimension_length=4) + call register_axis(Sfc_restart, 'Time', 1) + end if + else + call register_axis(Sfc_restart, 'xaxis_1', 'X') + call register_axis(Sfc_restart, 'yaxis_1', 'Y') + call register_axis(Sfc_restart, 'zaxis_1', dimension_length=Model%kice) + if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then + call register_axis(Sfc_restart, 'zaxis_2', dimension_length=Model%lsoil) + else if(Model%lsm == Model%lsm_ruc .and. reading) then + call register_axis(Sfc_restart, 'zaxis_2', dimension_length=Model%lsoil_lsm) + ! The RUC only ever writes zaxis_1, which is combined soil/ice + ! vertical dimension, lsoil_lsm/kice, which is 9. Other LSMs read and + ! write zaxis_2, which is lsoil for them, and that's always 4. + ! Defining zaxis_2 here lets RUC LSM read from a different soil + ! vertical coordinate (lsoil_lsm). It is needed for restart of RUC LSM + ! from RUC LSM. This capability exists for historical reasons, because + ! there are two sets of soil state variables: one set has lsoil=4 + ! vertical layers (Noah LSM. NoahMP LSM), and another set has + ! lsoil_lsm=9 vertical levels (RUC LSM). Ideally there should be just + ! one set of soil variables that could have different vertical + ! dimension depending on the choice of LSM. For now: just make sure + ! you only restart RUC LSM off of RUC LSM, and always have kice = + ! lsoil = lsoil_lsm = 9 and everything will be fine. + endif + if(Model%lsm == Model%lsm_noahmp) then + call register_axis(Sfc_restart, 'zaxis_3', dimension_length=3) + call register_axis(Sfc_restart, 'zaxis_4', dimension_length=7) + end if + call register_axis(Sfc_restart, 'Time', unlimited) + endif + end subroutine Sfc_io_register_axes + + !>@ Writes axis index variables and related metadata for all axes when writing FMS (non-quilt) restarts + subroutine Sfc_io_write_axes(sfc, Model, Sfc_restart) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + + integer, allocatable :: buffer(:) + integer :: i, is, ie + logical :: mand + + call register_field(Sfc_restart, 'xaxis_1', 'double', (/'xaxis_1'/)) + call register_variable_attribute(Sfc_restart, 'xaxis_1', 'cartesian_axis', 'X', str_len=1) + call get_global_io_domain_indices(Sfc_restart, 'xaxis_1', is, ie, indices=buffer) + call write_data(Sfc_restart, "xaxis_1", buffer) + deallocate(buffer) + + call register_field(Sfc_restart, 'yaxis_1', 'double', (/'yaxis_1'/)) + call register_variable_attribute(Sfc_restart, 'yaxis_1', 'cartesian_axis', 'Y', str_len=1) + call get_global_io_domain_indices(Sfc_restart, 'yaxis_1', is, ie, indices=buffer) + call write_data(Sfc_restart, "yaxis_1", buffer) + deallocate(buffer) + + call register_field(Sfc_restart, 'zaxis_1', 'double', (/'zaxis_1'/)) + call register_variable_attribute(Sfc_restart, 'zaxis_1', 'cartesian_axis', 'Z', str_len=1) + allocate( buffer(Model%kice) ) + do i=1, Model%kice + buffer(i) = i + end do + call write_data(Sfc_restart, 'zaxis_1', buffer) + deallocate(buffer) + + if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp) then + call register_field(Sfc_restart, 'zaxis_2', 'double', (/'zaxis_2'/)) + call register_variable_attribute(Sfc_restart, 'zaxis_2', 'cartesian_axis', 'Z', str_len=1) + allocate( buffer(Model%lsoil) ) + do i=1, Model%lsoil + buffer(i)=i + end do + call write_data(Sfc_restart, 'zaxis_2', buffer) + deallocate(buffer) + endif + + if(Model%lsm == Model%lsm_noahmp) then + call register_field(Sfc_restart, 'zaxis_3', 'double', (/'zaxis_3'/)) + call register_variable_attribute(Sfc_restart, 'zaxis_3', 'cartesian_axis', 'Z', str_len=1) + allocate(buffer(3)) + do i=1, 3 + buffer(i) = i + end do + call write_data(Sfc_restart, 'zaxis_3', buffer) + deallocate(buffer) + + call register_field(Sfc_restart, 'zaxis_4', 'double', (/'zaxis_4'/)) + call register_variable_attribute(Sfc_restart, 'zaxis_4', 'cartesian_axis' ,'Z', str_len=1) + allocate(buffer(7)) + do i=1, 7 + buffer(i)=i + end do + call write_data(Sfc_restart, 'zaxis_4', buffer) + deallocate(buffer) + end if + call register_field(Sfc_restart, 'Time', 'double', (/'Time'/)) + call register_variable_attribute(Sfc_restart, 'Time', 'cartesian_axis', 'T', str_len=1) + call write_data( Sfc_restart, 'Time', 1) + end subroutine Sfc_io_write_axes + + !>@ Fills the name3d array with all surface 3D field names. + subroutine Sfc_io_fill_3d_names(sfc,Model,warm_start) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + logical, intent(in) :: warm_start + integer :: nt + + !--- names of the 3d variables to save + if (Model%lsm == Model%lsm_noah .or. Model%lsm == Model%lsm_noahmp .or. (.not.warm_start)) then + !--- names of the 3D variables to save + sfc%name3(1) = 'stc' + sfc%name3(2) = 'smc' + sfc%name3(3) = 'slc' + if (Model%lsm == Model%lsm_noahmp) then + sfc%name3(4) = 'snicexy' + sfc%name3(5) = 'snliqxy' + sfc%name3(6) = 'tsnoxy' + sfc%name3(7) = 'smoiseq' + sfc%name3(8) = 'zsnsoxy' + endif + else if (Model%lsm == Model%lsm_ruc) then + !--- names of the 3D variables to save + sfc%name3(1) = 'tslb' + sfc%name3(2) = 'smois' + sfc%name3(3) = 'sh2o' + sfc%name3(4) = 'smfr' + sfc%name3(5) = 'flfr' + end if + sfc%name3(0) = 'tiice' + end subroutine Sfc_io_fill_3d_names + + !>@ Fills the name2d array with all surface 2D field names. Updates nvar2m if needed. + subroutine Sfc_io_fill_2d_names(sfc,Model,warm_start) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + logical, intent(in) :: warm_start + integer :: nt + + !--- names of the 2D variables to save + nt=0 + nt=nt+1 ; sfc%name2(nt) = 'slmsk' + nt=nt+1 ; sfc%name2(nt) = 'tsea' !tsfc + nt=nt+1 ; sfc%name2(nt) = 'sheleg' !weasd + nt=nt+1 ; sfc%name2(nt) = 'tg3' + nt=nt+1 ; sfc%name2(nt) = 'zorl' + nt=nt+1 ; sfc%name2(nt) = 'alvsf' + nt=nt+1 ; sfc%name2(nt) = 'alvwf' + nt=nt+1 ; sfc%name2(nt) = 'alnsf' + nt=nt+1 ; sfc%name2(nt) = 'alnwf' + nt=nt+1 ; sfc%name2(nt) = 'facsf' + nt=nt+1 ; sfc%name2(nt) = 'facwf' + nt=nt+1 ; sfc%name2(nt) = 'vfrac' + nt=nt+1 ; sfc%name2(nt) = 'canopy' + nt=nt+1 ; sfc%name2(nt) = 'f10m' + nt=nt+1 ; sfc%name2(nt) = 't2m' + nt=nt+1 ; sfc%name2(nt) = 'q2m' + nt=nt+1 ; sfc%name2(nt) = 'vtype' + nt=nt+1 ; sfc%name2(nt) = 'stype' + nt=nt+1 ; sfc%name2(nt) = 'uustar' + nt=nt+1 ; sfc%name2(nt) = 'ffmm' + nt=nt+1 ; sfc%name2(nt) = 'ffhh' + nt=nt+1 ; sfc%name2(nt) = 'hice' + nt=nt+1 ; sfc%name2(nt) = 'fice' + nt=nt+1 ; sfc%name2(nt) = 'tisfc' + nt=nt+1 ; sfc%name2(nt) = 'tprcp' + nt=nt+1 ; sfc%name2(nt) = 'srflag' + nt=nt+1 ; sfc%name2(nt) = 'snwdph' !snowd + nt=nt+1 ; sfc%name2(nt) = 'shdmin' + nt=nt+1 ; sfc%name2(nt) = 'shdmax' + nt=nt+1 ; sfc%name2(nt) = 'slope' + nt=nt+1 ; sfc%name2(nt) = 'snoalb' + !--- variables below here are optional + nt=nt+1 ; sfc%name2(nt) = 'sncovr' + nt=nt+1 ; sfc%name2(nt) = 'snodl' !snowd on land portion of a cell + nt=nt+1 ; sfc%name2(nt) = 'weasdl'!weasd on land portion of a cell + nt=nt+1 ; sfc%name2(nt) = 'tsfc' !tsfc composite + nt=nt+1 ; sfc%name2(nt) = 'tsfcl' !temp on land portion of a cell + nt=nt+1 ; sfc%name2(nt) = 'zorlw' !zorl on water portion of a cell + nt=nt+1 ; sfc%name2(nt) = 'zorll' !zorl on land portion of a cell + nt=nt+1 ; sfc%name2(nt) = 'zorli' !zorl on ice portion of a cell + nt=nt+1 ; sfc%name2(nt) = 'albdirvis_lnd' + nt=nt+1 ; sfc%name2(nt) = 'albdirnir_lnd' + nt=nt+1 ; sfc%name2(nt) = 'albdifvis_lnd' + nt=nt+1 ; sfc%name2(nt) = 'albdifnir_lnd' + nt=nt+1 ; sfc%name2(nt) = 'emis_lnd' + nt=nt+1 ; sfc%name2(nt) = 'emis_ice' + nt=nt+1 ; sfc%name2(nt) = 'sncovr_ice' + nt=nt+1 ; sfc%name2(nt) = 'snodi' ! snowd on ice portion of a cell + nt=nt+1 ; sfc%name2(nt) = 'weasdi'! weasd on ice portion of a cell + + if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then + nt=nt+1 ; sfc%name2(nt) = 'albdirvis_ice' + nt=nt+1 ; sfc%name2(nt) = 'albdifvis_ice' + nt=nt+1 ; sfc%name2(nt) = 'albdirnir_ice' + nt=nt+1 ; sfc%name2(nt) = 'albdifnir_ice' + endif + + if(Model%cplwav) then + nt=nt+1 ; sfc%name2(nt) = 'zorlwav' !zorl from wave component + sfc%nvar2m = nt + endif + + if (Model%nstf_name(1) > 0) then + !--- NSSTM inputs only needed when (nstf_name(1) > 0) .and. (nstf_name(2)) == 0) + nt=nt+1 ; sfc%name2(nt) = 'tref' + nt=nt+1 ; sfc%name2(nt) = 'z_c' + nt=nt+1 ; sfc%name2(nt) = 'c_0' + nt=nt+1 ; sfc%name2(nt) = 'c_d' + nt=nt+1 ; sfc%name2(nt) = 'w_0' + nt=nt+1 ; sfc%name2(nt) = 'w_d' + nt=nt+1 ; sfc%name2(nt) = 'xt' + nt=nt+1 ; sfc%name2(nt) = 'xs' + nt=nt+1 ; sfc%name2(nt) = 'xu' + nt=nt+1 ; sfc%name2(nt) = 'xv' + nt=nt+1 ; sfc%name2(nt) = 'xz' + nt=nt+1 ; sfc%name2(nt) = 'zm' + nt=nt+1 ; sfc%name2(nt) = 'xtts' + nt=nt+1 ; sfc%name2(nt) = 'xzts' + nt=nt+1 ; sfc%name2(nt) = 'd_conv' + nt=nt+1 ; sfc%name2(nt) = 'ifd' + nt=nt+1 ; sfc%name2(nt) = 'dt_cool' + nt=nt+1 ; sfc%name2(nt) = 'qrain' + endif + ! + ! Only needed when Noah MP LSM is used - 29 2D + ! + if (Model%lsm == Model%lsm_noahmp) then + nt=nt+1 ; sfc%name2(nt) = 'snowxy' + nt=nt+1 ; sfc%name2(nt) = 'tvxy' + nt=nt+1 ; sfc%name2(nt) = 'tgxy' + nt=nt+1 ; sfc%name2(nt) = 'canicexy' + nt=nt+1 ; sfc%name2(nt) = 'canliqxy' + nt=nt+1 ; sfc%name2(nt) = 'eahxy' + nt=nt+1 ; sfc%name2(nt) = 'tahxy' + nt=nt+1 ; sfc%name2(nt) = 'cmxy' + nt=nt+1 ; sfc%name2(nt) = 'chxy' + nt=nt+1 ; sfc%name2(nt) = 'fwetxy' + nt=nt+1 ; sfc%name2(nt) = 'sneqvoxy' + nt=nt+1 ; sfc%name2(nt) = 'alboldxy' + nt=nt+1 ; sfc%name2(nt) = 'qsnowxy' + nt=nt+1 ; sfc%name2(nt) = 'wslakexy' + nt=nt+1 ; sfc%name2(nt) = 'zwtxy' + nt=nt+1 ; sfc%name2(nt) = 'waxy' + nt=nt+1 ; sfc%name2(nt) = 'wtxy' + nt=nt+1 ; sfc%name2(nt) = 'lfmassxy' + nt=nt+1 ; sfc%name2(nt) = 'rtmassxy' + nt=nt+1 ; sfc%name2(nt) = 'stmassxy' + nt=nt+1 ; sfc%name2(nt) = 'woodxy' + nt=nt+1 ; sfc%name2(nt) = 'stblcpxy' + nt=nt+1 ; sfc%name2(nt) = 'fastcpxy' + nt=nt+1 ; sfc%name2(nt) = 'xsaixy' + nt=nt+1 ; sfc%name2(nt) = 'xlaixy' + nt=nt+1 ; sfc%name2(nt) = 'taussxy' + nt=nt+1 ; sfc%name2(nt) = 'smcwtdxy' + nt=nt+1 ; sfc%name2(nt) = 'deeprechxy' + nt=nt+1 ; sfc%name2(nt) = 'rechxy' + else if (Model%lsm == Model%lsm_ruc .and. warm_start) then + nt=nt+1 ; sfc%name2(nt) = 'wetness' + nt=nt+1 ; sfc%name2(nt) = 'clw_surf_land' + nt=nt+1 ; sfc%name2(nt) = 'clw_surf_ice' + nt=nt+1 ; sfc%name2(nt) = 'qwv_surf_land' + nt=nt+1 ; sfc%name2(nt) = 'qwv_surf_ice' + nt=nt+1 ; sfc%name2(nt) = 'tsnow_land' + nt=nt+1 ; sfc%name2(nt) = 'tsnow_ice' + nt=nt+1 ; sfc%name2(nt) = 'snowfall_acc_land' + nt=nt+1 ; sfc%name2(nt) = 'snowfall_acc_ice' + nt=nt+1 ; sfc%name2(nt) = 'sfalb_lnd' + nt=nt+1 ; sfc%name2(nt) = 'sfalb_lnd_bck' + nt=nt+1 ; sfc%name2(nt) = 'sfalb_ice' + if (Model%rdlai) then + nt=nt+1 ; sfc%name2(nt) = 'lai' + endif + else if (Model%lsm == Model%lsm_ruc .and. Model%rdlai) then + nt=nt+1 ; sfc%name2(nt) = 'lai' + endif + + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + nt=nt+1 ; sfc%name2(nt) = 'T_snow' + nt=nt+1 ; sfc%name2(nt) = 'T_ice' + nt=nt+1 ; sfc%name2(nt) = 'h_ML' + nt=nt+1 ; sfc%name2(nt) = 't_ML' + nt=nt+1 ; sfc%name2(nt) = 't_mnw' + nt=nt+1 ; sfc%name2(nt) = 'h_talb' + nt=nt+1 ; sfc%name2(nt) = 't_talb' + nt=nt+1 ; sfc%name2(nt) = 't_bot1' + nt=nt+1 ; sfc%name2(nt) = 't_bot2' + nt=nt+1 ; sfc%name2(nt) = 'c_t' + endif + end subroutine Sfc_io_fill_2d_names + + !>@ Registers 2D fields with FMS for reading or writing non-quilt restart files + subroutine Sfc_io_register_2d_fields(sfc,Model,Sfc_restart,reading,warm_start) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + logical, intent(in) :: reading, warm_start + + real(kind=kind_phys), pointer, dimension(:,:) :: var2_p => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p1 => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p2 => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p3 => NULL() + integer :: num + logical :: mand + + character(len=7) :: time2d(3) + + if(.not.reading) then + time2d=(/'xaxis_1','yaxis_1','Time '/) + else + time2d=(/'Time ','yaxis_1','xaxis_1'/) + endif + + !--- register the 2D fields + do num = 1,sfc%nvar2m + var2_p => sfc%var2(:,:,num) + if (trim(sfc%name2(num)) == 'sncovr' .or. trim(sfc%name2(num)) == 'tsfcl' .or. trim(sfc%name2(num)) == 'zorll' & + .or. trim(sfc%name2(num)) == 'zorli' .or. trim(sfc%name2(num)) == 'zorlwav' & + .or. trim(sfc%name2(num)) == 'snodl' .or. trim(sfc%name2(num)) == 'weasdl' & + .or. trim(sfc%name2(num)) == 'snodi' .or. trim(sfc%name2(num)) == 'weasdi' & + .or. trim(sfc%name2(num)) == 'tsfc' .or. trim(sfc%name2(num)) == 'zorlw' & + .or. trim(sfc%name2(num)) == 'albdirvis_lnd' .or. trim(sfc%name2(num)) == 'albdirnir_lnd' & + .or. trim(sfc%name2(num)) == 'albdifvis_lnd' .or. trim(sfc%name2(num)) == 'albdifnir_lnd' & + .or. trim(sfc%name2(num)) == 'albdirvis_ice' .or. trim(sfc%name2(num)) == 'albdirnir_ice' & + .or. trim(sfc%name2(num)) == 'albdifvis_ice' .or. trim(sfc%name2(num)) == 'albdifnir_ice' & + .or. trim(sfc%name2(num)) == 'emis_lnd' .or. trim(sfc%name2(num)) == 'emis_ice' & + .or. trim(sfc%name2(num)) == 'sncovr_ice') then + if(reading .and. sfc%is_lsoil) then + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=(/'lat','lon'/), is_optional=.true.) + else + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=time2d,& + &is_optional=.true.) + end if + else + if(reading .and. sfc%is_lsoil) then + call register_restart_field(Sfc_restart,sfc%name2(num),var2_p, dimensions=(/'lat','lon'/)) + else + call register_restart_field(Sfc_restart,sfc%name2(num),var2_p, dimensions=time2d) + end if + endif + enddo + + if (Model%nstf_name(1) > 0) then + mand = .false. + if (Model%nstf_name(2) == 0) mand = .true. + do num = sfc%nvar2m+1,sfc%nvar2m+sfc%nvar2o + var2_p => sfc%var2(:,:,num) + if(sfc%is_lsoil) then + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=(/'lat','lon'/), is_optional=.not.mand) + else + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=time2d, is_optional=.not.mand) + endif + enddo + endif + + if (Model%lsm == Model%lsm_ruc) then ! sfc%nvar2mp = 0 + do num = sfc%nvar2m+sfc%nvar2o+1, sfc%nvar2m+sfc%nvar2o+sfc%nvar2r + var2_p => sfc%var2(:,:,num) + if(sfc%is_lsoil) then + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=(/'lat','lon'/) ) + else + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=time2d) + end if + enddo + endif ! mp/ruc + + ! Noah MP register only necessary only lsm = 2, not necessary has values + if ( (.not.reading .and. Model%lsm == Model%lsm_noahmp) & + .or. (reading .and. sfc%nvar2mp > 0) ) then + mand = .not.reading + do num = sfc%nvar2m+sfc%nvar2o+1,sfc%nvar2m+sfc%nvar2o+sfc%nvar2mp + var2_p => sfc%var2(:,:,num) + if(sfc%is_lsoil) then + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=(/'lat','lon'/), is_optional=.not.mand) + else + call register_restart_field(Sfc_restart, sfc%name2(num), var2_p, dimensions=time2d, is_optional=.not.mand) + end if + enddo + endif ! noahmp + + ! Flake + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + mand = .not.reading + do num = sfc%nvar_before_lake+1,sfc%nvar_before_lake+sfc%nvar2l + var2_p => sfc%var2(:,:,num) + if(sfc%is_lsoil) then + call register_restart_field(Sfc_restart, sfc%name2(num),var2_p,dimensions=(/'lat','lon'/), is_optional=.not.mand) + else + call register_restart_field(Sfc_restart, sfc%name2(num),var2_p,dimensions=time2d, is_optional=.not.mand) + endif + enddo + endif + + end subroutine Sfc_io_register_2d_fields + + !>@ Registers 3D fields with FMS for reading or writing non-quilt restart files + subroutine Sfc_io_register_3d_fields(sfc,Model,Sfc_restart,reading,warm_start) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + type(FmsNetcdfDomainFile_t) :: Sfc_restart + logical, intent(in) :: reading, warm_start + + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p1 => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p2 => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_p3 => NULL() + real(kind=kind_phys), pointer, dimension(:,:,:) :: var3_fr => NULL() + integer :: num + logical :: mand + + character(len=7), parameter :: xyz1_time(4) = (/'xaxis_1', 'yaxis_1', 'zaxis_1', 'Time '/) + character(len=7), parameter :: xyz2_time(4) = (/'xaxis_1', 'yaxis_1', 'zaxis_2', 'Time '/) + character(len=7), parameter :: xyz3_time(4) = (/'xaxis_1', 'yaxis_1', 'zaxis_3', 'Time '/) + character(len=7), parameter :: xyz4_time(4) = (/'xaxis_1', 'yaxis_1', 'zaxis_4', 'Time '/) + + !--- register the 3D fields + var3_p => sfc%var3ice(:,:,:) + call register_restart_field(Sfc_restart, sfc%name3(0), var3_p, dimensions=xyz1_time, is_optional=.true.) + + if(reading) then + do num = 1,sfc%nvar3 + var3_p => sfc%var3(:,:,:,num) + if ( warm_start ) then + call register_restart_field(Sfc_restart, sfc%name3(num), var3_p, dimensions=(/'xaxis_1', 'yaxis_1', 'lsoil ', 'Time '/),& + &is_optional=.true.) + else + if(sfc%is_lsoil) then + call register_restart_field(Sfc_restart, sfc%name3(num), var3_p, dimensions=(/'lat ', 'lon ', 'lsoil'/), is_optional=.true.) + else + call register_restart_field(Sfc_restart, sfc%name3(num), var3_p, dimensions=xyz2_time,& + &is_optional=.true.) + end if + end if + enddo + elseif(Model%lsm == Model%lsm_ruc) then + do num = 1,sfc%nvar3 + var3_p => sfc%var3(:,:,:,num) + call register_restart_field(Sfc_restart, sfc%name3(num), var3_p, dimensions=xyz1_time) + enddo + nullify(var3_p) + else ! writing something other than ruc + do num = 1,sfc%nvar3 + var3_p => sfc%var3(:,:,:,num) + call register_restart_field(Sfc_restart, sfc%name3(num), var3_p, dimensions=xyz2_time) + enddo + nullify(var3_p) + endif + + if (Model%lsm == Model%lsm_noahmp) then + mand = .not.reading + do num = sfc%nvar3+1,sfc%nvar3+3 + var3_p1 => sfc%var3sn(:,:,:,num) + call register_restart_field(Sfc_restart, sfc%name3(num), var3_p1, dimensions=xyz3_time, is_optional=.not.mand) + enddo + + var3_p2 => sfc%var3eq(:,:,:,7) + call register_restart_field(Sfc_restart, sfc%name3(7), var3_p2, dimensions=xyz2_time, is_optional=.not.mand) + + var3_p3 => sfc%var3zn(:,:,:,8) + call register_restart_field(Sfc_restart, sfc%name3(8), var3_p3, dimensions=xyz4_time, is_optional=.not.mand) + endif !mp + + end subroutine Sfc_io_register_3d_fields + + !>@ Initializes some surface fields with reasonable defaults + subroutine Sfc_io_init_fields(sfc,Model) + implicit none + class(Sfc_io_data_type) :: sfc + type(GFS_control_type), intent(in) :: Model + + !--- Noah MP define arbitrary value (number layers of snow) to indicate + !coldstart(sfcfile doesn't include noah mp fields) or not + + if (Model%lsm == Model%lsm_noahmp) then + sfc%var2(1,1,sfc%nvar2m+19) = -66666.0_kind_phys + endif + end subroutine Sfc_io_init_fields + + !>@ Copies data to the model grid (reading=true) or from the model grid (reading=false) + !> \section Sfc_io_data_type%transfer + !! Called to transfer data between the model grid and Sfc_io_data_type temporary arrays. + !! The FMS and ESMF restarts use the temporary arrays, not the model grid arrays. This + !! transfer routine copies to the model grid if reading=.true. or from the model grid + !! if reading=.false. This is mostly loops around GFS_data_transfer() interface calls. + !! + !! In addition, if override_frac_grid is provided, it will be set to Model%frac_grid. + subroutine Sfc_io_transfer(sfc, reading, Model, Atm_block, Sfcprop, warm_start, override_frac_grid) + !--- interface variable definitions + implicit none + + class(Sfc_io_data_type) :: sfc + logical, intent(in) :: reading + type(GFS_sfcprop_type) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + logical, intent(in) :: warm_start + logical, intent(out), optional :: override_frac_grid + + integer :: i, j, k, nb, ix, lsoil, num, nt + integer :: isc, iec, jsc, jec, npz, nx, ny + integer, allocatable :: ii1(:), jj1(:) + real(kind_phys) :: ice + + ! "To" variable: + ! to=.TRUE. means transfer sfc data TO Sfcprop grid + ! to=.FALSE. means transfer into sfc data FROM Sfcprop grid + + isc = Atm_block%isc + iec = Atm_block%iec + jsc = Atm_block%jsc + jec = Atm_block%jec + npz = Atm_block%npz + nx = (iec - isc + 1) + ny = (jec - jsc + 1) + + ! write(0,*)' stype read in min,max=',minval(sfc_var2(:,:,35)),maxval(sfc_var2(:,:,35)),' sfc_name2=',sfc_name2(35) + ! write(0,*)' stype read in min,max=',minval(sfc_var2(:,:,18)),maxval(sfc_var2(:,:,18)) + ! write(0,*)' sfc_var2=',sfc_var2(:,:,12) + + !$omp parallel do default(shared) private(i, j, nb, ix, nt, ii1, jj1, lsoil) + block_loop: do nb = 1, Atm_block%nblks + allocate(ii1(Atm_block%blksz(nb))) + allocate(jj1(Atm_block%blksz(nb))) + ii1=Atm_block%index(nb)%ii - isc + 1 + jj1=Atm_block%index(nb)%jj - jsc + 1 + + nt=0 + + !--- 2D variables + ! ------------ + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%slmsk) !--- slmsk + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tsfco) !--- tsfc (tsea in sfc file) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%weasd) !--- weasd (sheleg in sfc file) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tg3) !--- tg3 + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%zorl) !--- zorl composite + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%alvsf) !--- alvsf + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%alvwf) !--- alvwf + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%alnsf) !--- alnsf + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%alnwf) !--- alnwf + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%facsf) !--- facsf + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%facwf) !--- facwf + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%vfrac) !--- vfrac + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%canopy) !--- canopy + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%f10m) !--- f10m + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%t2m) !--- t2m + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%q2m) !--- q2m + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%vtype) !--- vtype + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%stype) !--- stype + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%uustar) !--- uustar + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%ffmm) !--- ffmm + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%ffhh) !--- ffhh + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%hice) !--- hice + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%fice) !--- fice + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tisfc) !--- tisfc + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tprcp) !--- tprcp + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%srflag) !--- srflag + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%snowd) !--- snowd (snwdph in the file) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%shdmin) !--- shdmin + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%shdmax) !--- shdmax + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%slope) !--- slope + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%snoalb) !--- snoalb + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%sncovr) !--- sncovr + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%snodl) !--- snodl (snowd on land portion of a cell) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%weasdl) !--- weasdl (weasd on land portion of a cell) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tsfc) !--- tsfc composite + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tsfcl) !--- tsfcl (temp on land portion of a cell) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%zorlw) !--- zorlw (zorl on water portion of a cell) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%zorll) !--- zorll (zorl on land portion of a cell) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%zorli) !--- zorli (zorl on ice portion of a cell) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdirvis_lnd) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdirnir_lnd) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdifvis_lnd) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdifnir_lnd) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%emis_lnd) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%emis_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%sncovr_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%snodi) !--- snodi (snowd on ice portion of a cell) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%weasdi) !--- weasdi (weasd on ice portion of a cell) + if (Model%use_cice_alb .or. Model%lsm == Model%lsm_ruc) then + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdirvis_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdifvis_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdirnir_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%albdifnir_ice) + ! call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%sfalb_ice) + endif + if(Model%cplwav) then + !tgs - the following line is a bug. It should be nt = nt + !nt = sfc%nvar2m-1 ! Next item will be at sfc%nvar2m + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%zorlwav) !--- (zorl from wave model) + else if(reading) then + Sfcprop(nb)%zorlwav = Sfcprop(nb)%zorlw + endif + + if(present(override_frac_grid)) then + override_frac_grid=Model%frac_grid + endif + + if(reading) then + do_lsi_fractions: do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%stype(ix) == 14 .or. Sfcprop(nb)%stype(ix) <= 0) then + Sfcprop(nb)%landfrac(ix) = zero + Sfcprop(nb)%stype(ix) = 0 + if (Sfcprop(nb)%lakefrac(ix) > zero) then + Sfcprop(nb)%lakefrac(ix) = one + endif + endif + + if_frac_grid: if (Model%frac_grid) then + if (Sfcprop(nb)%landfrac(ix) > -999.0_kind_phys) then + Sfcprop(nb)%slmsk(ix) = ceiling(Sfcprop(nb)%landfrac(ix)-1.0e-6) + if (Sfcprop(nb)%slmsk(ix) == 1 .and. Sfcprop(nb)%stype(ix) == 14) & + Sfcprop(nb)%slmsk(ix) = 0 + if (Sfcprop(nb)%lakefrac(ix) > zero) then + Sfcprop(nb)%oceanfrac(ix) = zero ! lake & ocean don't coexist in a cell + if (nint(Sfcprop(nb)%slmsk(ix)) /= 1) then + if(Sfcprop(nb)%fice(ix) >= Model%min_lakeice) then + Sfcprop(nb)%slmsk(ix) = 2 + else + Sfcprop(nb)%slmsk(ix) = 0 + endif + endif + else + Sfcprop(nb)%lakefrac(ix) = zero + Sfcprop(nb)%oceanfrac(ix) = one - Sfcprop(nb)%landfrac(ix) + if (nint(Sfcprop(nb)%slmsk(ix)) /= 1) then + if (Sfcprop(nb)%fice(ix) >= Model%min_seaice) then + Sfcprop(nb)%slmsk(ix) = 2 + else + Sfcprop(nb)%slmsk(ix) = 0 + endif + endif + endif + else + if(present(override_frac_grid)) then + override_frac_grid = .false. + endif + if (nint(Sfcprop(nb)%slmsk(ix)) == 1) then + Sfcprop(nb)%landfrac(ix) = one + Sfcprop(nb)%lakefrac(ix) = zero + Sfcprop(nb)%oceanfrac(ix) = zero + else + if (Sfcprop(nb)%slmsk(ix) < 0.1_kind_phys .or. Sfcprop(nb)%slmsk(ix) > 1.9_kind_phys) then + Sfcprop(nb)%landfrac(ix) = zero + if (Sfcprop(nb)%oro_uf(ix) > min_lake_orog) then ! lakes + Sfcprop(nb)%lakefrac(ix) = one + Sfcprop(nb)%oceanfrac(ix) = zero + else ! ocean + Sfcprop(nb)%lakefrac(ix) = zero + Sfcprop(nb)%oceanfrac(ix) = one + endif + endif + endif + endif + else ! not a fractional grid + if (Sfcprop(nb)%landfrac(ix) > -999.0_kind_phys) then + if (Sfcprop(nb)%lakefrac(ix) > zero) then + Sfcprop(nb)%oceanfrac(ix) = zero + Sfcprop(nb)%landfrac(ix) = zero + Sfcprop(nb)%lakefrac(ix) = one + Sfcprop(nb)%slmsk(ix) = zero + if (Sfcprop(nb)%fice(ix) >= Model%min_lakeice) Sfcprop(nb)%slmsk(ix) = 2.0 + else + Sfcprop(nb)%slmsk(ix) = nint(Sfcprop(nb)%landfrac(ix)) + if (Sfcprop(nb)%stype(ix) <= 0 .or. Sfcprop(nb)%stype(ix) == 14) & + Sfcprop(nb)%slmsk(ix) = zero + if (nint(Sfcprop(nb)%slmsk(ix)) == 0) then + Sfcprop(nb)%oceanfrac(ix) = one + Sfcprop(nb)%landfrac(ix) = zero + Sfcprop(nb)%lakefrac(ix) = zero + if (Sfcprop(nb)%fice(ix) >= Model%min_seaice) Sfcprop(nb)%slmsk(ix) = 2.0 + else + Sfcprop(nb)%landfrac(ix) = one + Sfcprop(nb)%lakefrac(ix) = zero + Sfcprop(nb)%oceanfrac(ix) = zero + endif + endif + else + if (nint(Sfcprop(nb)%slmsk(ix)) == 1 .and. Sfcprop(nb)%stype(ix) > 0 & + .and. Sfcprop(nb)%stype(ix) /= 14) then + Sfcprop(nb)%landfrac(ix) = one + Sfcprop(nb)%lakefrac(ix) = zero + Sfcprop(nb)%oceanfrac(ix) = zero + else + Sfcprop(nb)%slmsk(ix) = zero + Sfcprop(nb)%landfrac(ix) = zero + if (Sfcprop(nb)%oro_uf(ix) > min_lake_orog) then ! lakes + Sfcprop(nb)%lakefrac(ix) = one + Sfcprop(nb)%oceanfrac(ix) = zero + if (Sfcprop(nb)%fice(ix) > Model%min_lakeice) Sfcprop(nb)%slmsk(ix) = 2.0 + else ! ocean + Sfcprop(nb)%lakefrac(ix) = zero + Sfcprop(nb)%oceanfrac(ix) = one + if (Sfcprop(nb)%fice(ix) > Model%min_seaice) Sfcprop(nb)%slmsk(ix) = 2.0 + endif + endif + endif + endif if_frac_grid + enddo do_lsi_fractions + endif + + if (reading .and. warm_start .and. Model%kdt > 1) then + do ix = 1, Atm_block%blksz(nb) + Sfcprop(nb)%slmsk(ix) = sfc%var2(ii1(ix),jj1(ix),1) !--- slmsk + enddo + endif + + ! + !--- NSSTM variables + !tgs - the following line is a bug that will show if(Model%cplwav) = true + !nt = sfc%nvar2m + if (Model%nstf_name(1) > 0) then + if (reading .and. Model%nstf_name(2) == 1) then ! nsst spinup + !--- nsstm tref + nt = nt + 18 + Sfcprop(nb)%tref = Sfcprop(nb)%tsfco + Sfcprop(nb)%z_c = zero + Sfcprop(nb)%c_0 = zero + Sfcprop(nb)%c_d = zero + Sfcprop(nb)%w_0 = zero + Sfcprop(nb)%w_d = zero + Sfcprop(nb)%xt = zero + Sfcprop(nb)%xs = zero + Sfcprop(nb)%xu = zero + Sfcprop(nb)%xv = zero + Sfcprop(nb)%xz = 20.0_kind_phys + Sfcprop(nb)%zm = zero + Sfcprop(nb)%xtts = zero + Sfcprop(nb)%xzts = zero + Sfcprop(nb)%d_conv = zero + Sfcprop(nb)%ifd = zero + Sfcprop(nb)%dt_cool = zero + Sfcprop(nb)%qrain = zero + elseif (.not.reading .or. Model%nstf_name(2) == 0) then ! nsst restart + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tref) !--- nsstm tref + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%z_c) !--- nsstm z_c + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%c_0) !--- nsstm c_0 + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%c_d) !--- nsstm c_d + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%w_0) !--- nsstm w_0 + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%w_d) !--- nsstm w_d + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xt) !--- nsstm xt + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xs) !--- nsstm xs + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xu) !--- nsstm xu + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xv) !--- nsstm xv + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xz) !--- nsstm xz + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%zm) !--- nsstm zm + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xtts) !--- nsstm xtts + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xzts) !--- nsstm xzts + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%d_conv) !--- nsstm d_conv + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%ifd) !--- nsstm ifd + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%dt_cool) !--- nsstm dt_cool + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%qrain) !--- nsstm qrain + endif + endif + + if (Model%lsm == Model%lsm_ruc .and. (warm_start .or. .not. reading)) then + !--- Extra RUC variables + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%wetness) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%clw_surf_land) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%clw_surf_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%qwv_surf_land) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%qwv_surf_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tsnow_land) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tsnow_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%snowfallac_land) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%snowfallac_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%sfalb_lnd) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%sfalb_lnd_bck) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%sfalb_ice) + if (Model%rdlai) then + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xlaixy) + endif + else if (reading .and. Model%lsm == Model%lsm_ruc) then + ! Initialize RUC snow cover on ice from snow cover + Sfcprop(nb)%sncovr_ice = Sfcprop(nb)%sncovr + if (Model%rdlai) then + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xlaixy) + end if + elseif (Model%lsm == Model%lsm_noahmp) then + !--- Extra Noah MP variables + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%snowxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tvxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tgxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%canicexy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%canliqxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%eahxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%tahxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%cmxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%chxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%fwetxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%sneqvoxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%alboldxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%qsnowxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%wslakexy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%zwtxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%waxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%wtxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%lfmassxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%rtmassxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%stmassxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%woodxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%stblcpxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%fastcpxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xsaixy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%xlaixy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%taussxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%smcwtdxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%deeprechxy) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%rechxy) + endif + if (Model%lkm > 0 .and. Model%iopt_lake==Model%iopt_lake_flake) then + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%T_snow) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%T_ice) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%h_ML) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%t_ML) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%t_mnw) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%h_talb) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%t_talb) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%t_bot1) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%t_bot2) + call GFS_Data_transfer(reading,ii1,jj1,isc,jsc,nt,sfc%var2,Sfcprop(nb)%c_t) + endif + if(.not.reading) then + do k = 1,Model%kice + do ix = 1, Atm_block%blksz(nb) + ice=Sfcprop(nb)%tiice(ix,k) + if(ice@ Copies from Sfc_io_data_type internal arrays to the model grid by calling transfer() with reading=.true. + subroutine Sfc_io_copy_to_grid(sfc, Model, Atm_block, Sfcprop, warm_start, override_frac_grid) + !--- interface variable definitions + implicit none + + class(Sfc_io_data_type) :: sfc + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + logical, intent(in) :: warm_start + logical, intent(out), optional :: override_frac_grid + + call sfc%transfer(.true.,Model, Atm_block, Sfcprop, warm_start, override_frac_grid) + + end subroutine Sfc_io_copy_to_grid + + !>@ Copies from the model grid to Sfc_io_data_type internal arrays by calling transfer() with reading=.false. + subroutine Sfc_io_copy_from_grid(sfc, Model, Atm_block, Sfcprop) + !--- interface variable definitions + implicit none + + class(Sfc_io_data_type) :: sfc + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + + call sfc%transfer(.false., Model, Atm_block, Sfcprop, warm_start=.false.) + + end subroutine Sfc_io_copy_from_grid + + !>@ Calculates values and applies safeguards after reading restart data. + subroutine Sfc_io_apply_safeguards(sfc, Model, Atm_block, Sfcprop) + !--- interface variable definitions + implicit none + + class(Sfc_io_data_type) :: sfc + type(GFS_sfcprop_type), intent(in) :: Sfcprop(:) + type(block_control_type), intent(in) :: Atm_block + type(GFS_control_type), intent(in) :: Model + + integer :: i, j, k, nb, ix, lsoil, num, nt + integer :: isc, iec, jsc, jec, npz, nx, ny + real(kind_phys) :: ice, tem, tem1 + + isc = Atm_block%isc + iec = Atm_block%iec + jsc = Atm_block%jsc + jec = Atm_block%jec + npz = Atm_block%npz + nx = (iec - isc + 1) + ny = (jec - jsc + 1) + + ! so far: At cold start everything is 9999.0, warm start snowxy has values + ! but the 3D of snow fields are not available because not allocated yet. + ! ix,nb loops may be consolidate with the Noah MP isnowxy init + ! restore traditional vars first,we need some of them to init snow fields + ! snow depth to actual snow layers; so we can allocate and register + ! note zsnsoxy is from -2:4 - isnowxy is from 0:-2, but we need + ! exact snow layers to pass 3D fields correctly, snow layers are + ! different fro grid to grid, we have to init point by point/grid. + ! It has to be done after the weasd is available + ! sfc%var2(1,1,32) is the first; we need this to allocate snow related fields + + i = Atm_block%index(1)%ii(1) - isc + 1 + j = Atm_block%index(1)%jj(1) - jsc + 1 + + if (sfc%var2(i,j,33) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing snodl') + !$omp parallel do default(shared) private(nb, ix, tem) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%landfrac(ix) > zero) then + tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) + Sfcprop(nb)%snodl(ix) = Sfcprop(nb)%snowd(ix) * tem + else + Sfcprop(nb)%snodl(ix) = zero + endif + enddo + enddo + endif + + if (sfc%var2(i,j,34) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing weasdl') + !$omp parallel do default(shared) private(nb, ix, tem) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%landfrac(ix) > zero) then + tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) + Sfcprop(nb)%weasdl(ix) = Sfcprop(nb)%weasd(ix) * tem + else + Sfcprop(nb)%weasdl(ix) = zero + endif + enddo + enddo + endif + + if (sfc%var2(i,j,36) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing tsfcl') + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + Sfcprop(nb)%tsfcl(ix) = Sfcprop(nb)%tsfco(ix) !--- compute tsfcl from existing variables + enddo + enddo + endif + + if (sfc%var2(i,j,37) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorlw') + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%landfrac(ix) < one .and. Sfcprop(nb)%fice(ix) < one) then + Sfcprop(nb)%zorlw(ix) = min(Sfcprop(nb)%zorl(ix), 0.317) + endif + enddo + enddo + endif + + if (sfc%var2(i,j,38) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorll') + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + Sfcprop(nb)%zorll(ix) = Sfcprop(nb)%zorl(ix) !--- compute zorll from existing variables + enddo + enddo + endif + + if (sfc%var2(i,j,39) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorli') + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix)) > zero) then + Sfcprop(nb)%zorli(ix) = one + endif + enddo + enddo + endif + + if (sfc%var2(i,j,45) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing emis_ice') + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + Sfcprop(nb)%emis_ice(ix) = 0.96 + enddo + enddo + endif + + if (sfc%var2(i,j,46) < -9990.0_kind_phys .and. Model%lsm /= Model%lsm_ruc) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing sncovr_ice') + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + ! Sfcprop(nb)%sncovr_ice(ix) = Sfcprop(nb)%sncovr(ix) + Sfcprop(nb)%sncovr_ice(ix) = zero + enddo + enddo + endif + + if (sfc%var2(i,j,47) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing snodi') + !$omp parallel do default(shared) private(nb, ix, tem) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%fice(ix) > zero) then + tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) + Sfcprop(nb)%snodi(ix) = min(Sfcprop(nb)%snowd(ix) * tem, 3.0) + else + Sfcprop(nb)%snodi(ix) = zero + endif + enddo + enddo + endif + + if (sfc%var2(i,j,48) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing weasdi') + !$omp parallel do default(shared) private(nb, ix, tem) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%fice(ix) > zero) then + tem = one / (Sfcprop(nb)%fice(ix)*(one-Sfcprop(nb)%landfrac(ix))+Sfcprop(nb)%landfrac(ix)) + Sfcprop(nb)%weasdi(ix) = Sfcprop(nb)%weasd(ix)*tem + else + Sfcprop(nb)%weasdi(ix) = zero + endif + enddo + enddo + endif + + if (Model%use_cice_alb) then + if (sfc%var2(i,j,49) < -9990.0_kind_phys) then + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%oceanfrac(ix) > zero .and. & + Sfcprop(nb)%fice(ix) >= Model%min_seaice) then + Sfcprop(nb)%albdirvis_ice(ix) = 0.6_kind_phys + Sfcprop(nb)%albdifvis_ice(ix) = 0.6_kind_phys + Sfcprop(nb)%albdirnir_ice(ix) = 0.6_kind_phys + Sfcprop(nb)%albdifnir_ice(ix) = 0.6_kind_phys + endif + enddo + enddo + endif + + endif + + ! Fill in composite tsfc for coldstart runs - must happen after tsfcl is computed + compute_tsfc_for_colstart: if (sfc%var2(i,j,35) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing composite tsfc') + if(Model%frac_grid) then ! 3-way composite + !$omp parallel do default(shared) private(nb, ix, tem, tem1) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + Sfcprop(nb)%tsfco(ix) = max(con_tice, Sfcprop(nb)%tsfco(ix)) ! this may break restart reproducibility + tem1 = one - Sfcprop(nb)%landfrac(ix) + tem = tem1 * Sfcprop(nb)%fice(ix) ! tem = ice fraction wrt whole cell + Sfcprop(nb)%tsfc(ix) = Sfcprop(nb)%tsfcl(ix) * Sfcprop(nb)%landfrac(ix) & + + Sfcprop(nb)%tisfc(ix) * tem & + + Sfcprop(nb)%tsfco(ix) * (tem1-tem) + enddo + enddo + else + !$omp parallel do default(shared) private(nb, ix, tem) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + if (Sfcprop(nb)%slmsk(ix) == 1) then + Sfcprop(nb)%tsfc(ix) = Sfcprop(nb)%tsfcl(ix) + else + tem = one - Sfcprop(nb)%fice(ix) + Sfcprop(nb)%tsfc(ix) = Sfcprop(nb)%tisfc(ix) * Sfcprop(nb)%fice(ix) & + + Sfcprop(nb)%tsfco(ix) * tem + endif + enddo + enddo + endif + endif compute_tsfc_for_colstart + + if (sfc%var2(i,j,sfc%nvar2m) < -9990.0_kind_phys) then + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing zorlwav') + !$omp parallel do default(shared) private(nb, ix) + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + Sfcprop(nb)%zorlwav(ix) = Sfcprop(nb)%zorl(ix) !--- compute zorlwav from existing variables + enddo + enddo + endif + + if (nint(sfc%var3ice(1,1,1)) == -9999) then !--- initialize internal ice temp from layer 1 and 2 soil temp + if (Model%me == Model%master ) call mpp_error(NOTE, 'gfs_driver::surface_props_input - computing tiice') + do nb = 1, Atm_block%nblks + do ix = 1, Atm_block%blksz(nb) + Sfcprop(nb)%tiice(ix,1) = max(timin, min(con_tice, Sfcprop(nb)%stc(ix,1))) + Sfcprop(nb)%tiice(ix,2) = max(timin, min(con_tice, Sfcprop(nb)%stc(ix,2))) + enddo + enddo + endif + + end subroutine Sfc_io_apply_safeguards + + !>@ destructor for Sfc_io_data_type + subroutine Sfc_io_final(sfc) + implicit none + type(Sfc_io_data_type) :: sfc + + sfc%nvar2m=0 + sfc%nvar2o=0 + sfc%nvar2l=0 + sfc%nvar3=0 + sfc%nvar2r=0 + sfc%nvar2mp=0 + sfc%nvar3mp=0 + sfc%nvar2m=0 + sfc%nvar_before_lake=0 + sfc%is_lsoil=.false. + + ! This #define reduces code length by a lot +#define IF_ASSOC_DEALLOC_NULL(var) \ + if(associated(sfc%var)) then ; \ + deallocate(sfc%var) ; \ + nullify(sfc%var) ; \ + endif + + IF_ASSOC_DEALLOC_NULL(var2) + IF_ASSOC_DEALLOC_NULL(var3ice) + IF_ASSOC_DEALLOC_NULL(var3) + IF_ASSOC_DEALLOC_NULL(var3sn) + IF_ASSOC_DEALLOC_NULL(var3eq) + IF_ASSOC_DEALLOC_NULL(var3zn) + IF_ASSOC_DEALLOC_NULL(name2) + IF_ASSOC_DEALLOC_NULL(name3) + +#undef IF_ASSOC_DEALLOC_NULL + + end subroutine Sfc_io_final + + !>@ Creates ESMF bundles for 2D fields, for writing surface restart files using the write component (quilt) + subroutine Sfc_io_bundle_2d_fields(sfc, bundle, grid, Model, outputfile) + use esmf + use GFS_typedefs, only: GFS_control_type + implicit none + class(Sfc_io_data_type) :: sfc + type(ESMF_FieldBundle),intent(inout) :: bundle + type(ESMF_Grid),intent(inout) :: grid + type(GFS_control_type), intent(in) :: Model + character(*), intent(in) :: outputfile + + real(kind_phys),dimension(:,:),pointer :: temp_r2d + integer :: num + + if (.not. associated(sfc%var2)) then + write(0,*)'ERROR sfc%var2, NOT associated' + return + endif + if (.not. associated(sfc%name2)) then + write(0,*)'ERROR sfc%name2 NOT associated' + return + endif + + do num = 1,sfc%nvar2m + temp_r2d => sfc%var2(:,:,num) + call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc%name2(num)), outputfile, grid, bundle) + enddo + + if (Model%nstf_name(1) > 0) then + do num = sfc%nvar2m+1,sfc%nvar2m+sfc%nvar2o + temp_r2d => sfc%var2(:,:,num) + call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc%name2(num)), outputfile, grid, bundle) + enddo + endif + + if (Model%lsm == Model%lsm_ruc) then ! sfc%nvar2mp =0 + do num = sfc%nvar2m+sfc%nvar2o+1, sfc%nvar2m+sfc%nvar2o+sfc%nvar2r + temp_r2d => sfc%var2(:,:,num) + call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc%name2(num)), outputfile, grid, bundle) + enddo + else if (Model%lsm == Model%lsm_noahmp) then ! sfc%nvar2r =0 + do num = sfc%nvar2m+sfc%nvar2o+1,sfc%nvar2m+sfc%nvar2o+sfc%nvar2mp + temp_r2d => sfc%var2(:,:,num) + call create_2d_field_and_add_to_bundle(temp_r2d, trim(sfc%name2(num)), outputfile, grid, bundle) + enddo + endif + end subroutine Sfc_io_bundle_2d_fields + + !>@ Creates ESMF bundles for 3D fields, for writing surface restart files using the write component (quilt) + subroutine Sfc_io_bundle_3d_fields(sfc, bundle, grid, Model, outputfile) + use esmf + use GFS_typedefs, only: GFS_control_type + implicit none + class(Sfc_io_data_type) :: sfc + type(ESMF_FieldBundle),intent(inout) :: bundle + type(ESMF_Grid),intent(inout) :: grid + type(GFS_control_type), intent(in) :: Model + character(*), intent(in) :: outputfile + + real(kind_phys),dimension(:,:,:),pointer :: temp_r3d + integer :: num, i + real(kind_phys), dimension(:), allocatable :: zaxis_1, zaxis_2, zaxis_3, zaxis_4 + + allocate(zaxis_1(Model%kice)) + zaxis_1 = (/ (i, i=1,Model%kice) /) + + temp_r3d => sfc%var3ice(:,:,:) + call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc%name3(0)), "zaxis_1", zaxis_1, trim(outputfile), grid, bundle) + + if(Model%lsm == Model%lsm_ruc) then + do num = 1,sfc%nvar3 + temp_r3d => sfc%var3(:,:,:,num) + call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc%name3(num)), "zaxis_1", zaxis_1, trim(outputfile), grid, bundle) + enddo + else + allocate(zaxis_2(Model%lsoil)) + zaxis_2 = (/ (i, i=1,Model%lsoil) /) + do num = 1,sfc%nvar3 + temp_r3d => sfc%var3(:,:,:,num) + call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc%name3(num)), "zaxis_2", zaxis_2, trim(outputfile), grid, bundle) + enddo + deallocate(zaxis_2) + endif + + if (Model%lsm == Model%lsm_noahmp) then + allocate(zaxis_3(3)) + zaxis_3 = (/ (i, i=1,3) /) + + do num = sfc%nvar3+1,sfc%nvar3+3 + temp_r3d => sfc%var3sn(:,:,:,num) + call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc%name3(num)), "zaxis_3", zaxis_3, trim(outputfile), grid, bundle) + enddo + + allocate(zaxis_2(Model%lsoil)) + zaxis_2 = (/ (i, i=1,Model%lsoil) /) + + temp_r3d => sfc%var3eq(:,:,:,7) + call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc%name3(7)), "zaxis_2", zaxis_2, trim(outputfile), grid, bundle) + + allocate(zaxis_4(7)) + zaxis_4 = (/ (i, i=1,7) /) + + temp_r3d => sfc%var3zn(:,:,:,8) + call create_3d_field_and_add_to_bundle(temp_r3d, trim(sfc%name3(8)), "zaxis_4", zaxis_4, trim(outputfile), grid, bundle) + endif ! lsm = lsm_noahmp + + if(allocated(zaxis_1)) deallocate(zaxis_1) + if(allocated(zaxis_2)) deallocate(zaxis_2) + if(allocated(zaxis_3)) deallocate(zaxis_3) + if(allocated(zaxis_4)) deallocate(zaxis_4) + + end subroutine Sfc_io_bundle_3d_fields +end module fv3atm_sfc_io +!> @} diff --git a/io/module_wrt_grid_comp.F90 b/io/module_wrt_grid_comp.F90 index 94e568073..3cd17002f 100644 --- a/io/module_wrt_grid_comp.F90 +++ b/io/module_wrt_grid_comp.F90 @@ -2024,7 +2024,7 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc) if (mype == lead_write_task) then !** write out inline post log file open(newunit=nolog,file='log.atm.inlinepost.f'//trim(cfhour),form='FORMATTED') - write(nolog,"(' completed fv3gfs fhour=',f10.3,2x,6(i4,2x))") nfhour, idate(1:6) + write(nolog,"(' completed fv3atm fhour=',f10.3,2x,6(i4,2x))") nfhour, idate(1:6) close(nolog) endif if (lprnt) then @@ -2327,7 +2327,7 @@ subroutine wrt_run(wrt_comp, imp_state_write, exp_state_write,clock,rc) if (out_phase == 1 .and. mype == lead_write_task) then !** write out log file open(newunit=nolog,file='log.atm.f'//trim(cfhour),form='FORMATTED') - write(nolog,"(' completed fv3gfs fhour=',f10.3,2x,6(i4,2x))") nfhour, idate(1:6) + write(nolog,"(' completed fv3atm fhour=',f10.3,2x,6(i4,2x))") nfhour, idate(1:6) close(nolog) endif enddo two_phase_loop diff --git a/module_fcst_grid_comp.F90 b/module_fcst_grid_comp.F90 index 3897ff43c..6557f76f8 100644 --- a/module_fcst_grid_comp.F90 +++ b/module_fcst_grid_comp.F90 @@ -55,8 +55,8 @@ module module_fcst_grid_comp use data_override_mod, only: data_override_init use fv_nggps_diags_mod, only: fv_dyn_bundle_setup - use fv3gfs_io_mod, only: fv_phys_bundle_setup - use fv3gfs_restart_io_mod, only: fv_phy_restart_bundle_setup, fv_sfc_restart_bundle_setup + use fv3atm_history_io_mod, only: fv_phys_bundle_setup + use fv3atm_restart_io_mod, only: fv_phy_restart_bundle_setup, fv_sfc_restart_bundle_setup use fv_ufs_restart_io_mod, only: fv_core_restart_bundle_setup, & fv_srf_wnd_restart_bundle_setup, & fv_tracer_restart_bundle_setup diff --git a/moving_nest/fv_moving_nest_physics.F90 b/moving_nest/fv_moving_nest_physics.F90 index 2dc6bce5b..1219617a6 100644 --- a/moving_nest/fv_moving_nest_physics.F90 +++ b/moving_nest/fv_moving_nest_physics.F90 @@ -177,7 +177,7 @@ subroutine mn_phys_reset_sfc_props(Atm, n, mn_static, Atm_block, IPD_data, ioffs IPD_data(nb)%Sfcprop%tg3(ix) = mn_static%deep_soil_temp_grid(i_idx, j_idx) - ! Follow logic from FV3/io/FV3GFS_io.F90 line 1187 + ! Follow logic from FV3/io/fv3atm_sfc_io.F90 ! TODO this will need to be more complicated if we support frac_grid !if (nint(mn_static%soil_type_grid(i_idx, j_idx)) == 14 .or. int(mn_static%soil_type_grid(i_idx, j_idx)+0.5) <= 0) then !if (nint(mn_static%soil_type_grid(i_idx, j_idx)) == 14 .or.