From bed84164ffb6e388190234c5daaa9ee6dd81c1c9 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 13 Dec 2024 15:21:18 -0700 Subject: [PATCH 01/12] remove lcp_moist and line-by-line merge of subroutine vertical_remap --- src/dynamics/se/dp_coupling.F90 | 4 +- src/dynamics/se/dycore/dimensions_mod.F90 | 7 -- src/dynamics/se/dycore/prim_advance_mod.F90 | 28 ++--- src/dynamics/se/dycore/prim_advection_mod.F90 | 106 ++++++++---------- src/dynamics/se/dyn_comp.F90 | 6 - .../se/namelist_definition_se_dycore.xml | 16 --- 6 files changed, 58 insertions(+), 109 deletions(-) diff --git a/src/dynamics/se/dp_coupling.F90 b/src/dynamics/se/dp_coupling.F90 index 8b56e9d9..e7271841 100644 --- a/src/dynamics/se/dp_coupling.F90 +++ b/src/dynamics/se/dp_coupling.F90 @@ -838,7 +838,7 @@ subroutine thermodynamic_consistency(phys_state, const_data_ptr, phys_tend, ncol real(kind_phys) :: inv_cp(ncols,pver) !---------------------------------------------------------------------------- - if (lcp_moist.and.phys_dyn_cp==1) then +!xxx if (lcp_moist.and.phys_dyn_cp==1) then lcp_moist removed ! ! scale temperature tendency so that thermal energy increment from physics ! matches SE (not taking into account dme adjust) @@ -849,7 +849,7 @@ subroutine thermodynamic_consistency(phys_state, const_data_ptr, phys_tend, ncol call get_cp(const_data_ptr(1:ncols,1:pver,1:num_advected),.true.,inv_cp) phys_tend%dTdt_total(1:ncols,1:pver) = phys_tend%dTdt_total(1:ncols,1:pver)*cpair*inv_cp - end if +!xxx end if end subroutine thermodynamic_consistency !========================================================================================= diff --git a/src/dynamics/se/dycore/dimensions_mod.F90 b/src/dynamics/se/dycore/dimensions_mod.F90 index 14856a4b..0fe69bc3 100644 --- a/src/dynamics/se/dycore/dimensions_mod.F90 +++ b/src/dynamics/se/dycore/dimensions_mod.F90 @@ -19,13 +19,6 @@ module dimensions_mod ! character(len=16), allocatable, public :: cnst_name_gll(:) ! constituent names for SE tracers character(len=128), allocatable, public :: cnst_longname_gll(:) ! long name of SE tracers - ! - !moist cp in energy conversion term - ! - ! .false.: force dycore to use cpd (cp dry) instead of moist cp - ! .true. : use moist cp in dycore - ! - logical , public :: lcp_moist = .true. integer, parameter, public :: np = NP integer, parameter, public :: nc = 3 !cslam resolution diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index 1341b9f4..5c64d91c 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -68,7 +68,6 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net use hybvcoord_mod, only: hvcoord_t use hybrid_mod, only: hybrid_t use time_mod, only: TimeLevel_t, timelevel_qdp, tevolve - use dimensions_mod, only: lcp_moist use fvm_control_volume_mod, only: fvm_struct use control_mod, only: raytau0 @@ -146,16 +145,10 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net ! ! compute Cp and kappa=Rdry/cpdry here and not in RK-stages since Q stays constant => Cp and kappa also stays constant ! - if (lcp_moist) then - do ie=nets,nete - call get_cp(qwater(:,:,:,:,ie), & - .true.,inv_cp_full(:,:,:,ie),active_species_idx_dycore=qidx) - end do - else - do ie=nets,nete - inv_cp_full(:,:,:,ie) = 1.0_r8/cpair - end do - end if + do ie=nets,nete + call get_cp(qwater(:,:,:,:,ie), & + .true.,inv_cp_full(:,:,:,ie),active_species_idx_dycore=qidx) + end do do ie=nets,nete call get_kappa_dry(qwater(:,:,:,:,ie),qidx,kappa(:,:,:,ie)) end do @@ -1587,7 +1580,7 @@ subroutine distribute_flux_at_corners(cflux, corners, getmapP) cflux(2,2,2) = (corners(np ,np+1) - corners(np,np )) endif end subroutine distribute_flux_at_corners - +!xxx tot_energy_dyn not merged in yet subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suffix) use dynconst, only: gravit, cpair, rearth, omega use dyn_thermo, only: get_dp, get_cp @@ -1601,7 +1594,7 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf !SE dycore: use element_mod, only: element_t - use dimensions_mod, only: npsq,nlev,np,lcp_moist,nc,ntrac,qsize + use dimensions_mod, only: npsq,nlev,np,nc,ntrac,qsize use fvm_control_volume_mod, only: fvm_struct use dimensions_mod, only: cnst_name_gll !------------------------------Arguments-------------------------------- @@ -1683,14 +1676,7 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf ! kinetic energy ! ke_tmp = 0.5_r8*(elem(ie)%state%v(i,j,1,k,tl)**2+ elem(ie)%state%v(i,j,2,k,tl)**2)*pdel(i,j,k)/gravit - if (lcp_moist) then - se_tmp = cp(i,j,k)*elem(ie)%state%T(i,j,k,tl)*pdel(i,j,k)/gravit - else - ! - ! using CAM physics definition of internal energy - ! - se_tmp = cpair*elem(ie)%state%T(i,j,k,tl)*pdel(i,j,k)/gravit - end if + se_tmp = cp(i,j,k)*elem(ie)%state%T(i,j,k,tl)*pdel(i,j,k)/gravit se (i+(j-1)*np) = se (i+(j-1)*np) + se_tmp ke (i+(j-1)*np) = ke (i+(j-1)*np) + ke_tmp end do diff --git a/src/dynamics/se/dycore/prim_advection_mod.F90 b/src/dynamics/se/dycore/prim_advection_mod.F90 index f1ea126e..674593a5 100644 --- a/src/dynamics/se/dycore/prim_advection_mod.F90 +++ b/src/dynamics/se/dycore/prim_advection_mod.F90 @@ -948,22 +948,22 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) ! ! map tracers ! map velocity components - ! map temperature (either by mapping thermal energy or virtual temperature over log(p) + ! map temperature (either by mapping enthalpy or virtual temperature + ! over log(p) ! (controlled by vert_remap_uvTq_alg > -20 or <= -20) ! - use hybvcoord_mod , only: hvcoord_t - use vertremap_mod , only: remap1 - use hybrid_mod , only: hybrid_t, config_thread_region,get_loop_ranges, PrintHybrid + use hybvcoord_mod, only: hvcoord_t + use vertremap_mod, only: remap1 + use hybrid_mod, only: hybrid_t, config_thread_region,get_loop_ranges, PrintHybrid use fvm_control_volume_mod, only: fvm_struct - use dimensions_mod , only: ntrac - use dimensions_mod , only: lcp_moist, kord_tr,kord_tr_cslam - use cam_logfile , only: iulog - use dynconst , only: pi - use dyn_thermo , only: get_enthalpy, get_dp, get_virtual_temp - use cam_thermo , only: MASS_MIXING_RATIO - use air_composition , only: thermodynamic_active_species_idx_dycore - use thread_mod , only: omp_set_nested - use control_mod , only: vert_remap_uvTq_alg + use dimensions_mod, only: ntrac + use dimensions_mod, only: kord_tr,kord_tr_cslam + use cam_logfile, only: iulog + use dynconst, only: pi + use air_composition, only: thermodynamic_active_species_idx_dycore + use cam_thermo, only: get_enthalpy, get_virtual_temp, get_dp, MASS_MIXING_RATIO + use thread_mod, only: omp_set_nested + use control_mod, only: vert_remap_uvTq_alg type (hybrid_t), intent(in) :: hybrid ! distributed parallel structure (shared) type(fvm_struct), intent(inout) :: fvm(:) @@ -974,7 +974,7 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) type (hvcoord_t) :: hvcoord integer :: ie,i,j,k,np1,nets,nete,np1_qdp,q, m_cnst real (kind=r8), dimension(np,np,nlev) :: dp_moist,dp_star_moist, dp_dry,dp_star_dry - real (kind=r8), dimension(np,np,nlev) :: internal_energy_star + real (kind=r8), dimension(np,np,nlev) :: enthalpy_star real (kind=r8), dimension(np,np,nlev,2):: ttmp real(r8), parameter :: rad2deg = 180.0_r8/pi integer :: region_num_threads,qbeg,qend,kord_uvT(1) @@ -989,23 +989,20 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) ! prepare for mapping of temperature ! if (vert_remap_uvTq_alg>-20) then - if (lcp_moist) then - ! - ! compute internal energy on Lagrangian levels - ! (do it here since qdp is overwritten by remap1) - ! - call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & - elem(ie)%state%t(:,:,:,np1),elem(ie)%state%dp3d(:,:,:,np1),internal_energy_star, & - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - end if + ! + ! compute enthalpy on Lagrangian levels + ! (do it here since qdp is overwritten by remap1) + ! + call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & + elem(ie)%state%t(:,:,:,np1), elem(ie)%state%dp3d(:,:,:,np1), enthalpy_star, & + active_species_idx_dycore=thermodynamic_active_species_idx_dycore) else ! ! map Tv over log(p) following FV and FV3 ! - call get_virtual_temp(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & - internal_energy_star,dp_dry=elem(ie)%state%dp3d(:,:,:,np1), & - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - internal_energy_star = internal_energy_star*elem(ie)%state%t(:,:,:,np1) + call get_virtual_temp(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), enthalpy_star, & + dp_dry=elem(ie)%state%dp3d(:,:,:,np1), active_species_idx_dycore=thermodynamic_active_species_idx_dycore) + enthalpy_star = enthalpy_star*elem(ie)%state%t(:,:,:,np1) end if ! ! update final psdry @@ -1013,17 +1010,18 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) elem(ie)%state%psdry(:,:) = ptop + & sum(elem(ie)%state%dp3d(:,:,:,np1),3) ! - ! compute dry vertical coordinate (Lagrangian and reference levels) + ! compute dry vertical coordinate (Lagrangian and reference + ! levels) ! do k=1,nlev dp_star_dry(:,:,k) = elem(ie)%state%dp3d(:,:,k,np1) - dp_dry(:,:,k) = ( hvcoord%hyai(k+1) - hvcoord%hyai(k) )*hvcoord%ps0 + & - ( hvcoord%hybi(k+1) - hvcoord%hybi(k) )*elem(ie)%state%psdry(:,:) + dp_dry(:,:,k) = ( hvcoord%hyai(k+1) - hvcoord%hyai(k))*hvcoord%ps0 + & + ( hvcoord%hybi(k+1) - hvcoord%hybi(k))*elem(ie)%state%psdry(:,:) elem(ie)%state%dp3d(:,:,k,np1) = dp_dry(:,:,k) enddo ! call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,np1_qdp),MASS_MIXING_RATIO,& - thermodynamic_active_species_idx_dycore,dp_star_dry,dp_star_moist(:,:,:)) + thermodynamic_active_species_idx_dycore, dp_star_dry,dp_star_moist(:,:,:)) ! ! Check if Lagrangian leves have crossed ! @@ -1037,7 +1035,7 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) elem(ie)%spherep(i,j)%lon*rad2deg,elem(ie)%spherep(i,j)%lat*rad2deg write(iulog,*) " " do k=1,nlev - write(iulog,'(A21,I5,A1,f12.8,3f8.2)') "k,dp_star_moist,u,v,T: ",k," ",dp_star_moist(i,j,k)/100.0_r8,& + write(iulog,'(A21,I5,A1,f16.12,3f10.2)')"k,dp_star_moist,u,v,T: ",k," ",dp_star_moist(i,j,k)/100.0_r8,& elem(ie)%state%v(i,j,1,k,np1),elem(ie)%state%v(i,j,2,k,np1),elem(ie)%state%T(i,j,k,np1) end do end if @@ -1051,42 +1049,35 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) ! compute moist reference pressure level thickness ! call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,np1_qdp),MASS_MIXING_RATIO,& - thermodynamic_active_species_idx_dycore,dp_dry,dp_moist(:,:,:)) + thermodynamic_active_species_idx_dycore, dp_dry,dp_moist(:,:,:)) ! ! Remapping of temperature ! if (vert_remap_uvTq_alg>-20) then ! - ! remap internal energy and back out temperature + ! remap enthalpy energy and back out temperature ! - if (lcp_moist) then - call remap1(internal_energy_star,np,1,1,1,dp_star_dry,dp_dry,ptop,1,.true.,kord_uvT) - ! - ! compute sum c^(l)_p*m^(l)*dp on arrival (Eulerian) grid - ! - ttmp(:,:,:,1) = 1.0_r8 - call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & - ttmp(:,:,:,1),dp_dry,ttmp(:,:,:,2), & - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - elem(ie)%state%t(:,:,:,np1)=internal_energy_star/ttmp(:,:,:,2) - else - internal_energy_star(:,:,:)=elem(ie)%state%t(:,:,:,np1)*dp_star_moist - call remap1(internal_energy_star,np,1,1,1,dp_star_moist,dp_moist,ptop,1,.true.,kord_uvT) - elem(ie)%state%t(:,:,:,np1)=internal_energy_star/dp_moist - end if + call remap1(enthalpy_star,np,1,1,1,dp_star_dry,dp_dry,ptop,1,.true.,kord_uvT) + ! + ! compute sum c^(l)_p*m^(l)*dp on arrival (Eulerian) grid + ! + ttmp(:,:,:,1) = 1.0_r8 + call get_enthalpy(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & + ttmp(:,:,:,1), dp_dry,ttmp(:,:,:,2), & + active_species_idx_dycore=thermodynamic_active_species_idx_dycore) + elem(ie)%state%t(:,:,:,np1)=enthalpy_star/ttmp(:,:,:,2) else ! ! map Tv over log(p); following FV and FV3 ! - call remap1(internal_energy_star,np,1,1,1,dp_star_moist,dp_moist,ptop,1,.false.,kord_uvT) - call get_virtual_temp(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), & - ttmp(:,:,:,1),dp_dry=dp_dry, & - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) + call remap1(enthalpy_star,np,1,1,1,dp_star_moist,dp_moist,ptop,1,.false.,kord_uvT) + call get_virtual_temp(elem(ie)%state%qdp(:,:,:,1:qsize,np1_qdp), ttmp(:,:,:,1), & + dp_dry=dp_dry,active_species_idx_dycore=thermodynamic_active_species_idx_dycore) ! ! convert new Tv to T ! - elem(ie)%state%t(:,:,:,np1)=internal_energy_star/ttmp(:,:,:,1) + elem(ie)%state%t(:,:,:,np1)=enthalpy_star/ttmp(:,:,:,1) end if ! ! remap velocity components @@ -1112,14 +1103,15 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) end do end do end do - if(ntrac>tracer_num_threads) then + if(ntrac>tracer_num_threads) then call omp_set_nested(.true.) - !$OMP PARALLEL NUM_THREADS(tracer_num_threads), DEFAULT(SHARED), PRIVATE(hybridnew2,qbeg,qend) + !$OMP PARALLEL NUM_THREADS(tracer_num_threads), + !DEFAULT(SHARED), PRIVATE(hybridnew2,qbeg,qend) hybridnew2 = config_thread_region(hybrid,'ctracer') call get_loop_ranges(hybridnew2, qbeg=qbeg, qend=qend) call remap1(fvm(ie)%c(1:nc,1:nc,:,1:ntrac),nc,qbeg,qend,ntrac,dpc_star, & fvm(ie)%dp_fvm(1:nc,1:nc,:),ptop,0,.false.,kord_tr_cslam) - !$OMP END PARALLEL + !$OMP END PARALLEL call omp_set_nested(.false.) else call remap1(fvm(ie)%c(1:nc,1:nc,:,1:ntrac),nc,1,ntrac,ntrac,dpc_star, & diff --git a/src/dynamics/se/dyn_comp.F90 b/src/dynamics/se/dyn_comp.F90 index ab52d91c..ddb73707 100644 --- a/src/dynamics/se/dyn_comp.F90 +++ b/src/dynamics/se/dyn_comp.F90 @@ -116,7 +116,6 @@ subroutine dyn_readnl(NLFileName) use control_mod, only: max_hypervis_courant, statediag_numtrac,refined_mesh use control_mod, only: raytau0, raykrange, rayk0, molecular_diff use dimensions_mod, only: ne, npart - use dimensions_mod, only: lcp_moist use dimensions_mod, only: hypervis_dynamic_ref_state,large_Courant_incr use dimensions_mod, only: fvm_supercycling, fvm_supercycling_jet use dimensions_mod, only: kmin_jet, kmax_jet @@ -164,7 +163,6 @@ subroutine dyn_readnl(NLFileName) integer :: se_vert_num_threads integer :: se_tracer_num_threads logical :: se_hypervis_dynamic_ref_state - logical :: se_lcp_moist logical :: se_write_restart_unstruct logical :: se_large_Courant_incr integer :: se_fvm_supercycling @@ -212,7 +210,6 @@ subroutine dyn_readnl(NLFileName) se_vert_num_threads, & se_tracer_num_threads, & se_hypervis_dynamic_ref_state,& - se_lcp_moist, & se_write_restart_unstruct, & se_large_Courant_incr, & se_fvm_supercycling, & @@ -285,7 +282,6 @@ subroutine dyn_readnl(NLFileName) call MPI_bcast(se_vert_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) call MPI_bcast(se_tracer_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) call MPI_bcast(se_hypervis_dynamic_ref_state, 1, mpi_logical, masterprocid, mpicom, ierr) - call MPI_bcast(se_lcp_moist, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_write_restart_unstruct, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_large_Courant_incr, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_fvm_supercycling, 1, mpi_integer, masterprocid, mpicom, ierr) @@ -361,7 +357,6 @@ subroutine dyn_readnl(NLFileName) vert_remap_tracer_alg = set_vert_remap(se_vert_remap_T, se_vert_remap_tracer_alg) fv_nphys = se_fv_nphys hypervis_dynamic_ref_state = se_hypervis_dynamic_ref_state - lcp_moist = se_lcp_moist large_Courant_incr = se_large_Courant_incr fvm_supercycling = se_fvm_supercycling fvm_supercycling_jet = se_fvm_supercycling_jet @@ -451,7 +446,6 @@ subroutine dyn_readnl(NLFileName) write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_uvTq_alg = ',trim(se_vert_remap_uvTq_alg) write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_tracer_alg = ',trim(se_vert_remap_tracer_alg) write(iulog, '(a,l4)') 'dyn_readnl: se_hypervis_dynamic_ref_state = ',hypervis_dynamic_ref_state - write(iulog, '(a,l4)') 'dyn_readnl: lcp_moist = ',lcp_moist write(iulog, '(a,i0)') 'dyn_readnl: se_fvm_supercycling = ',fvm_supercycling write(iulog, '(a,i0)') 'dyn_readnl: se_fvm_supercycling_jet = ',fvm_supercycling_jet write(iulog, '(a,i0)') 'dyn_readnl: se_kmin_jet = ',kmin_jet diff --git a/src/dynamics/se/namelist_definition_se_dycore.xml b/src/dynamics/se/namelist_definition_se_dycore.xml index 12f674aa..6c2ad249 100644 --- a/src/dynamics/se/namelist_definition_se_dycore.xml +++ b/src/dynamics/se/namelist_definition_se_dycore.xml @@ -343,22 +343,6 @@ .false. - - logical - se - dyn_se_nl - - If TRUE the continous equations the dynamical core is based on will conserve a - comprehensive moist total energy - If FALSE the continous equations the dynamical core is based on will conserve - a total energy based on cp for dry air and no condensates (same total energy as - CAM physics uses). - For more details see Lauritzen et al., (2018;DOI:10.1029/2017MS001257) - - - .true. - - logical se From 5442b6bdbd8145673f660cae7e4e438c9e7bbe8f Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 13 Dec 2024 15:26:52 -0700 Subject: [PATCH 02/12] forgot to remove lcp_moist from dp_coupling --- src/dynamics/se/dp_coupling.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dynamics/se/dp_coupling.F90 b/src/dynamics/se/dp_coupling.F90 index e7271841..446a3cef 100644 --- a/src/dynamics/se/dp_coupling.F90 +++ b/src/dynamics/se/dp_coupling.F90 @@ -827,7 +827,6 @@ subroutine thermodynamic_consistency(phys_state, const_data_ptr, phys_tend, ncol use air_composition, only: get_cp ! SE dycore: - use dimensions_mod, only: lcp_moist use control_mod, only: phys_dyn_cp type(physics_state), intent(in) :: phys_state From d4ae7022bdf597ed71968c0f14f036348f98095e Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 13 Dec 2024 16:22:47 -0700 Subject: [PATCH 03/12] remove phys_dyn_cp, Rayleigh friction (incl. namelist), vertical diffusion, add se_molecular_diff namelist --- src/dynamics/se/dp_coupling.F90 | 3 - src/dynamics/se/dycore/control_mod.F90 | 32 ++-- src/dynamics/se/dycore/prim_advance_mod.F90 | 151 ++---------------- src/dynamics/se/dyn_comp.F90 | 49 +----- .../se/namelist_definition_se_dycore.xml | 70 +------- 5 files changed, 34 insertions(+), 271 deletions(-) diff --git a/src/dynamics/se/dp_coupling.F90 b/src/dynamics/se/dp_coupling.F90 index 446a3cef..2f819682 100644 --- a/src/dynamics/se/dp_coupling.F90 +++ b/src/dynamics/se/dp_coupling.F90 @@ -826,9 +826,6 @@ subroutine thermodynamic_consistency(phys_state, const_data_ptr, phys_tend, ncol use physconst, only: cpair use air_composition, only: get_cp - ! SE dycore: - use control_mod, only: phys_dyn_cp - type(physics_state), intent(in) :: phys_state real(kind_phys), pointer :: const_data_ptr(:,:,:) type(physics_tend ), intent(inout) :: phys_tend diff --git a/src/dynamics/se/dycore/control_mod.F90 b/src/dynamics/se/dycore/control_mod.F90 index fb7046d9..4de87e33 100644 --- a/src/dynamics/se/dycore/control_mod.F90 +++ b/src/dynamics/se/dycore/control_mod.F90 @@ -16,6 +16,7 @@ module control_mod integer, public :: rk_stage_user = 0 ! number of RK stages to use integer, public :: ftype = 2 ! Forcing Type integer, public :: ftype_conserve = 1 !conserve momentum (dp*u) + integer, public :: dribble_in_rsplit_loop = 0 integer, public :: statediag_numtrac = 3 integer, public :: qsplit = 1 ! ratio of dynamics tsteps to tracer tsteps @@ -23,9 +24,6 @@ module control_mod ! every rsplit tracer timesteps logical, public :: variable_nsplit=.false. - integer, public :: phys_dyn_cp = 0 !=0; no thermal energy scaling of T increment - !=1; scale increment for cp consistency between dynamics and physics - logical, public :: refined_mesh integer, public :: vert_remap_q_alg = 10 @@ -63,10 +61,25 @@ module control_mod ! (only used for variable viscosity, recommend 1.9 in namelist) real (kind=r8), public :: nu = 7.0D5 ! viscosity (momentum equ) real (kind=r8), public :: nu_div = -1 ! viscsoity (momentum equ, div component) - real (kind=r8), public :: nu_s = -1 ! default = nu T equ. viscosity + real (kind=r8), public :: nu_s = -1 ! default = nu T equ. viscosity xxx rename nu_t real (kind=r8), public :: nu_q = -1 ! default = nu tracer viscosity real (kind=r8), public :: nu_p = 0.0D5 ! default = 0 ps equ. viscosity real (kind=r8), public :: nu_top = 0.0D5 ! top-of-the-model viscosity + + ! + ! Del4 sponge layer diffusion + ! + ! Divergence damping hyperviscosity coefficient nu_div [m^4/s] for u,v is increased to + ! nu_div*sponge_del4_nu_div_fac following a hyperbolic tangent function + ! centered around pressure at vertical index sponge_del4_lev + ! + ! Similar for sponge_del4_nu_fac + ! + real(r8), public :: sponge_del4_nu_fac + real(r8), public :: sponge_del4_nu_div_fac + integer , public :: sponge_del4_lev + + integer, public :: hypervis_subcycle=1 ! number of subcycles for hyper viscsosity timestep integer, public :: hypervis_subcycle_sponge=1 ! number of subcycles for hyper viscsosity timestep in sponge integer, public :: hypervis_subcycle_q=1 ! number of subcycles for hyper viscsosity timestep on TRACERS @@ -105,18 +118,13 @@ module control_mod integer, public, parameter :: seast = 6 integer, public, parameter :: nwest = 7 integer, public, parameter :: neast = 8 - - ! - ! parameters for sponge layer Rayleigh damping - ! - real(r8), public :: raytau0 - real(r8), public :: raykrange - integer, public :: rayk0 ! ! molecular diffusion ! real(r8), public :: molecular_diff = -1.0_r8 integer, public :: vert_remap_uvTq_alg, vert_remap_tracer_alg - + + + integer, public :: pgf_formulation = -1 !PGF formulation - see prim_advance_mod.F90 end module control_mod diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index 5c64d91c..95edffee 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -69,7 +69,6 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net use hybrid_mod, only: hybrid_t use time_mod, only: TimeLevel_t, timelevel_qdp, tevolve use fvm_control_volume_mod, only: fvm_struct - use control_mod, only: raytau0 implicit none @@ -156,7 +155,6 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net dt_vis = dt - if (raytau0>0) call rayleigh_friction(elem,n0,nets,nete,dt) if (tstep_type==1) then ! RK2-SSP 3 stage. matches tracer scheme. optimal SSP CFL, but ! not optimal for regular CFL @@ -797,57 +795,12 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, ! sponge layer damping ! !*************************************************************** - ! - ! - ! vertical diffusion - ! - call t_startf('vertical_molec_diff') - if (molecular_diff>1) then - do ie=nets,nete - call get_rho_dry(elem(ie)%state%Qdp(:,:,:,1:qsize,qn0), & - elem(ie)%state%T(:,:,:,nt),ptop,elem(ie)%state%dp3d(:,:,:,nt),& - .true.,rhoi_dry=rhoi_dry(:,:,:), & - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - ! - ! constant coefficients - ! - do k=1,ksponge_end+1 - kmvisi(:,:,k) = kmvisi_ref(k)*rhoi_dry(:,:,k) - kmcndi(:,:,k) = kmcndi_ref(k)*rhoi_dry(:,:,k) - end do - ! - ! do vertical diffusion - ! - do j=1,np - do i=1,np - call solve_diffusion(dt2,np,nlev,i,j,ksponge_end,pmid,pint,kmcndi(:,:,:)/cpair,elem(ie)%state%T(:,:,:,nt),& - 0,dtemp) - call solve_diffusion(dt2,np,nlev,i,j,ksponge_end,pmid,pint,kmvisi(:,:,:),elem(ie)%state%v(:,:,1,:,nt),1,du) - call solve_diffusion(dt2,np,nlev,i,j,ksponge_end,pmid,pint,kmvisi(:,:,:),elem(ie)%state%v(:,:,2,:,nt),1,dv) - do k=1,ksponge_end - v1 = elem(ie)%state%v(i,j,1,k,nt) - v2 = elem(ie)%state%v(i,j,2,k,nt) - v1new = v1 + du(k) - v2new = v2 + dv(k) - ! - ! frictional heating - ! - heating = 0.5_r8*((v1new*v1new+v2new*v2new) - (v1*v1+v2*v2)) - elem(ie)%state%T(i,j,k,nt)=elem(ie)%state%T(i,j,k,nt) & - -heating*inv_cp_full(i,j,k,ie)+dtemp(k) - elem(ie)%state%v(i,j,1,k,nt)=v1new - elem(ie)%state%v(i,j,2,k,nt)=v2new - end do - end do - end do - end do - end if - call t_stopf('vertical_molec_diff') + call t_startf('sponge_diff') ! ! compute coefficients for horizontal diffusion ! - if (molecular_diff>0) then + if (molecular_diff==1) then do ie=nets,nete call get_rho_dry(elem(ie)%state%Qdp(:,:,:,1:qsize,qn0), & elem(ie)%state%T(:,:,:,nt),ptop,elem(ie)%state%dp3d(:,:,:,nt),& @@ -855,26 +808,14 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, active_species_idx_dycore=thermodynamic_active_species_idx_dycore) end do - if (molecular_diff==1) then - do ie=nets,nete - ! - ! compute molecular diffusion and thermal conductivity coefficients at mid-levels - ! - call get_molecular_diff_coef(elem(ie)%state%T(:,:,:,nt),.false.,km_sponge_factor(1:ksponge_end),kmvis(:,:,:,ie),kmcnd(:,:,:,ie),qsize,& - elem(ie)%state%Qdp(:,:,:,1:qsize,qn0),fact=1.0_r8/elem(ie)%state%dp3d(:,:,1:ksponge_end,nt),& - active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - end do - else + do ie=nets,nete ! - ! constant coefficients + ! compute molecular diffusion and thermal conductivity coefficients at mid-levels ! - do ie=nets,nete - do k=1,ksponge_end - kmvis (:,:,k,ie) = kmvis_ref(k) - kmcnd (:,:,k,ie) = kmcnd_ref(k) - end do - end do - end if + call get_molecular_diff_coef(elem(ie)%state%T(:,:,:,nt),.false.,km_sponge_factor(1:ksponge_end),kmvis(:,:,:,ie),kmcnd(:,:,:,ie),qsize,& + elem(ie)%state%Qdp(:,:,:,1:qsize,qn0),fact=1.0_r8/elem(ie)%state%dp3d(:,:,1:ksponge_end,nt),& + active_species_idx_dycore=thermodynamic_active_species_idx_dycore) + end do ! ! diagnostics ! @@ -928,7 +869,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, rhypervis_subcycle=1.0_r8/real(hypervis_subcycle_sponge,kind=r8) do ie=nets,nete do k=1,ksponge_end - if (nu_top>0.or.molecular_diff>1) then + if (nu_top>0.or.molecular_diff>0) then !************************************************************** ! ! traditional sponge formulation (constant coefficients) @@ -2245,78 +2186,4 @@ subroutine fill_element(Eval) return end subroutine fill_element - subroutine rayleigh_friction(elem,nt,nets,nete,dt) - use dimensions_mod, only: nlev, otau - use hybrid_mod, only: hybrid_t!, get_loop_ranges - use element_mod, only: element_t - - type (element_t) , intent(inout), target :: elem(:) - integer , intent(in) :: nets,nete, nt - real(r8) :: dt - - real(r8) :: c1, c2 - integer :: k,ie - - do ie=nets,nete - do k=1,nlev - c2 = 1._r8 / (1._r8 + otau(k)*dt) - c1 = -otau(k) * c2 * dt - elem(ie)%state%v(:,:,:,k,nt) = elem(ie)%state%v(:,:,:,k,nt)+c1 * elem(ie)%state%v(:,:,:,k,nt) -! ptend%s(:ncol,k) = c3 * (state%u(:ncol,k)**2 + state%v(:ncol,k)**2) - enddo - end do - end subroutine rayleigh_friction - - - - subroutine solve_diffusion(dt,nx,nlev,i,j,nlay,pmid,pint,km,fld,boundary_condition,dfld) - use dynconst, only: gravit - real(kind=r8), intent(in) :: dt - integer , intent(in) :: nlay, nlev,nx, i, j - real(kind=r8), intent(in) :: pmid(nx,nx,nlay),pint(nx,nx,nlay+1),km(nx,nx,nlay+1) - real(kind=r8), intent(in) :: fld(nx,nx,nlev) - real(kind=r8), intent(out) :: dfld(nlay) - integer :: boundary_condition - ! - real(kind=r8), dimension(nlay) :: current_guess,next_iterate - real(kind=r8) :: alp, alm, value_level0 - integer :: k,iter, niterations=4 - - ! Make the guess for the next time step equal to the initial value - current_guess(:)= fld(i,j,1:nlay) - do iter = 1, niterations - ! two formulations of the upper boundary condition - !next_iterate(1) = (initial_value(1) + alp * current_guess(i+1) + alm * current_guess(1)) /(1. + alp + alm) ! top BC, u'=0 - if (boundary_condition==0) then - next_iterate(1) = fld(i,j,1) ! u doesn't get prognosed by diffusion at top - else if (boundary_condition==1) then - value_level0 = 0.75_r8*fld(i,j,1) ! value above sponge - k=1 - alp = dt*(km(i,j,k+1)*gravit*gravit/(pmid(i,j,k)-pmid(i,j,k+1)))/(pint(i,j,k)-pint(i,j,k+1)) - alm = dt*(km(i,j,k )*gravit*gravit/(0.5_r8*(pmid(i,j,1)-pmid(i,j,2))))/(pint(i,j,k)-pint(i,j,k+1)) - next_iterate(k) = (fld(i,j,k) + alp * current_guess(k+1) + alm * value_level0)/(1._r8 + alp + alm) - else - ! - ! set fld'=0 at model top - ! - k=1 - alp = dt*(km(i,j,k+1)*gravit*gravit/(pmid(i,j,k)-pmid(i,j,k+1)))/(pint(i,j,k)-pint(i,j,k+1)) - alm = dt*(km(i,j,k )*gravit*gravit/(0.5_r8*(pmid(i,j,1)-pmid(i,j,2))))/(pint(i,j,k)-pint(i,j,k+1)) - next_iterate(k) = (fld(i,j,1) + alp * current_guess(2) + alm * current_guess(1))/(1._r8 + alp + alm) - end if - do k = 2, nlay-1 - alp = dt*(km(i,j,k+1)*gravit*gravit/(pmid(i,j,k )-pmid(i,j,k+1)))/(pint(i,j,k)-pint(i,j,k+1)) - alm = dt*(km(i,j,k )*gravit*gravit/(pmid(i,j,k-1)-pmid(i,j,k )))/(pint(i,j,k)-pint(i,j,k+1)) - next_iterate(k) = (fld(i,j,k) + alp * current_guess(k+1) + alm * current_guess(k-1))/(1._r8 + alp + alm) - end do - next_iterate(nlay) = (fld(i,j,nlay) + alp * fld(i,j,nlay) + alm * current_guess(nlay-1))/(1._r8 + alp + alm) ! bottom BC - - ! before the next iterate, make the current guess equal to the values of the last iteration - current_guess(:) = next_iterate(:) - end do - dfld(:) = next_iterate(:) - fld(i,j,1:nlay) - - end subroutine solve_diffusion - - end module prim_advance_mod diff --git a/src/dynamics/se/dyn_comp.F90 b/src/dynamics/se/dyn_comp.F90 index ddb73707..77ee5ebf 100644 --- a/src/dynamics/se/dyn_comp.F90 +++ b/src/dynamics/se/dyn_comp.F90 @@ -111,10 +111,10 @@ subroutine dyn_readnl(NLFileName) use control_mod, only: vert_remap_uvTq_alg, vert_remap_tracer_alg use control_mod, only: tstep_type, rk_stage_user use control_mod, only: ftype, limiter_option, partmethod - use control_mod, only: topology, phys_dyn_cp, variable_nsplit + use control_mod, only: topology, variable_nsplit use control_mod, only: fine_ne, hypervis_power, hypervis_scaling use control_mod, only: max_hypervis_courant, statediag_numtrac,refined_mesh - use control_mod, only: raytau0, raykrange, rayk0, molecular_diff + use control_mod, only: molecular_diff, pgf_formulation, dribble_in_rsplit_loop use dimensions_mod, only: ne, npart use dimensions_mod, only: hypervis_dynamic_ref_state,large_Courant_incr use dimensions_mod, only: fvm_supercycling, fvm_supercycling_jet @@ -169,10 +169,6 @@ subroutine dyn_readnl(NLFileName) integer :: se_fvm_supercycling_jet integer :: se_kmin_jet integer :: se_kmax_jet - integer :: se_phys_dyn_cp - real(r8) :: se_raytau0 - real(r8) :: se_raykrange - integer :: se_rayk0 real(r8) :: se_molecular_diff namelist /dyn_se_nl/ & @@ -216,10 +212,6 @@ subroutine dyn_readnl(NLFileName) se_fvm_supercycling_jet, & se_kmin_jet, & se_kmax_jet, & - se_phys_dyn_cp, & - se_raytau0, & - se_raykrange, & - se_rayk0, & se_molecular_diff !-------------------------------------------------------------------------- @@ -288,12 +280,7 @@ subroutine dyn_readnl(NLFileName) call MPI_bcast(se_fvm_supercycling_jet, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_kmin_jet, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_kmax_jet, 1, mpi_integer, masterprocid, mpicom, ierr) - call MPI_bcast(se_phys_dyn_cp, 1, mpi_integer, masterprocid, mpicom, ierr) - call MPI_bcast(se_rayk0 , 1, mpi_integer, masterprocid, mpicom, ierr) - call MPI_bcast(se_raykrange, 1, mpi_real8, masterprocid, mpicom, ierr) - call MPI_bcast(se_raytau0, 1, mpi_real8, masterprocid, mpicom, ierr) call MPI_bcast(se_molecular_diff, 1, mpi_real8, masterprocid, mpicom, ierr) - ! If se_npes is set to negative one, then make it match host model: if (se_npes == -1) then se_npes = npes @@ -363,10 +350,6 @@ subroutine dyn_readnl(NLFileName) kmin_jet = se_kmin_jet kmax_jet = se_kmax_jet variable_nsplit = .false. - phys_dyn_cp = se_phys_dyn_cp - raytau0 = se_raytau0 - raykrange = se_raykrange - rayk0 = se_rayk0 molecular_diff = se_molecular_diff if (rsplit < 1) then @@ -425,7 +408,6 @@ subroutine dyn_readnl(NLFileName) end if write(iulog, '(a,i0)') 'dyn_readnl: se_npes = ',se_npes write(iulog, '(a,i0)') 'dyn_readnl: se_nsplit = ',se_nsplit - write(iulog, '(a,i0)') 'dyn_readnl: se_phys_dyn_cp = ',se_phys_dyn_cp ! ! se_nu<0 then coefficients are set automatically in module global_norms_mod ! @@ -482,10 +464,6 @@ subroutine dyn_readnl(NLFileName) se_write_gll_corners write(iulog,'(a,l1)') 'dyn_readnl: write restart data on unstructured grid = ', & se_write_restart_unstruct - - write(iulog, '(a,e9.2)') 'dyn_readnl: se_raytau0 = ', raytau0 - write(iulog, '(a,e9.2)') 'dyn_readnl: se_raykrange = ', raykrange - write(iulog, '(a,i0)' ) 'dyn_readnl: se_rayk0 = ', rayk0 write(iulog, '(a,e9.2)') 'dyn_readnl: se_molecular_diff = ', molecular_diff end if @@ -572,7 +550,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) use dimensions_mod, only: irecons_tracer_lev, irecons_tracer, otau, kord_tr, kord_tr_cslam use prim_driver_mod, only: prim_init2 use time_mod, only: time_at - use control_mod, only: runtype, raytau0, raykrange, rayk0, molecular_diff, nu_top + use control_mod, only: runtype, nu_top, molecular_diff use test_fvm_mapping, only: test_mapping_addfld use control_mod, only: vert_remap_uvTq_alg, vert_remap_tracer_alg @@ -718,27 +696,6 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) call clean_iodesc_list() end if ! - ! initialize Rayleigh friction - ! - krange = raykrange - if (raykrange .eq. 0._r8) krange = (rayk0 - 1) / 2._r8 - tau0 = (86400._r8) * raytau0 ! convert to seconds - otau0 = 0._r8 - if (tau0 .ne. 0._r8) otau0 = 1._r8/tau0 - do k = 1, nlev - otau(k) = otau0 * (1.0_r8 + tanh((rayk0 - k) / krange)) / (2._r8) - enddo - if (masterproc) then - if (tau0 > 0._r8) then - write (iulog,*) 'SE dycore Rayleigh friction - krange = ', krange - write (iulog,*) 'SE dycore Rayleigh friction - otau0 = ', 1.0_r8/tau0 - write (iulog,*) 'SE dycore Rayleigh friction decay rate profile (only applied to (u,v))' - do k = 1, nlev - write (iulog,*) ' k = ', k, ' otau = ', otau(k) - enddo - end if - end if - ! ! initialize diffusion in dycore ! kmol_end = 0 diff --git a/src/dynamics/se/namelist_definition_se_dycore.xml b/src/dynamics/se/namelist_definition_se_dycore.xml index 6c2ad249..580ed330 100644 --- a/src/dynamics/se/namelist_definition_se_dycore.xml +++ b/src/dynamics/se/namelist_definition_se_dycore.xml @@ -89,66 +89,16 @@ 4 - - integer - se - dyn_se_nl - - Variable to specify the vertical index at which the - Rayleigh friction term is centered (the peak value). - Default: 2 - - - 2 - - - - real - se - dyn_se_nl - - Rayleigh friction parameter to determine the width of the profile. If set - to 0 then a width is chosen by the algorithm (see rayleigh_friction.F90). - Default: 0.5. - - - 0.5 - 3 - - - - real - se - dyn_se_nl - - Rayleigh friction parameter to determine the approximate value of the decay - time (days) at model top. If 0.0 then no Rayleigh friction is applied. - Default: 0. - - - 0.0 - - real se dyn_se_nl - Used by SE dycore to apply sponge layer diffusion to u, v, and T for - stability of WACCM configurations. The diffusion is modeled on 3D molecular - diffusion and thermal conductivity by using actual molecular diffusion and - thermal conductivity coefficients multiplied by the value of - se_molecular_diff. - - If set <= 0.0 then the code is not activated. If set > 0.0 then - the molecular diffusion and thermal conductivity coefficients will be - multiplied by a factor of se_molecular_diff. - - Default: 0. + Enable thermal conductivity and molecular diffusion in the horizontal in SE dycore. 0.0 - 100.0 + 1.0 @@ -255,22 +205,6 @@ 7 - - integer - se - dyn_se_nl - 0,1,2 - - Scaling of temperature increment for different levels of - thermal energy consistency. - 0: no scaling - 1: scale increment for cp consistency between dynamics and physics - 2: do 1 as well as take into account condensate effect on thermal energy - - - 1 - - real se From 983b1322b06e9c0f79710d72fad336fe8b57acc7 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 13 Dec 2024 16:29:46 -0700 Subject: [PATCH 04/12] rename nu_s->nu_t --- src/dynamics/se/dycore/control_mod.F90 | 2 +- src/dynamics/se/dycore/global_norms_mod.F90 | 4 ++-- src/dynamics/se/dycore/prim_advance_mod.F90 | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/dynamics/se/dycore/control_mod.F90 b/src/dynamics/se/dycore/control_mod.F90 index 4de87e33..245e5d95 100644 --- a/src/dynamics/se/dycore/control_mod.F90 +++ b/src/dynamics/se/dycore/control_mod.F90 @@ -61,7 +61,7 @@ module control_mod ! (only used for variable viscosity, recommend 1.9 in namelist) real (kind=r8), public :: nu = 7.0D5 ! viscosity (momentum equ) real (kind=r8), public :: nu_div = -1 ! viscsoity (momentum equ, div component) - real (kind=r8), public :: nu_s = -1 ! default = nu T equ. viscosity xxx rename nu_t + real (kind=r8), public :: nu_t = -1 ! default = nu T equ. viscosity xxx rename nu_t real (kind=r8), public :: nu_q = -1 ! default = nu tracer viscosity real (kind=r8), public :: nu_p = 0.0D5 ! default = 0 ps equ. viscosity real (kind=r8), public :: nu_top = 0.0D5 ! top-of-the-model viscosity diff --git a/src/dynamics/se/dycore/global_norms_mod.F90 b/src/dynamics/se/dycore/global_norms_mod.F90 index 21d46b9b..772bcac8 100644 --- a/src/dynamics/se/dycore/global_norms_mod.F90 +++ b/src/dynamics/se/dycore/global_norms_mod.F90 @@ -212,7 +212,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& use reduction_mod, only: ParallelMin,ParallelMax use dynconst, only: ra, rearth, cpair - use control_mod, only: nu, nu_div, nu_q, nu_p, nu_s, nu_top, fine_ne, rk_stage_user, max_hypervis_courant + use control_mod, only: nu, nu_div, nu_q, nu_p, nu_t, nu_top, fine_ne, rk_stage_user, max_hypervis_courant use control_mod, only: tstep_type, hypervis_power, hypervis_scaling use cam_abortutils, only: endrun use parallel_mod, only: global_shared_buf, global_shared_sum @@ -573,7 +573,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& end if if (nu_q<0) nu_q = nu_p ! necessary for consistency - if (nu_s<0) nu_s = nu_p ! temperature damping is always equal to nu_p + if (nu_t<0) nu_t = nu_p ! temperature damping is always equal to nu_p !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index 95edffee..86da98a6 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -498,7 +498,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, use dimensions_mod, only: hypervis_dynamic_ref_state,ksponge_end use dimensions_mod, only: nu_scale_top,nu_lev,kmvis_ref,kmcnd_ref,rho_ref,km_sponge_factor use dimensions_mod, only: kmvisi_ref,kmcndi_ref,rhoi_ref - use control_mod, only: nu, nu_s, hypervis_subcycle,hypervis_subcycle_sponge, nu_p, nu_top + use control_mod, only: nu, nu_t, hypervis_subcycle,hypervis_subcycle_sponge, nu_p, nu_top use control_mod, only: molecular_diff use hybrid_mod, only: hybrid_t!, get_loop_ranges use element_mod, only: element_t @@ -554,7 +554,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, real (kind=r8), dimension(ksponge_end) :: dtemp,du,dv real (kind=r8) :: nu_temp, nu_dp, nu_velo - if (nu_s == 0 .and. nu == 0 .and. nu_p==0 ) return; + if (nu_t == 0 .and. nu == 0 .and. nu_p==0 ) return; ptop = hvcoord%hyai(1)*hvcoord%ps0 @@ -637,7 +637,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, !DIR_VECTOR_ALIGNED do j=1,np do i=1,np - ttens(i,j,k,ie) = -nu_s*ttens(i,j,k,ie) + ttens(i,j,k,ie) = -nu_t*ttens(i,j,k,ie) dptens(i,j,k,ie) = -nu_p*dptens(i,j,k,ie) vtens(i,j,1,k,ie) = -nu_lev(k)*vtens(i,j,1,k,ie) vtens(i,j,2,k,ie) = -nu_lev(k)*vtens(i,j,2,k,ie) From ef7a2744d5fd691176faecccad901f8c1baab366 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 13 Dec 2024 17:13:59 -0700 Subject: [PATCH 05/12] remove unused variables (element_mod.F90 merged) --- src/dynamics/se/dycore/element_mod.F90 | 100 +++---------------------- src/dynamics/se/dycore/prim_init.F90 | 16 ---- 2 files changed, 11 insertions(+), 105 deletions(-) diff --git a/src/dynamics/se/dycore/element_mod.F90 b/src/dynamics/se/dycore/element_mod.F90 index 2fa3b91a..c1401794 100644 --- a/src/dynamics/se/dycore/element_mod.F90 +++ b/src/dynamics/se/dycore/element_mod.F90 @@ -45,10 +45,6 @@ module element_mod real(kind=r8), allocatable :: phi(:,:,:) ! geopotential real(kind=r8), allocatable :: omega(:,:,:) ! vertical velocity - ! semi-implicit diagnostics: computed in explict-component, reused in Helmholtz-component. - real(kind=r8), allocatable :: zeta(:,:,:) ! relative vorticity - real(kind=r8), allocatable :: div(:,:,:,:) ! divergence - ! tracer advection fields used for consistency and limiters real(kind=r8), allocatable :: dp(:,:,:) ! for dp_tracers at physics timestep real(kind=r8), allocatable :: divdp(:,:,:) ! divergence of dp @@ -60,24 +56,10 @@ module element_mod real(kind=r8), allocatable :: FM(:,:,:,:) ! momentum forcing real(kind=r8), allocatable :: FDP(:,:,:) ! save full updated dp right after physics real(kind=r8), allocatable :: FT(:,:,:) ! temperature forcing - real(kind=r8), allocatable :: etadot_prescribed(:,:,:) ! prescribed vertical tendency - real(kind=r8), allocatable :: u_met(:,:,:) ! zonal component of prescribed meteorology winds - real(kind=r8), allocatable :: dudt_met(:,:,:) ! rate of change of zonal component of prescribed meteorology winds - real(kind=r8), allocatable :: v_met(:,:,:) ! meridional component of prescribed meteorology winds - real(kind=r8), allocatable :: dvdt_met(:,:,:) ! rate of change of meridional component of prescribed meteorology winds - real(kind=r8), allocatable :: T_met(:,:,:) ! prescribed meteorology temperature - real(kind=r8), allocatable :: dTdt_met(:,:,:) ! rate of change of prescribed meteorology temperature - real(kind=r8), allocatable :: nudge_factor(:,:,:) ! nudging factor (prescribed) - real(kind=r8), allocatable :: Utnd(:,:) ! accumulated U tendency due to nudging towards prescribed met - real(kind=r8), allocatable :: Vtnd(:,:) ! accumulated V tendency due to nudging towards prescribed met - real(kind=r8), allocatable :: Ttnd(:,:) ! accumulated T tendency due to nudging towards prescribed met - - real(kind=r8), allocatable :: pecnd(:,:,:) ! pressure perturbation from condensate - - real(kind=r8) :: ps_met(np,np) ! surface pressure of prescribed meteorology - real(kind=r8) :: dpsdt_met(np,np) ! rate of change of surface pressure of prescribed meteorology - + ! reference profiles + real(kind=r8), allocatable :: T_ref(:,:,:) ! reference temperature + real(kind=r8), allocatable :: dp_ref(:,:,:) ! reference pressure level thickness end type derived_state_t !___________________________________________________________________ @@ -455,7 +437,7 @@ subroutine allocate_element_dims(elem) allocate(elem(i)%state%Qdp(np,np,nlev,qsize_d,2), stat=iret) call check_allocate(iret, subname, 'elem%state%Qdp(np,np,nlev,qsize_d,2)', & file=__FILE__, line=__LINE__) - + !-------------------------- !Allocate "derived" variables: @@ -486,16 +468,6 @@ subroutine allocate_element_dims(elem) call check_allocate(iret, subname, 'elem%derived%omega(np,np,nlev)', & file=__FILE__, line=__LINE__) - ! relative vorticity - allocate(elem(i)%derived%zeta(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%zeta(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! divergence - allocate(elem(i)%derived%div(np,np,nlev,timelevels), stat=iret) - call check_allocate(iret, subname, 'elem%derived%div(np,np,nlev,timelevels)', & - file=__FILE__, line=__LINE__) - ! for dp_tracers at physics timestep allocate(elem(i)%derived%dp(np,np,nlev), stat=iret) call check_allocate(iret, subname, 'elem%derived%dp(np,np,nlev)', & @@ -536,64 +508,14 @@ subroutine allocate_element_dims(elem) call check_allocate(iret, subname, 'elem%derived%FT(np,np,nlev)', & file=__FILE__, line=__LINE__) - ! prescribed vertical tendency - allocate(elem(i)%derived%etadot_prescribed(np,np,nlevp), stat=iret) - call check_allocate(iret, subname, 'elem%derived%etadot_prescribed(np,np,nlevp)', & - file=__FILE__, line=__LINE__) - - ! zonal component of prescribed meteorology winds - allocate(elem(i)%derived%u_met(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%u_met(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! rate of change of zonal component of prescribed meteorology winds - allocate(elem(i)%derived%dudt_met(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%dudt_met(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! meridional component of prescribed meteorology winds - allocate(elem(i)%derived%v_met(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%v_met(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! rate of change of meridional component of prescribed meteorology winds - allocate(elem(i)%derived%dvdt_met(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%dvdt_met(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! prescribed meteorology temperature - allocate(elem(i)%derived%T_met(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%T_met(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! rate of change of prescribed meteorology temperature - allocate(elem(i)%derived%dTdt_met(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%dTdt_met(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! nudging factor (prescribed) - allocate(elem(i)%derived%nudge_factor(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%nudge_factor(np,np,nlev)', & - file=__FILE__, line=__LINE__) - - ! accumulated U tendency due to nudging towards prescribed met - allocate(elem(i)%derived%Utnd(npsq,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%Utnd(npsq,nlev)', & - file=__FILE__, line=__LINE__) - - ! accumulated V tendency due to nudging towards prescribed met - allocate(elem(i)%derived%Vtnd(npsq,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%Vtnd(npsq,nlev)', & - file=__FILE__, line=__LINE__) - - ! accumulated T tendency due to nudging towards prescribed met - allocate(elem(i)%derived%Ttnd(npsq,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%Ttnd(npsq,nlev)', & - file=__FILE__, line=__LINE__) + ! reference temperature profile for hyperviscosity + allocate(elem(i)%derived%T_ref(np,np,nlev), stat=iret) + call check_allocate(iret, subname, 'elem%derived%T_ref(np,np,nlev)', & + file=__FILE__, line=__LINE__) - ! pressure perturbation from condensate - allocate(elem(i)%derived%pecnd(np,np,nlev), stat=iret) - call check_allocate(iret, subname, 'elem%derived%pecnd(np,np,nlev)', & + ! reference pressure level thickness profile for hyperviscosity + allocate(elem(i)%derived%dp_ref(np,np,nlev), stat=iret) + call check_allocate(iret, subname, 'elem%derived%dp_ref(np,np,nlev)', & file=__FILE__, line=__LINE__) !---------------------------- diff --git a/src/dynamics/se/dycore/prim_init.F90 b/src/dynamics/se/dycore/prim_init.F90 index b0e8e425..76d3a635 100644 --- a/src/dynamics/se/dycore/prim_init.F90 +++ b/src/dynamics/se/dycore/prim_init.F90 @@ -332,25 +332,9 @@ subroutine prim_init1(elem, fvm, par, Tl) elem(ie)%derived%FQ=0.0_r8 elem(ie)%derived%FT=0.0_r8 elem(ie)%derived%FDP=0.0_r8 - elem(ie)%derived%pecnd=0.0_r8 elem(ie)%derived%Omega=0 elem(ie)%state%dp3d=0 - - elem(ie)%derived%etadot_prescribed = nan - elem(ie)%derived%u_met = nan - elem(ie)%derived%v_met = nan - elem(ie)%derived%dudt_met = nan - elem(ie)%derived%dvdt_met = nan - elem(ie)%derived%T_met = nan - elem(ie)%derived%dTdt_met = nan - elem(ie)%derived%ps_met = nan - elem(ie)%derived%dpsdt_met = nan - elem(ie)%derived%nudge_factor = nan - - elem(ie)%derived%Utnd=0._r8 - elem(ie)%derived%Vtnd=0._r8 - elem(ie)%derived%Ttnd=0._r8 end do ! ========================================================== From 5930c27a0be76c222297241dc1cbc00cf743ed65 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 13 Dec 2024 17:36:28 -0700 Subject: [PATCH 06/12] merge fvm_consistent.F90 (efficiency updates from Jim Edwards for Derecho) --- .../se/dycore/fvm_consistent_se_cslam.F90 | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 b/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 index 20391710..9cec35f9 100644 --- a/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 +++ b/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 @@ -45,7 +45,7 @@ subroutine run_consistent_se_cslam(elem,fvm,hybrid,dt_fvm,tl,nets,nete,hvcoord,& use thread_mod , only: vert_num_threads, omp_set_nested implicit none type (element_t) , intent(inout) :: elem(:) - type (fvm_struct) , intent(inout) :: fvm(:) + type (fvm_struct), target , intent(inout) :: fvm(:) type (hybrid_t) , intent(in) :: hybrid ! distributed parallel structure (shared) type (TimeLevel_t) , intent(in) :: tl ! time level struct type (hvcoord_t) , intent(in) :: hvcoord @@ -72,7 +72,9 @@ subroutine run_consistent_se_cslam(elem,fvm,hybrid,dt_fvm,tl,nets,nete,hvcoord,& integer :: region_num_threads logical :: inJetCall logical :: ActiveJetThread - + + real(r8), pointer :: fcube(:,:,:,:) + real(r8), pointer :: spherecentroid(:,:,:) llimiter = .true. @@ -153,22 +155,26 @@ subroutine run_consistent_se_cslam(elem,fvm,hybrid,dt_fvm,tl,nets,nete,hvcoord,& !call t_stopf('fvm:orthogonal_swept_areas') do ie=nets,nete + ! Intel compiler version 2023.0.0 on derecho had significant slowdown on subroutine interface without + ! these pointers. + fcube => fvm(ie)%c(:,:,:,:) + spherecentroid => fvm(ie)%spherecentroid(:,1-nhe:nc+nhe,1-nhe:nc+nhe) do k=kmin,kmax - !call t_startf('fvm:tracers_reconstruct') - call reconstruction(fvm(ie)%c(:,:,:,:),nlev,k,& + !call t_startf('FVM:tracers_reconstruct') + call reconstruction(fcube,nlev,k,& ctracer(:,:,:,:),irecons_tracer,llimiter,ntrac,& nc,nhe,nhr,nhc,nht,ns,nhr+(nhe-1),& fvm(ie)%jx_min,fvm(ie)%jx_max,fvm(ie)%jy_min,fvm(ie)%jy_max,& fvm(ie)%cubeboundary,fvm(ie)%halo_interp_weight,fvm(ie)%ibase,& - fvm(ie)%spherecentroid(:,1-nhe:nc+nhe,1-nhe:nc+nhe),& + spherecentroid,& fvm(ie)%recons_metrics,fvm(ie)%recons_metrics_integral,& fvm(ie)%rot_matrix,fvm(ie)%centroid_stretch,& fvm(ie)%vertex_recons_weights,fvm(ie)%vtx_cart,& irecons_tracer_lev(k)) - !call t_stopf('fvm:tracers_reconstruct') - !call t_startf('fvm:swept_flux') - call swept_flux(elem(ie),fvm(ie),k,ctracer,irecons_tracer_lev(k),gsweights,gspts) - !call t_stopf('fvm:swept_flux') + !call t_stopf('FVM:tracers_reconstruct') + !call t_startf('fvm:swept_flux') + call swept_flux(elem(ie),fvm(ie),k,ctracer,irecons_tracer_lev(k),gsweights,gspts) + !call t_stopf('fvm:swept_flux') end do end do ! From 14ecf1fe547f7ff9919f0ba35469ab35bd96dbf5 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Tue, 17 Dec 2024 08:41:53 -0700 Subject: [PATCH 07/12] merge use_cslam logic (instead of ntrac>0) --- src/dynamics/se/advect_tend.F90 | 175 +++++++++++++++++- src/dynamics/se/dp_coupling.F90 | 10 +- src/dynamics/se/dycore/dimensions_mod.F90 | 1 + src/dynamics/se/dycore/fvm_mod.F90 | 24 +-- src/dynamics/se/dycore/global_norms_mod.F90 | 23 +-- src/dynamics/se/dycore/hybrid_mod.F90 | 4 +- src/dynamics/se/dycore/namelist_mod.F90 | 4 +- src/dynamics/se/dycore/prim_advance_mod.F90 | 40 ++-- src/dynamics/se/dycore/prim_advection_mod.F90 | 8 +- src/dynamics/se/dycore/prim_driver_mod.F90 | 16 +- src/dynamics/se/dycore/prim_state_mod.F90 | 16 +- .../{time_mod.F90 => se_dyn_time_mod.F90} | 3 +- src/dynamics/se/dycore/viscosity_mod.F90 | 6 +- src/dynamics/se/dyn_comp.F90 | 68 +++++-- src/dynamics/se/dyn_grid.F90 | 6 +- src/dynamics/se/test_fvm_mapping.F90 | 6 +- 16 files changed, 313 insertions(+), 97 deletions(-) rename src/dynamics/se/dycore/{time_mod.F90 => se_dyn_time_mod.F90} (98%) diff --git a/src/dynamics/se/advect_tend.F90 b/src/dynamics/se/advect_tend.F90 index 62d5b65c..8b5a4966 100644 --- a/src/dynamics/se/advect_tend.F90 +++ b/src/dynamics/se/advect_tend.F90 @@ -29,7 +29,7 @@ subroutine compute_adv_tends_xyz(elem,fvm,nets,nete,qn0,n0) use cam_abortutils, only: check_allocate ! SE dycore: - use dimensions_mod, only: nc,np,nlev,ntrac + use dimensions_mod, only: nc,np,nlev,ntrac,use_cslam use element_mod, only: element_t use fvm_control_volume_mod, only: fvm_struct @@ -45,7 +45,7 @@ subroutine compute_adv_tends_xyz(elem,fvm,nets,nete,qn0,n0) character(len=*), parameter :: subname = 'compute_adv_tends_xyz' - if (ntrac>0) then + if (use_cslam) then nx=nc else nx=np @@ -65,7 +65,7 @@ subroutine compute_adv_tends_xyz(elem,fvm,nets,nete,qn0,n0) adv_tendxyz(:,:,:,:,:) = 0._r8 endif - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete do ic = 1, num_advected adv_tendxyz(:,:,:,ic,ie) = fvm(ie)%c(1:nc,1:nc,:,ic) - adv_tendxyz(:,:,:,ic,ie) @@ -105,5 +105,174 @@ subroutine compute_adv_tends_xyz(elem,fvm,nets,nete,qn0,n0) deallocate(ftmp) #endif end subroutine compute_adv_tends_xyz +#ifdef scm_code + !---------------------------------------------------------------------- + ! computes camiop specific tendencies + ! and writes these to the camiop file + ! called twice each time step: + ! - first call sets the initial mixing ratios/state + ! - second call computes and outputs the tendencies + !---------------------------------------------------------------------- + subroutine compute_write_iop_fields(elem,fvm,nets,nete,qn0,n0) + use cam_abortutils, only: endrun + use cam_history, only: outfld, hist_fld_active + use time_manager, only: get_step_size + use constituents, only: pcnst,cnst_name + use dimensions_mod, only: nc,np,nlev,use_cslam,npsq + use element_mod, only: element_t + use fvm_control_volume_mod, only: fvm_struct + implicit none + + type (element_t), intent(inout) :: elem(:) + type(fvm_struct), intent(inout) :: fvm(:) + integer, intent(in) :: nets,nete,qn0,n0 + real(r8) :: dt + real(r8), allocatable :: q_new(:,:,:) + real(r8), allocatable :: q_adv(:,:,:) + real(r8), allocatable :: t_adv(:,:) + real(r8), allocatable :: out_q(:,:) + real(r8), allocatable :: out_t(:,:) + real(r8), allocatable :: out_u(:,:) + real(r8), allocatable :: out_v(:,:) + real(r8), allocatable :: out_ps(:) + + integer :: i,j,ic,nx,ie,nxsq,p + integer :: ierr + logical :: init + character(len=*), parameter :: sub = 'compute_write_iop_fields:' + !---------------------------------------------------------------------------- + + if (use_cslam) then + nx=nc + else + nx=np + endif + nxsq=nx*nx + init = .false. + dt = get_step_size() + + if ( .not. allocated( iop_qtendxyz ) ) then + init = .true. + + allocate( iop_qtendxyz(nx,nx,nlev,pcnst,nets:nete),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate iop_qtendxyz' ) + iop_qtendxyz = 0._r8 + allocate( derivedfq(nx,nx,nlev,pcnst,nets:nete),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate derivedfq' ) + derivedfq = 0._r8 + allocate( iop_qtendxyz_init(nx,nx,nlev,pcnst,nets:nete),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate iop_qtendxyz' ) + iop_qtendxyz_init = 0._r8 + allocate( iop_ttendxyz(nx,nx,nlev,nets:nete),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate iop_ttendxyz' ) + iop_ttendxyz = 0._r8 + allocate( iop_ttendxyz_init(nx,nx,nlev,nets:nete),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate iop_ttendxyz_init' ) + iop_ttendxyz_init = 0._r8 + endif + + ! save initial/calc tendencies on second call to this routine. + if (use_cslam) then + do ie=nets,nete + do ic=1,pcnst + iop_qtendxyz(:,:,:,ic,ie) = fvm(ie)%c(1:nc,1:nc,:,ic) - iop_qtendxyz(:,:,:,ic,ie) + end do + end do + else + do ie=nets,nete + do ic=1,pcnst + iop_qtendxyz(:,:,:,ic,ie) = elem(ie)%state%Qdp(:,:,:,ic,qn0)/elem(ie)%state%dp3d(:,:,:,n0) - iop_qtendxyz(:,:,:,ic,ie) + enddo + end do + end if + do ie=nets,nete + iop_ttendxyz(:,:,:,ie) = elem(ie)%state%T(:,:,:,n0) - iop_ttendxyz(:,:,:,ie) + end do + + if (init) then + do ie=nets,nete + iop_ttendxyz_init(:,:,:,ie) = iop_ttendxyz(:,:,:,ie) + iop_qtendxyz_init(:,:,:,:,ie) = iop_qtendxyz(:,:,:,:,ie) + derivedfq(:,:,:,:,ie)=elem(ie)%derived%FQ(:,:,:,:)/dt + end do + end if + + if ( .not. init ) then + allocate( q_adv(nxsq,nlev,pcnst),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate q_adv' ) + q_adv = 0._r8 + allocate( t_adv(npsq,nlev),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate t_adv' ) + t_adv = 0._r8 + allocate( q_new(nx,nx,nlev),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate q_new' ) + q_new = 0._r8 + allocate( out_q(npsq,nlev),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate out_q' ) + out_q = 0._r8 + allocate( out_t(npsq,nlev),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate out_t' ) + out_t = 0._r8 + allocate( out_u(npsq,nlev),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate out_u' ) + out_u = 0._r8 + allocate( out_v(npsq,nlev),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate out_v' ) + out_v = 0._r8 + allocate( out_ps(npsq),stat=ierr ) + if (ierr/=0) call endrun( sub//': not able to allocate out_ps' ) + out_ps = 0._r8 + do ie=nets,nete + do j=1,nx + do i=1,nx + t_adv(i+(j-1)*np,:) = iop_ttendxyz(i,j,:,ie)/dt - elem(ie)%derived%FT(i,j,:) + out_u(i+(j-1)*np,:) = elem(ie)%state%v(i,j,1,:,n0) + out_v(i+(j-1)*np,:) = elem(ie)%state%v(i,j,2,:,n0) + out_ps(i+(j-1)*np) = elem(ie)%state%psdry(i,j) + + ! to retain bfb, replace state q and t with roundoff version calculated using the ordering and tendencies of the + ! scam prognostic equation + elem(ie)%state%T(i,j,:,n0) = iop_ttendxyz_init(i,j,:,ie) + dt*(elem(ie)%derived%FT(i,j,:) + t_adv(i+(j-1)*np,:)) + out_t(i+(j-1)*np,:) = elem(ie)%state%T(i,j,:,n0) + do p=1,pcnst + q_adv(i+(j-1)*nx,:,p) = iop_qtendxyz(i,j,:,p,ie)/dt - derivedfq(i,j,:,p,ie) + q_new(i,j,:) = iop_qtendxyz_init(i,j,:,p,ie) + dt*(derivedfq(i,j,:,p,ie) + q_adv(i+(j-1)*nx,:,p)) + if (use_cslam) then + fvm(ie)%c(i,j,:,p)=q_new(i,j,:) + else + elem(ie)%state%Qdp(i,j,:,p,qn0)=q_new(i,j,:)*elem(ie)%state%dp3d(i,j,:,n0) + end if + enddo + out_q(i+(j-1)*nx,:) = elem(ie)%state%Qdp(i,j,:,1,qn0)/elem(ie)%state%dp3d(i,j,:,n0) + end do + end do + call outfld('Ps',out_ps,npsq,ie) + call outfld('t',out_t,npsq,ie) + call outfld('q',out_q,nxsq,ie) + call outfld('u',out_u,npsq,ie) + call outfld('v',out_v,npsq,ie) + call outfld('divT3d',t_adv,npsq,ie) + do p=1,pcnst + call outfld(trim(cnst_name(p))//'_dten',q_adv(:,:,p),nxsq,ie) + enddo + end do + + deallocate(iop_ttendxyz) + deallocate(iop_ttendxyz_init) + deallocate(iop_qtendxyz) + deallocate(iop_qtendxyz_init) + deallocate(derivedfq) + deallocate(out_t) + deallocate(out_q) + deallocate(out_u) + deallocate(out_v) + deallocate(out_ps) + deallocate(t_adv) + deallocate(q_adv) + deallocate(q_new) + + endif + end subroutine compute_write_iop_fields +#endif end module advect_tend diff --git a/src/dynamics/se/dp_coupling.F90 b/src/dynamics/se/dp_coupling.F90 index 2f819682..9eb8da2b 100644 --- a/src/dynamics/se/dp_coupling.F90 +++ b/src/dynamics/se/dp_coupling.F90 @@ -329,7 +329,7 @@ subroutine p_d_coupling(cam_runtime_opts, phys_state, phys_tend, dyn_in, tl_f, t use bndry_mod, only: bndry_exchange use edge_mod, only: edgeVpack, edgeVunpack use fvm_mapping, only: phys2dyn_forcings_fvm - + use dimensions_mod, only: use_cslam ! arguments type(runtime_options), intent(in) :: cam_runtime_opts ! Runtime settings object type(physics_state), intent(inout) :: phys_state @@ -522,7 +522,13 @@ subroutine p_d_coupling(cam_runtime_opts, phys_state, phys_tend, dyn_in, tl_f, t kptr = kptr + 2*nlev call edgeVpack(edgebuf, dyn_in%elem(ie)%derived%FT(:,:,:), nlev, kptr, ie) kptr = kptr + nlev +!xxx if (.not. use_cslam) then +!xxx ! +!xxx ! if using CSLAM qdp is being overwritten with CSLAM values in the dynamics +!xxx ! so no need to do boundary exchange of tracer tendency on GLL grid here +!xxx ! call edgeVpack(edgebuf, dyn_in%elem(ie)%derived%FQ(:,:,:,:), nlev*qsize, kptr, ie) +!xxx end of end do if (iam < par%nprocs) then @@ -534,8 +540,10 @@ subroutine p_d_coupling(cam_runtime_opts, phys_state, phys_tend, dyn_in, tl_f, t call edgeVunpack(edgebuf, dyn_in%elem(ie)%derived%FM(:,:,:,:), 2*nlev, kptr, ie) kptr = kptr + 2*nlev call edgeVunpack(edgebuf, dyn_in%elem(ie)%derived%FT(:,:,:), nlev, kptr, ie) +!xxx if (.not. use_cslam) then kptr = kptr + nlev call edgeVunpack(edgebuf, dyn_in%elem(ie)%derived%FQ(:,:,:,:), nlev*qsize, kptr, ie) +!xxx end if if (fv_nphys > 0) then do k = 1, nlev dyn_in%elem(ie)%derived%FM(:,:,1,k) = & diff --git a/src/dynamics/se/dycore/dimensions_mod.F90 b/src/dynamics/se/dycore/dimensions_mod.F90 index 0fe69bc3..3c393a42 100644 --- a/src/dynamics/se/dycore/dimensions_mod.F90 +++ b/src/dynamics/se/dycore/dimensions_mod.F90 @@ -25,6 +25,7 @@ module dimensions_mod integer , public :: fv_nphys !physics-grid resolution - the "MAX" is so that the code compiles with NC=0 integer, public, protected :: qsize_d !SE tracer dimension size + logical, public :: use_cslam = .false. !logical for CSLAM integer, public, protected :: ntrac = 0 !FVM tracer dimension size integer, public :: qsize = 0 !qsize is set in dyn_comp ! diff --git a/src/dynamics/se/dycore/fvm_mod.F90 b/src/dynamics/se/dycore/fvm_mod.F90 index 925e5e89..72b4a01e 100644 --- a/src/dynamics/se/dycore/fvm_mod.F90 +++ b/src/dynamics/se/dycore/fvm_mod.F90 @@ -302,28 +302,24 @@ subroutine fvm_init1(par,elem) use control_mod, only: rsplit use dimensions_mod, only: qsize, qsize_d use dimensions_mod, only: fvm_supercycling, fvm_supercycling_jet - use dimensions_mod, only: nc,nhe, nhc, nlev,ntrac, ntrac,ns, nhr + use dimensions_mod, only: nc,nhe, nhc, nlev,ntrac, ntrac,ns, nhr, use_cslam use dimensions_mod, only: large_Courant_incr use dimensions_mod, only: kmin_jet,kmax_jet type (parallel_t) :: par type (element_t),intent(inout) :: elem(:) ! - if (ntrac>0) then + if (use_cslam) then if (par%masterproc) then write(iulog,*) " " write(iulog,*) "|-----------------------------------------|" write(iulog,*) "| FVM tracer transport scheme information |" write(iulog,*) "|-----------------------------------------|" write(iulog,*) " " - end if - if (ntrac>0) then - if (par%masterproc) then - write(iulog,*) "Running consistent SE-CSLAM, Lauritzen et al. (2017, MWR)." - write(iulog,*) "CSLAM = Conservative Semi-LAgrangian Multi-tracer scheme" - write(iulog,*) "Lauritzen et al., (2010), J. Comput. Phys." - write(iulog,*) " " - end if + write(iulog,*) "Running consistent SE-CSLAM, Lauritzen et al. (2017, MWR)." + write(iulog,*) "CSLAM = Conservative Semi-LAgrangian Multi-tracer scheme" + write(iulog,*) "Lauritzen et al., (2010), J. Comput. Phys." + write(iulog,*) " " end if ! ! PARAMETER ERROR CHECKING @@ -423,8 +419,8 @@ subroutine fvm_init1(par,elem) endif call endrun("stopping") end if - end if - + endif + if (nc==4.and.ns.ne.4) then if (par%masterproc) then write(iulog,*) "Recommended setting for nc=4 is ns=4 (cubic interpolation in halo)" @@ -527,7 +523,7 @@ end subroutine fvm_init2 subroutine fvm_init3(elem,fvm,hybrid,nets,nete,irecons) use control_mod , only: neast, nwest, seast, swest use fvm_analytic_mod, only: compute_reconstruct_matrix - use dimensions_mod , only: fv_nphys + use dimensions_mod , only: fv_nphys, use_cslam use dimensions_mod, only: nlev, nc, nhe, nlev, ntrac, nhc use coordinate_systems_mod, only: cartesian2D_t,cartesian3D_t use coordinate_systems_mod, only: cubedsphere2cart, cart2cubedsphere @@ -546,7 +542,7 @@ subroutine fvm_init3(elem,fvm,hybrid,nets,nete,irecons) type (cartesian2D_t) :: gnom type(cartesian3D_t) :: tmpcart3d - if (ntrac>0.and.nc.ne.fv_nphys) then + if (use_cslam.and.nc.ne.fv_nphys) then ! ! fill the fvm halo for mapping in d_p_coupling if ! physics grid resolution is different than fvm resolution diff --git a/src/dynamics/se/dycore/global_norms_mod.F90 b/src/dynamics/se/dycore/global_norms_mod.F90 index 772bcac8..667e5693 100644 --- a/src/dynamics/se/dycore/global_norms_mod.F90 +++ b/src/dynamics/se/dycore/global_norms_mod.F90 @@ -205,7 +205,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& ! use hybrid_mod, only: hybrid_t, PrintHybrid use element_mod, only: element_t - use dimensions_mod, only: np,ne,nelem,nelemd,nc,nhe,qsize,ntrac,nlev,large_Courant_incr + use dimensions_mod, only: np,ne,nelem,nelemd,nc,nhe,use_cslam,nlev,large_Courant_incr use dimensions_mod, only: nu_scale_top,nu_div_lev,nu_lev use quadrature_mod, only: gausslobatto, quadrature_t @@ -604,7 +604,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& write(iulog,*) rk_str write(iulog,'(a)') ' * Spectral-element advection uses SSP preservation RK3' write(iulog,'(a)') ' * Viscosity operators use forward Euler' - if (ntrac>0) then + if (use_cslam) then write(iulog,'(a)') ' * CSLAM uses two time-levels backward trajectory method' end if end if @@ -624,7 +624,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& dt_max_adv = S_rk/(umax*max_normDinv*lambda_max*ra) dt_max_gw = S_rk/(ugw*max_normDinv*lambda_max*ra) dt_max_tracer_se = S_rk_tracer*min_gw/(umax*max_normDinv*ra) - if (ntrac>0) then + if (use_cslam) then if (large_Courant_incr) then dt_max_tracer_fvm = real(nhe, r8)*(4.0_r8*pi*real(Rearth, r8)/real(4.0_r8*ne*nc, r8))/umax else @@ -653,14 +653,15 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_dyn_vis (hyperviscosity) ; u,v,T,dM) < ',dt_max_hypervis,& 's ',dt_dyn_visco_actual,'s' if (dt_dyn_visco_actual>dt_max_hypervis) write(iulog,*) 'WARNING: dt_dyn_vis theoretically unstable' - write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_se (time-stepping tracers ; q ) < ',dt_max_tracer_se,'s ',& - dt_tracer_se_actual,'s' - if (dt_tracer_se_actual>dt_max_tracer_se) write(iulog,*) 'WARNING: dt_tracer_se theoretically unstable' - write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_vis (hyperviscosity tracers; q ) < ',dt_max_hypervis_tracer,'s',& - dt_tracer_visco_actual,'s' - if (dt_tracer_visco_actual>dt_max_hypervis_tracer) write(iulog,*) 'WARNING: dt_tracer_hypervis theoretically unstable' - - if (ntrac>0) then + if (.not.use_cslam) then + write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_se (time-stepping tracers ; q ) < ',dt_max_tracer_se,'s ',& + dt_tracer_se_actual,'s' + if (dt_tracer_se_actual>dt_max_tracer_se) write(iulog,*) 'WARNING: dt_tracer_se theoretically unstable' + write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_vis (hyperviscosity tracers; q ) < ',dt_max_hypervis_tracer,'s',& + dt_tracer_visco_actual,'s' + if (dt_tracer_visco_actual>dt_max_hypervis_tracer) write(iulog,*) 'WARNING: dt_tracer_hypervis theoretically unstable' + end if + if (use_cslam) then write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_fvm (time-stepping tracers ; q ) < ',dt_max_tracer_fvm,& 's ',dt_tracer_fvm_actual if (dt_tracer_fvm_actual>dt_max_tracer_fvm) write(iulog,*) 'WARNING: dt_tracer_fvm theortically unstable' diff --git a/src/dynamics/se/dycore/hybrid_mod.F90 b/src/dynamics/se/dycore/hybrid_mod.F90 index f167435a..46c5a76f 100644 --- a/src/dynamics/se/dycore/hybrid_mod.F90 +++ b/src/dynamics/se/dycore/hybrid_mod.F90 @@ -7,7 +7,7 @@ module hybrid_mod use parallel_mod , only : parallel_t, copy_par use thread_mod , only : omp_set_num_threads, omp_get_thread_num use thread_mod , only : horz_num_threads, vert_num_threads, tracer_num_threads -use dimensions_mod, only : nlev, qsize, ntrac +use dimensions_mod, only : nlev, qsize, ntrac, use_cslam implicit none private @@ -268,7 +268,7 @@ subroutine init_loop_ranges(nelemd) work_pool_trac(ith+1,2) = end_index end do - if(ntrac>0 .and. ntrac0) then + if ((cubed_sphere_map /= 0) .AND. use_cslam) then if (par%masterproc) then write(iulog, *) subname, 'fvm transport and require equi-angle gnomonic cube sphere mapping.' write(iulog, *) ' Set cubed_sphere_map = 0 or comment it out all together. ' diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index 86da98a6..fb96a7d6 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -309,7 +309,7 @@ end subroutine prim_advance_exp subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsubstep) - use dimensions_mod, only: np, nc, nlev, qsize, ntrac + use dimensions_mod, only: np, nc, nlev, qsize, ntrac, use_cslam use element_mod, only: element_t use control_mod, only: ftype, ftype_conserve use fvm_control_volume_mod, only: fvm_struct @@ -332,7 +332,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu character(len=*), parameter :: subname = 'applyCAMforcing (SE)' - if (ntrac>0) then + if (use_cslam) then allocate(ftmp_fvm(nc,nc,nlev,ntrac,nets:nete), stat=iret) call check_allocate(iret, subname, 'ftmp_fvm(nc,nc,nlev,ntrac,nets:nete)', & file=__FILE__, line=__LINE__) @@ -368,7 +368,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu ! do state-update for tracers and "dribbling" forcing for u,v,T ! dt_local = dt_dribble - if (ntrac>0) then + if (use_cslam) then dt_local_tracer = dt_dribble dt_local_tracer_fvm = dt_phys if (nsubstep.ne.1) then @@ -417,7 +417,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu else ftmp(:,:,:,:,ie) = 0.0_r8 end if - if (ntrac>0.and.dt_local_tracer_fvm>0) then + if (use_cslam.and.dt_local_tracer_fvm>0) then ! ! Repeat for the fvm tracers: fc holds tendency (fc_new-fc_old)/dt_physics ! @@ -441,7 +441,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu end do end do else - if (ntrac>0) ftmp_fvm(:,:,:,:,ie) = 0.0_r8 + if (use_cslam) ftmp_fvm(:,:,:,:,ie) = 0.0_r8 end if @@ -472,13 +472,13 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu dt_local*elem(ie)%derived%FM(:,:,:,:) end if end do - if (ntrac>0) then + if (use_cslam) then call output_qdp_var_dynamics(ftmp_fvm(:,:,:,:,:),nc,ntrac,nets,nete,'PDC') else call output_qdp_var_dynamics(ftmp(:,:,:,:,:),np,qsize,nets,nete,'PDC') end if if (ftype==1.and.nsubstep==1) call calc_tot_energy_dynamics(elem,fvm,nets,nete,np1,np1_qdp,'p2d') - if (ntrac>0) deallocate(ftmp_fvm) + if (use_cslam) deallocate(ftmp_fvm) end subroutine applyCAMforcing @@ -494,7 +494,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, ! use dynconst, only: gravit, cappa, cpair, tref, lapse_rate use dyn_thermo, only: get_dp_ref - use dimensions_mod, only: np, nlev, nc, ntrac, npsq, qsize + use dimensions_mod, only: np, nlev, nc, use_cslam, npsq, qsize use dimensions_mod, only: hypervis_dynamic_ref_state,ksponge_end use dimensions_mod, only: nu_scale_top,nu_lev,kmvis_ref,kmcnd_ref,rho_ref,km_sponge_factor use dimensions_mod, only: kmvisi_ref,kmcndi_ref,rhoi_ref @@ -644,7 +644,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, enddo enddo - if (ntrac>0) then + if (use_cslam) then !OMP_COLLAPSE_SIMD !DIR_VECTOR_ALIGNED do j=1,nc @@ -696,7 +696,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = kbeg - 1 + 2*nlev call edgeVunpack(edge3,vtens(:,:,2,kbeg:kend,ie),kblk,kptr,ie) - if (ntrac>0) then + if (use_cslam) then do k=kbeg,kend temp(:,:,k) = elem(ie)%state%dp3d(:,:,k,nt) / elem(ie)%spheremp ! STATE before DSS corners(0:np+1,0:np+1,k) = 0.0_r8 @@ -706,7 +706,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = kbeg - 1 + 3*nlev call edgeVunpack(edge3,elem(ie)%state%dp3d(:,:,kbeg:kend,nt),kblk,kptr,ie) - if (ntrac>0) then + if (use_cslam) then desc = elem(ie)%desc kptr = kbeg - 1 + 3*nlev @@ -920,7 +920,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, end do end if - if (ntrac>0.and.nu_dp>0) then + if (use_cslam.and.nu_dp>0) then ! ! mass flux for CSLAM due to sponge layer diffusion on dp ! @@ -968,7 +968,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = 2*ksponge_end call edgeVunpack(edgeSponge,vtens(:,:,2,1:ksponge_end,ie),kblk,kptr,ie) - if (ntrac>0.and.nu_dp>0.0_r8) then + if (use_cslam.and.nu_dp>0.0_r8) then do k=1,ksponge_end temp(:,:,k) = elem(ie)%state%dp3d(:,:,k,nt) / elem(ie)%spheremp ! STATE before DSS corners(0:np+1,0:np+1,k) = 0.0_r8 @@ -978,7 +978,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kptr = 3*ksponge_end call edgeVunpack(edgeSponge,elem(ie)%state%dp3d(:,:,1:ksponge_end,nt),kblk,kptr,ie) - if (ntrac>0.and.nu_dp>0.0_r8) then + if (use_cslam.and.nu_dp>0.0_r8) then desc = elem(ie)%desc kptr = 3*ksponge_end @@ -1083,7 +1083,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& use dyn_thermo, only: get_R_dry !SE dycore: - use dimensions_mod, only: np, nc, nlev, ntrac, ksponge_end + use dimensions_mod, only: np, nc, nlev, use_cslam, ksponge_end use hybrid_mod, only: hybrid_t use element_mod, only: element_t use derivative_mod, only: derivative_t, divergence_sphere, gradient_sphere, vorticity_sphere @@ -1349,7 +1349,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& enddo - if (ntrac>0.and.eta_ave_w.ne.0._r8) then + if (use_cslam.and.eta_ave_w.ne.0._r8) then !OMP_COLLAPSE_SIMD !DIR_VECTOR_ALIGNED do j=1,np @@ -1392,7 +1392,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& kptr=nlev call edgeVunpack(edge3, elem(ie)%state%v(:,:,:,:,np1), 2*nlev, kptr, ie) - if (ntrac>0.and.eta_ave_w.ne.0._r8) then + if (use_cslam.and.eta_ave_w.ne.0._r8) then do k=1,nlev stashdp3d(:,:,k) = elem(ie)%state%dp3d(:,:,k,np1)/elem(ie)%spheremp(:,:) end do @@ -1403,7 +1403,7 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& kptr=kptr+2*nlev call edgeVunpack(edge3, elem(ie)%state%dp3d(:,:,:,np1),nlev,kptr,ie) - if (ntrac>0.and.eta_ave_w.ne.0._r8) then + if (use_cslam.and.eta_ave_w.ne.0._r8) then desc = elem(ie)%desc call edgeDGVunpack(edge3, corners, nlev, kptr, ie) @@ -1586,7 +1586,7 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2).or.hist_fld_active(name_out3).or.& hist_fld_active(name_out4).or.hist_fld_active(name_out5).or.hist_fld_active(name_out6)) then - if (ntrac>0) then + if (use_cslam) then ixwv = 1 call cnst_get_ind('CLDLIQ' , ixcldliq, abort=.false.) call cnst_get_ind('CLDICE' , ixcldice, abort=.false.) @@ -1637,7 +1637,7 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf ! ! mass variables are output on CSLAM grid if using CSLAM else GLL grid ! - if (ntrac>0) then + if (use_cslam) then if (ixwv>0) then cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixwv)*fvm(ie)%dp_fvm(1:nc,1:nc,:) call util_function(cdp_fvm,nc,nlev,name_out3,ie) diff --git a/src/dynamics/se/dycore/prim_advection_mod.F90 b/src/dynamics/se/dycore/prim_advection_mod.F90 index 674593a5..8cd327d2 100644 --- a/src/dynamics/se/dycore/prim_advection_mod.F90 +++ b/src/dynamics/se/dycore/prim_advection_mod.F90 @@ -62,7 +62,7 @@ module prim_advection_mod subroutine Prim_Advec_Init1(par, elem) - use dimensions_mod, only: nlev, qsize, nelemd,ntrac + use dimensions_mod, only: nlev, qsize, nelemd,ntrac, use_cslam use parallel_mod, only: parallel_t, boundaryCommMethod use cam_abortutils, only: check_allocate type(parallel_t) :: par @@ -82,7 +82,7 @@ subroutine Prim_Advec_Init1(par, elem) ! ! Set the number of threads used in the subroutine Prim_Advec_tracers_remap() ! - if (ntrac>0) then + if (use_cslam) then advec_remap_num_threads = 1 else advec_remap_num_threads = tracer_num_threads @@ -956,7 +956,7 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) use vertremap_mod, only: remap1 use hybrid_mod, only: hybrid_t, config_thread_region,get_loop_ranges, PrintHybrid use fvm_control_volume_mod, only: fvm_struct - use dimensions_mod, only: ntrac + use dimensions_mod, only: use_cslam, ntrac use dimensions_mod, only: kord_tr,kord_tr_cslam use cam_logfile, only: iulog use dynconst, only: pi @@ -1086,7 +1086,7 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) call remap1(elem(ie)%state%v(:,:,2,:,np1),np,1,1,1,dp_star_moist,dp_moist,ptop,-1,.false.,kord_uvT) enddo - if (ntrac>0) then + if (use_cslam) then ! ! vertical remapping of CSLAM tracers ! diff --git a/src/dynamics/se/dycore/prim_driver_mod.F90 b/src/dynamics/se/dycore/prim_driver_mod.F90 index fdee231f..f5715cea 100644 --- a/src/dynamics/se/dycore/prim_driver_mod.F90 +++ b/src/dynamics/se/dycore/prim_driver_mod.F90 @@ -190,7 +190,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst use thread_mod, only: omp_get_thread_num use perf_mod , only: t_startf, t_stopf use fvm_mod , only: fill_halo_fvm, ghostBufQnhc_h - use dimensions_mod, only: ntrac,fv_nphys, ksponge_end + use dimensions_mod, only: use_cslam,fv_nphys type (element_t) , intent(inout) :: elem(:) type(fvm_struct), intent(inout) :: fvm(:) @@ -341,7 +341,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst call prim_printstate(elem, tl, hybrid,nets,nete, fvm, omega_cn) end if - if (ntrac>0.and.nsubstep==nsplit.and.nc.ne.fv_nphys) then + if (use_cslam.and.nsubstep==nsplit.and.nc.ne.fv_nphys) then ! ! fill the fvm halo for mapping in d_p_coupling if ! physics grid resolution is different than fvm resolution @@ -377,7 +377,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) use prim_advection_mod, only: prim_advec_tracers_remap, prim_advec_tracers_fvm, deriv use derivative_mod, only: subcell_integration use hybrid_mod, only: set_region_num_threads, config_thread_region, get_loop_ranges - use dimensions_mod, only: ntrac,fvm_supercycling,fvm_supercycling_jet + use dimensions_mod, only: use_cslam,fvm_supercycling,fvm_supercycling_jet use dimensions_mod, only: kmin_jet, kmax_jet use fvm_mod, only: ghostBufQnhc_vh,ghostBufQ1_vh, ghostBufFlux_vh use fvm_mod, only: ghostBufQ1_h,ghostBufQnhcJet_h, ghostBufFluxJet_h @@ -456,7 +456,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) ! defer final timelevel update until after Q update. enddo #ifdef HOMME_TEST_SUB_ELEMENT_MASS_FLUX - if (ntrac>0.and.rstep==1) then + if (use_cslam.and.rstep==1) then do ie=nets,nete do k=1,nlev tempdp3d = elem(ie)%state%dp3d(:,:,k,tl%np1) - & @@ -500,10 +500,10 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) ! special case in CAM: if CSLAM tracers are turned on , qsize=1 but this tracer should ! not be advected. This will be cleaned up when the physgrid is merged into CAM trunk ! Currently advecting all species - if (qsize > 0) then + if (qsize > 0) then !xxx change when not double advecting call t_startf('prim_advec_tracers_remap') - if(ntrac>0) then + if(use_cslam) then ! Deactivate threading in the tracer dimension if this is a CSLAM run region_num_threads = 1 else @@ -511,7 +511,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) endif call omp_set_nested(.true.) !$OMP PARALLEL NUM_THREADS(region_num_threads), DEFAULT(SHARED), PRIVATE(hybridnew) - if(ntrac>0) then + if(use_cslam) then ! Deactivate threading in the tracer dimension if this is a CSLAM run hybridnew = config_thread_region(hybrid,'serial') else @@ -525,7 +525,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) ! ! only run fvm transport every fvm_supercycling rstep ! - if (ntrac>0) then + if (use_cslam) then ! ! FVM transport ! diff --git a/src/dynamics/se/dycore/prim_state_mod.F90 b/src/dynamics/se/dycore/prim_state_mod.F90 index 6395c169..28ca9cdc 100644 --- a/src/dynamics/se/dycore/prim_state_mod.F90 +++ b/src/dynamics/se/dycore/prim_state_mod.F90 @@ -19,7 +19,7 @@ module prim_state_mod CONTAINS subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) - use dimensions_mod, only: ntrac + use dimensions_mod, only: use_cslam !Un-comment once constitutents are enabled -JN: ! use constituents, only: cnst_name use string_utils, only: to_str !Remove once constituents are enabled -JN @@ -115,7 +115,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) n0=tl%n0 call TimeLevel_Qdp( tl, qsplit, n0_qdp) ! moist surface pressure - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete moist_ps_fvm(:,:,ie)=SUM(fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3) do q=dry_air_species_num+1,thermodynamic_active_species_num @@ -141,7 +141,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) do ie=nets,nete da_gll(:,:,ie) = elem(ie)%mp(:,:)*elem(ie)%metdet(:,:) enddo - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete da_fvm(:,:,ie) = fvm(ie)%area_sphere(:,:) enddo @@ -158,7 +158,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) varname(3) = 'T ' varname(4) = 'OMEGA ' varname(5) = 'OMEGA CN ' - if (ntrac>0) then + if (use_cslam) then varname(6) = 'PSDRY(fvm)' varname(7) = 'PS(fvm) ' varname(8) = 'PSDRY(gll)' @@ -188,7 +188,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) min_local(ie,5) = 0.0_r8 max_local(ie,5) = 0.0_r8 end if - if (ntrac>0) then + if (use_cslam) then min_local(ie,6) = MINVAL(SUM(fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3)) max_local(ie,6) = MAXVAL(SUM(fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3)) min_local(ie,7) = MINVAL(moist_ps_fvm(:,:,ie)) @@ -227,7 +227,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) max_local(ie,nm2+1) = MAXVAL(elem(ie)%derived%FT(:,:,:)) min_local(ie,nm2+2) = MINVAL(elem(ie)%derived%FM(:,:,:,:)) max_local(ie,nm2+2) = MAXVAL(elem(ie)%derived%FM(:,:,:,:)) - if (ntrac>0) then + if (use_cslam) then do q=1,statediag_numtrac !Un-comment once constitutents are enabled -JN: !varname(nm2+2+q) = TRIM('F'//TRIM(cnst_name(q))) @@ -265,7 +265,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) ! tracers ! mass = -1.0_r8 - if (ntrac>0) then + if (use_cslam) then do ie=nets,nete do q=1,statediag_numtrac tmp_fvm(:,:,q,ie) = SUM(fvm(ie)%c(1:nc,1:nc,:,q)*fvm(ie)%dp_fvm(1:nc,1:nc,:),DIM=3) @@ -307,7 +307,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) if (tl%nstep==0.or..not. initial_run) then mass_chg(:) = 0.0_R8 elem(nets)%derived%mass(nm+1:nm+statediag_numtrac) = mass(nm+1:nm+statediag_numtrac) - if (ntrac>0) then + if (use_cslam) then elem(nets)%derived%mass(6:9) = mass(6:9) else elem(nets)%derived%mass(6:7) = mass(6:7) diff --git a/src/dynamics/se/dycore/time_mod.F90 b/src/dynamics/se/dycore/se_dyn_time_mod.F90 similarity index 98% rename from src/dynamics/se/dycore/time_mod.F90 rename to src/dynamics/se/dycore/se_dyn_time_mod.F90 index fdd68af0..df0a7b53 100644 --- a/src/dynamics/se/dycore/time_mod.F90 +++ b/src/dynamics/se/dycore/se_dyn_time_mod.F90 @@ -80,13 +80,14 @@ end subroutine TimeLevel_init_specific !locations for nm1 and n0 for Qdp - because !it only has 2 levels for storage subroutine TimeLevel_Qdp(tl, qsplit, n0, np1) + use dimensions_mod, only: use_cslam type (TimeLevel_t) :: tl integer, intent(in) :: qsplit integer, intent(inout) :: n0 integer, intent(inout), optional :: np1 integer :: i_temp - +!xxxx change when not double advecting i_temp = tl%nstep/qsplit if (mod(i_temp,2) ==0) then diff --git a/src/dynamics/se/dycore/viscosity_mod.F90 b/src/dynamics/se/dycore/viscosity_mod.F90 index b29e48a1..83be78b5 100644 --- a/src/dynamics/se/dycore/viscosity_mod.F90 +++ b/src/dynamics/se/dycore/viscosity_mod.F90 @@ -53,7 +53,7 @@ module viscosity_mod subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid,nt,nets,nete,kbeg,kend,& dp3d_ref,T_ref) use derivative_mod, only : subcell_Laplace_fluxes - use dimensions_mod, only : ntrac, nu_div_lev,nu_lev + use dimensions_mod, only : use_cslam, nu_div_lev,nu_lev !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! compute weak biharmonic operator @@ -83,7 +83,7 @@ subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid, kblk = kend - kbeg + 1 - if (ntrac>0) dpflux = 0 + if (use_cslam) dpflux = 0 !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) !so tensor is only used on second call to laplace_sphere_wk var_coef1 = .true. @@ -155,7 +155,7 @@ subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid, kptr = kbeg - 1 + 3*nlev call edgeVunpack(edge3,dptens(:,:,kbeg:kend,ie),kblk,kptr,ie) - if (ntrac>0) then + if (use_cslam) then do k=1,nlev !CLEAN tmp(:,:)= rspheremv(:,:)*dptens(:,:,k,ie) tmp(:,:)= elem(ie)%rspheremp(:,:)*dptens(:,:,k,ie) diff --git a/src/dynamics/se/dyn_comp.F90 b/src/dynamics/se/dyn_comp.F90 index 77ee5ebf..8d13866e 100644 --- a/src/dynamics/se/dyn_comp.F90 +++ b/src/dynamics/se/dyn_comp.F90 @@ -40,7 +40,7 @@ module dyn_comp use parallel_mod, only: par use hybrid_mod, only: hybrid_t use dimensions_mod, only: nelemd, nlev, np, npsq, ntrac, nc, fv_nphys, & - qsize + qsize, use_cslam use element_mod, only: element_t, elem_state_t use fvm_control_volume_mod, only: fvm_struct use time_mod, only: nsplit @@ -351,7 +351,15 @@ subroutine dyn_readnl(NLFileName) kmax_jet = se_kmax_jet variable_nsplit = .false. molecular_diff = se_molecular_diff - + !xxx to merge pgf_formulation = se_pgf_formulation + !xxx to merge dribble_in_rsplit_loop = se_dribble_in_rsplit_loop + if (fv_nphys > 0) then + ! Use finite volume physics grid and CSLAM for tracer advection + use_cslam = .true. + else + ! Use GLL grid for physics and tracer advection + use_cslam = .false. + end if if (rsplit < 1) then call endrun('dyn_readnl: rsplit must be > 0') end if @@ -446,7 +454,7 @@ subroutine dyn_readnl(NLFileName) end if end if - if (fv_nphys > 0) then + if (use_cslam) then write(iulog, '(a)') 'dyn_readnl: physics will run on FVM points; advection by CSLAM' write(iulog,'(a,i0)') 'dyn_readnl: se_fv_nphys = ', fv_nphys else @@ -629,7 +637,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) file=__FILE__, line=__LINE__) kord_tr(:) = vert_remap_tracer_alg - if (ntrac>0) then + if (use_cslam) then allocate(kord_tr_cslam(ntrac), stat=iret) call check_allocate(iret, subname, 'kord_tr_cslam(ntrac)', & file=__FILE__, line=__LINE__) @@ -649,7 +657,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) ! CSLAM tracers are always indexed as in physics ! of no CSLAM then SE tracers are always indexed as in physics ! - if (ntrac>0) then + if (use_cslam) then ! ! note that in this case qsize = thermodynamic_active_species_num ! @@ -672,7 +680,36 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) end if end do - +#ifdef energy_budget_code + do m=1,thermodynamic_active_species_liq_num + if (use_cslam) then + do mfound=1,qsize + if (TRIM(cnst_name(thermodynamic_active_species_liq_idx(m)))==TRIM(cnst_name_gll(mfound))) then + thermodynamic_active_species_liq_idx_dycore(m) = mfound + end if + end do + else + thermodynamic_active_species_liq_idx_dycore(m) = thermodynamic_active_species_liq_idx(m) + end if + if (masterproc) then + write(iulog,*) sub//": m,thermodynamic_active_species_idx_liq_dycore: ",m,thermodynamic_active_species_liq_idx_dycore(m) + end if + end do + do m=1,thermodynamic_active_species_ice_num + if (use_cslam) then + do mfound=1,qsize + if (TRIM(cnst_name(thermodynamic_active_species_ice_idx(m)))==TRIM(cnst_name_gll(mfound))) then + thermodynamic_active_species_ice_idx_dycore(m) = mfound + end if + end do + else + thermodynamic_active_species_ice_idx_dycore(m) = thermodynamic_active_species_ice_idx(m) + end if + if (masterproc) then + write(iulog,*) sub//": m,thermodynamic_active_species_idx_ice_dycore: ",m,thermodynamic_active_species_ice_idx_dycore(m) + end if + end do +#endif ! ! Initialize the import/export objects ! @@ -796,7 +833,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) call addfld ('FT', (/ 'lev' /), 'A', 'K/s', 'Temperature forcing term on GLL grid',gridname='GLL') ! Tracer forcing on fvm (CSLAM) grid and internal CSLAM pressure fields - if (ntrac>0) then + if (use_cslam) then do m = 1, ntrac call addfld (trim(const_name(m))//'_fvm', (/ 'lev' /), 'I', 'kg/kg', & trim(const_longname(m)), gridname='FVM') @@ -850,7 +887,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) ! ! add dynamical core tracer tendency output ! - if (ntrac>0) then + if (use_cslam) then do m = 1, num_advected call addfld(tottnam(m),(/ 'lev' /),'A','kg/kg/s',trim(const_name(m))//' horz + vert', & gridname='FVM') @@ -993,6 +1030,7 @@ subroutine dyn_run(dyn_state) #endif ! convert elem(ie)%derived%fq to mass tendency +!xxx for cslam only merge if (.not.use_cslam) then do ie = nets, nete do m = 1, qsize do k = 1, nlev @@ -1005,7 +1043,8 @@ subroutine dyn_run(dyn_state) end do end do end do - + !xxx end if +!xxx for cslam only merge if (ftype_conserve>0.and..not.use_cslam) then if (ftype_conserve>0) then do ie = nets, nete do k=1,nlev @@ -1023,7 +1062,7 @@ subroutine dyn_run(dyn_state) end do end if - if (ntrac > 0) then + if (use_cslam) then do ie = nets, nete do m = 1, ntrac do k = 1, nlev @@ -1697,7 +1736,7 @@ subroutine read_inidat(dyn_in) ! if CSLAM active then we only advect water vapor and condensate ! loading tracers in state%qdp - if (ntrac > 0) then + if (use_cslam) then do ie = 1, nelemd do nq = 1, thermodynamic_active_species_num m_cnst = thermodynamic_active_species_idx(nq) @@ -1728,7 +1767,7 @@ subroutine read_inidat(dyn_in) ! interpolate fvm tracers and fvm pressure variables - if (ntrac > 0) then + if (use_cslam) then if (par%masterproc) then write(iulog,*) 'Initializing dp_fvm from spectral element dp' end if @@ -1876,7 +1915,7 @@ subroutine set_phis(dyn_in) phis_tmp = 0.0_r8 - if (fv_nphys > 0) then + if (use_cslam) then allocate(phis_phys_tmp(fv_nphys**2,nelemd), stat=ierr) call check_allocate(ierr, subname, 'phis_phys_tmp(fv_nphys**2,nelemd)', & file=__FILE__, line=__LINE__) @@ -1932,6 +1971,7 @@ subroutine set_phis(dyn_in) end if fieldname = 'PHIS' +!xxx GLL topo merge fieldname_gll = 'PHIS_gll' if (dyn_field_exists(fh_topo, trim(fieldname))) then if (fv_nphys == 0) then call read_dyn_var(fieldname, fh_topo, 'ncol', phis_tmp) @@ -2380,7 +2420,7 @@ subroutine write_dyn_vars(dyn_out) integer :: ie, m !---------------------------------------------------------------------------- - if (ntrac > 0) then + if (use_cslam) then do ie = 1, nelemd call outfld('dp_fvm', RESHAPE(dyn_out%fvm(ie)%dp_fvm(1:nc,1:nc,:), & (/nc*nc,nlev/)), nc*nc, ie) diff --git a/src/dynamics/se/dyn_grid.F90 b/src/dynamics/se/dyn_grid.F90 index 51fdb2da..bf61ff37 100644 --- a/src/dynamics/se/dyn_grid.F90 +++ b/src/dynamics/se/dyn_grid.F90 @@ -42,7 +42,7 @@ module dyn_grid !SE dycore: use dimensions_mod, only: globaluniquecols, nelem, nelemd, nelemdmax, & - ne, np, npsq, fv_nphys, nlev, nlevp, nc, ntrac + ne, np, npsq, fv_nphys, nlev, use_cslam, nlevp, nc use element_mod, only: element_t use fvm_control_volume_mod, only: fvm_struct use hybvcoord_mod, only: hvcoord_t @@ -248,7 +248,7 @@ subroutine model_grid_init() if (iam < par%nprocs) then call prim_init1(elem, fvm, par, TimeLevel) - if (fv_nphys > 0) then + if (use_cslam) then call dp_init(elem, fvm) end if @@ -938,7 +938,7 @@ subroutine define_cam_grids() ! Create FVM grid object for CSLAM !--------------------------------- - if (ntrac > 0) then + if (use_cslam) then ncols_fvm = nc * nc * nelemd ngcols_fvm = nc * nc * nelem_d diff --git a/src/dynamics/se/test_fvm_mapping.F90 b/src/dynamics/se/test_fvm_mapping.F90 index 1fada43a..308573d9 100644 --- a/src/dynamics/se/test_fvm_mapping.F90 +++ b/src/dynamics/se/test_fvm_mapping.F90 @@ -5,7 +5,7 @@ module test_fvm_mapping !SE dycore: use fvm_control_volume_mod, only: fvm_struct - use dimensions_mod, only: np, nelemd, nlev, npsq, ntrac + use dimensions_mod, only: np, nelemd, nlev, npsq, ntrac, use_cslam use element_mod, only: element_t implicit none private @@ -252,7 +252,7 @@ subroutine test_mapping_output_mapped_tendencies(fvm,elem,nets,nete,tl_f,tl_qdp) name = 'p2d_'//trim(const_name(m_cnst))//'_err_gll' call outfld(TRIM(name), RESHAPE(elem(ie)%derived%fq(:,:,:,nq),(/npsq,nlev/)), npsq, ie) end do - if (ntrac>0) then + if (use_cslam) then do nq=ntrac,ntrac m_cnst = nq name = 'p2f_'//trim(const_name(m_cnst))//'_fvm' @@ -390,7 +390,7 @@ subroutine test_mapping_output_phys_state(phys_state,fvm) call outfld('d2p_scalar', phys_state(lchnk)%omega(1:pcols,1:pver), pcols, lchnk) call outfld('d2p_u', phys_state(lchnk)%U(1:pcols,1:pver), pcols, lchnk) call outfld('d2p_v', phys_state(lchnk)%V(1:pcols,1:pver), pcols, lchnk) - if (ntrac>0) then + if (use_cslam) then do nq=ntrac,ntrac m_cnst = nq name = 'f2p_'//trim(const_name(m_cnst)) From e6edd621c58240a1cd897bf0ed8e0eb483d80a51 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Tue, 17 Dec 2024 11:57:01 -0700 Subject: [PATCH 08/12] merge fvm_reconstruction_mod --- src/dynamics/se/dycore/fvm_reconstruction_mod.F90 | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/dynamics/se/dycore/fvm_reconstruction_mod.F90 b/src/dynamics/se/dycore/fvm_reconstruction_mod.F90 index b7310ad4..b4708dfd 100644 --- a/src/dynamics/se/dycore/fvm_reconstruction_mod.F90 +++ b/src/dynamics/se/dycore/fvm_reconstruction_mod.F90 @@ -105,7 +105,6 @@ subroutine reconstruction(fcube,nlev_in,k_in,recons,irecons,llimiter,ntrac_in,& if(FVM_TIMERS) call t_startf('FVM:reconstruction:part#1') if (nhe>0) then do itr=1,ntrac_in - ! f=-9e9_r8 call extend_panel_interpolate(nc,nhc,nhr,nht,ns,nh,& fcube(:,:,k_in,itr),cubeboundary,halo_interp_weight,ibase,f(:,:,1),f(:,:,2:3)) call get_gradients(f(:,:,:),jx,jy,irecons,recons(:,:,:,itr),& @@ -113,8 +112,6 @@ subroutine reconstruction(fcube,nlev_in,k_in,recons,irecons,llimiter,ntrac_in,& end do else do itr=1,ntrac_in - ! f=-9e9_r8!to avoid floating point exception for uninitialized variables - ! !in non-existent cells (corners of cube) call extend_panel_interpolate(nc,nhc,nhr,nht,ns,nh,& fcube(:,:,k_in,itr),cubeboundary,halo_interp_weight,ibase,f(:,:,1)) call get_gradients(f(:,:,:),jx,jy,irecons,recons(:,:,:,itr),& From 8af4d32bda382980374888313438c58a5902fdc5 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Thu, 26 Dec 2024 16:23:28 -0700 Subject: [PATCH 09/12] first extensive merge with cam_development --- cime_config/namelist_definition_cam.xml | 22 +- src/control/cam_initfiles.F90 | 18 +- src/dynamics/se/dp_coupling.F90 | 65 +- src/dynamics/se/dycore/dimensions_mod.F90 | 39 +- .../se/dycore/fvm_consistent_se_cslam.F90 | 2 +- src/dynamics/se/dycore/fvm_mapping.F90 | 263 ++++-- src/dynamics/se/dycore/fvm_mod.F90 | 14 +- src/dynamics/se/dycore/global_norms_mod.F90 | 231 +++-- src/dynamics/se/dycore/prim_advance_mod.F90 | 840 ++++++------------ src/dynamics/se/dycore/prim_advection_mod.F90 | 39 +- src/dynamics/se/dycore/prim_driver_mod.F90 | 224 ++++- src/dynamics/se/dycore/prim_init.F90 | 2 +- src/dynamics/se/dycore/prim_state_mod.F90 | 8 +- src/dynamics/se/dycore/se_dyn_time_mod.F90 | 4 +- src/dynamics/se/dycore/viscosity_mod.F90 | 196 ++-- src/dynamics/se/dyn_comp.F90 | 467 ++++++---- src/dynamics/se/dyn_grid.F90 | 47 +- .../se/namelist_definition_se_dycore.xml | 97 +- src/dynamics/se/stepon.F90 | 111 ++- src/dynamics/utils/dynconst.F90 | 5 +- 20 files changed, 1489 insertions(+), 1205 deletions(-) diff --git a/cime_config/namelist_definition_cam.xml b/cime_config/namelist_definition_cam.xml index fce70728..e2f2a090 100644 --- a/cime_config/namelist_definition_cam.xml +++ b/cime_config/namelist_definition_cam.xml @@ -189,7 +189,27 @@ UNSET_PATH - + + real + initial_conditions + cam_initfiles_nl + + Specify whether and how to perform + dry surface pressure scaling. If less than or equal to 0.0, + do not perform scaling. If greater than 0.0, perform scaling to scale_dry_air_mass + value (in Pa) as the average dry surface pressure target. + Default: set by build-namelist. + + + 0.0D0 + 101080.0D0 + + 98288.0D0 + 98288.0D0 + 98288.0D0 + 98288.0D0 + + diff --git a/src/control/cam_initfiles.F90 b/src/control/cam_initfiles.F90 index bea73de7..32c06b52 100644 --- a/src/control/cam_initfiles.F90 +++ b/src/control/cam_initfiles.F90 @@ -44,6 +44,8 @@ module cam_initfiles ! cam_branch_file: Filepath of primary restart file for a branch run character(len=cl) :: cam_branch_file = ' ' + real(r8), public, protected :: scale_dry_air_mass = 0.0_r8 ! Toggle and target avg air mass + ! rest_pfile: The restart pointer file contains name of most recently ! written primary restart file. ! The contents of this file are updated by cam_write_restart @@ -89,7 +91,7 @@ subroutine cam_initfiles_readnl(nlfile) character(len=*), parameter :: subname = 'cam_initfiles_readnl' namelist /cam_initfiles_nl/ ncdata, bnd_topo, pertlim, cam_branch_file, & - unset_path_str + unset_path_str, scale_dry_air_mass !------------------------------------------------------------------------ if (masterproc) then @@ -121,7 +123,11 @@ subroutine cam_initfiles_readnl(nlfile) mstrid, mpicom, ierr) if (ierr /= 0) then call endrun(subname//": ERROR: mpi_bcast: cam_branch_file") - end if + end if + call mpi_bcast(scale_dry_air_mass, 1, mpi_real8, mstrid, mpicom, ierr) + if (ierr /= 0) then + call endrun(subname//": ERROR: mpi_bcast: scale_dry_air_mass") + endif call mpi_bcast(unset_path_str, len(unset_path_str), mpi_character, & mstrid, mpicom, ierr) if (ierr /= 0) then @@ -198,7 +204,13 @@ subroutine cam_initfiles_readnl(nlfile) write(iulog,*) ' Maximum abs value of scale factor used to ', & 'perturb initial conditions, pertlim= ', pertlim - + if (scale_dry_air_mass > 0) then + write(iulog,*) & + ' Initial condition dry mass will be scaled to: ',scale_dry_air_mass,' Pa' + else + write(iulog,*) & + ' Initial condition dry mass will not be scaled.' + end if end if end subroutine cam_initfiles_readnl diff --git a/src/dynamics/se/dp_coupling.F90 b/src/dynamics/se/dp_coupling.F90 index 9eb8da2b..4a834a89 100644 --- a/src/dynamics/se/dp_coupling.F90 +++ b/src/dynamics/se/dp_coupling.F90 @@ -61,7 +61,7 @@ subroutine d_p_coupling(cam_runtime_opts, phys_state, phys_tend, dyn_out) !SE dycore: use fvm_mapping, only: dyn2phys_vector, dyn2phys_all_vars - use time_mod, only: timelevel_qdp + use se_dyn_time_mod, only: timelevel_qdp use control_mod, only: qsplit ! arguments @@ -521,15 +521,15 @@ subroutine p_d_coupling(cam_runtime_opts, phys_state, phys_tend, dyn_in, tl_f, t call edgeVpack(edgebuf, dyn_in%elem(ie)%derived%FM(:,:,:,:), 2*nlev, kptr, ie) kptr = kptr + 2*nlev call edgeVpack(edgebuf, dyn_in%elem(ie)%derived%FT(:,:,:), nlev, kptr, ie) - kptr = kptr + nlev -!xxx if (.not. use_cslam) then -!xxx ! -!xxx ! if using CSLAM qdp is being overwritten with CSLAM values in the dynamics -!xxx ! so no need to do boundary exchange of tracer tendency on GLL grid here -!xxx ! - call edgeVpack(edgebuf, dyn_in%elem(ie)%derived%FQ(:,:,:,:), nlev*qsize, kptr, ie) -!xxx end of - end do + if (.not. use_cslam) then + ! + ! if using CSLAM qdp is being overwritten with CSLAM values in the dynamics + ! so no need to do boundary exchange of tracer tendency on GLL grid here + ! + kptr = kptr + nlev + call edgeVpack(edgebuf, dyn_in%elem(ie)%derived%FQ(:,:,:,:), nlev*qsize, kptr, ie) + end if + end do if (iam < par%nprocs) then call bndry_exchange(par, edgebuf, location='p_d_coupling') @@ -540,10 +540,10 @@ subroutine p_d_coupling(cam_runtime_opts, phys_state, phys_tend, dyn_in, tl_f, t call edgeVunpack(edgebuf, dyn_in%elem(ie)%derived%FM(:,:,:,:), 2*nlev, kptr, ie) kptr = kptr + 2*nlev call edgeVunpack(edgebuf, dyn_in%elem(ie)%derived%FT(:,:,:), nlev, kptr, ie) -!xxx if (.not. use_cslam) then - kptr = kptr + nlev - call edgeVunpack(edgebuf, dyn_in%elem(ie)%derived%FQ(:,:,:,:), nlev*qsize, kptr, ie) -!xxx end if + if (.not. use_cslam) then + kptr = kptr + nlev + call edgeVunpack(edgebuf, dyn_in%elem(ie)%derived%FQ(:,:,:,:), nlev*qsize, kptr, ie) + end if if (fv_nphys > 0) then do k = 1, nlev dyn_in%elem(ie)%derived%FM(:,:,1,k) = & @@ -756,6 +756,7 @@ subroutine derived_phys_dry(cam_runtime_opts, phys_state, phys_tend) ! Ensure O2 + O + H (N2) mmr greater than one. ! Check for unusually large H2 values and set to lower value. !------------------------------------------------------------ + !xxx this code is NOT in cam_development? if (cam_runtime_opts%waccmx_option() == 'ionosphere' .or. & cam_runtime_opts%waccmx_option() == 'neutral') then @@ -822,40 +823,4 @@ subroutine derived_phys_dry(cam_runtime_opts, phys_state, phys_tend) #endif end subroutine derived_phys_dry - -!========================================================================================= - -subroutine thermodynamic_consistency(phys_state, const_data_ptr, phys_tend, ncols, pver) - ! - ! Adjust the physics temperature tendency for thermal energy consistency with the - ! dynamics. - ! Note: mixing ratios are assumed to be dry. - ! - use physconst, only: cpair - use air_composition, only: get_cp - - type(physics_state), intent(in) :: phys_state - real(kind_phys), pointer :: const_data_ptr(:,:,:) - type(physics_tend ), intent(inout) :: phys_tend - integer, intent(in) :: ncols, pver - - real(kind_phys) :: inv_cp(ncols,pver) - !---------------------------------------------------------------------------- - -!xxx if (lcp_moist.and.phys_dyn_cp==1) then lcp_moist removed - ! - ! scale temperature tendency so that thermal energy increment from physics - ! matches SE (not taking into account dme adjust) - ! - ! note that if lcp_moist=.false. then there is thermal energy increment - ! consistency (not taking into account dme adjust) - ! - call get_cp(const_data_ptr(1:ncols,1:pver,1:num_advected),.true.,inv_cp) - - phys_tend%dTdt_total(1:ncols,1:pver) = phys_tend%dTdt_total(1:ncols,1:pver)*cpair*inv_cp -!xxx end if -end subroutine thermodynamic_consistency - -!========================================================================================= - end module dp_coupling diff --git a/src/dynamics/se/dycore/dimensions_mod.F90 b/src/dynamics/se/dycore/dimensions_mod.F90 index 3c393a42..58a85093 100644 --- a/src/dynamics/se/dycore/dimensions_mod.F90 +++ b/src/dynamics/se/dycore/dimensions_mod.F90 @@ -1,5 +1,6 @@ module dimensions_mod use shr_kind_mod, only: r8=>shr_kind_r8 + use air_composition, only: thermodynamic_active_species_num implicit none private @@ -29,10 +30,6 @@ module dimensions_mod integer, public, protected :: ntrac = 0 !FVM tracer dimension size integer, public :: qsize = 0 !qsize is set in dyn_comp ! - ! hyperviscosity is applied on approximate pressure levels - ! Similar to CAM-EUL; see CAM5 scietific documentation (Note TN-486), equation (3.09), page 58. - ! - logical, public :: hypervis_dynamic_ref_state = .false. ! fvm dimensions: logical, public :: lprint!for debugging integer, parameter, public :: ngpc=3 !number of Gausspoints for the fvm integral approximation !phl change from 4 @@ -56,19 +53,15 @@ module dimensions_mod integer, allocatable, public :: kord_tr(:), kord_tr_cslam(:) real(r8), allocatable, public :: nu_scale_top(:) ! scaling of del2 viscosity in sponge layer (initialized in dyn_comp) - real(r8), allocatable, public :: nu_lev(:) - real(r8), allocatable, public :: otau(:) - - integer, public :: ksponge_end ! sponge is active k=1,ksponge_end - real (r8), allocatable, public :: nu_div_lev(:) ! scaling of viscosity in sponge layer + real(r8), allocatable, public :: nu_lev(:) ! level dependent del4 (u,v) damping + real(r8), allocatable, public :: nu_t_lev(:) ! level depedendet del4 T damping + integer, public :: ksponge_end ! sponge is active k=1,ksponge_end + real(r8), allocatable, public :: nu_div_lev(:) ! scaling of viscosity in sponge layer real(r8), allocatable, public :: kmvis_ref(:) !reference profiles for molecular diffusion real(r8), allocatable, public :: kmcnd_ref(:) !reference profiles for molecular diffusion real(r8), allocatable, public :: rho_ref(:) !reference profiles for rho real(r8), allocatable, public :: km_sponge_factor(:) !scaling for molecular diffusion (when used as sponge) - real(r8), allocatable, public :: kmvisi_ref(:) !reference profiles for molecular diffusion - real(r8), allocatable, public :: kmcndi_ref(:) !reference profiles for molecular diffusion - real(r8), allocatable, public :: rhoi_ref(:) !reference profiles for rho integer, public :: nhc_phys integer, public :: nhe_phys @@ -123,13 +116,15 @@ subroutine dimensions_mod_init() ! Set tracer dimension variables: if (fv_nphys > 0) then - ! Use CSLAM for tracer advection - qsize_d = 10 ! SE tracers (currently SE supports 10 condensate loading tracers) + ! Use CSLAM for tracer advection + qsize_d = thermodynamic_active_species_num ntrac = num_advected + use_cslam = .true. else ! Use GLL for tracer advection qsize_d = num_advected ntrac = 0 ! No fvm tracers if CSLAM is off + use_cslam = .false. end if ! Set grid dimension variables: @@ -151,8 +146,8 @@ subroutine dimensions_mod_init() call check_allocate(iret, subname, 'nu_lev(nlev)', & file=__FILE__, line=__LINE__) - allocate(otau(nlev), stat=iret) - call check_allocate(iret, subname, 'otau(nlev)', & + allocate(nu_t_lev(nlev), stat=iret) + call check_allocate(iret, subname, 'nu_t_lev(nlev)', & file=__FILE__, line=__LINE__) allocate(nu_div_lev(nlev), stat=iret) @@ -175,18 +170,6 @@ subroutine dimensions_mod_init() call check_allocate(iret, subname, 'km_sponge_factor(nlev)', & file=__FILE__, line=__LINE__) - allocate(kmvisi_ref(nlevp), stat=iret) - call check_allocate(iret, subname, 'kmvisi_ref(nlevp)', & - file=__FILE__, line=__LINE__) - - allocate(kmcndi_ref(nlevp), stat=iret) - call check_allocate(iret, subname, 'kmcndi_ref(nlevp)', & - file=__FILE__, line=__LINE__) - - allocate(rhoi_ref(nlevp), stat=iret) - call check_allocate(iret, subname, 'rhoi_ref(nlevp)', & - file=__FILE__, line=__LINE__) - end subroutine dimensions_mod_init !============================================================================== diff --git a/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 b/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 index 9cec35f9..221fd197 100644 --- a/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 +++ b/src/dynamics/se/dycore/fvm_consistent_se_cslam.F90 @@ -6,7 +6,7 @@ module fvm_consistent_se_cslam use cam_abortutils, only: endrun use cam_logfile, only: iulog - use time_mod, only: timelevel_t + use se_dyn_time_mod, only: timelevel_t use element_mod, only: element_t use fvm_control_volume_mod, only: fvm_struct use hybrid_mod, only: hybrid_t, config_thread_region, get_loop_ranges, threadOwnsVertLevel diff --git a/src/dynamics/se/dycore/fvm_mapping.F90 b/src/dynamics/se/dycore/fvm_mapping.F90 index 7a4fb2bb..581440d8 100644 --- a/src/dynamics/se/dycore/fvm_mapping.F90 +++ b/src/dynamics/se/dycore/fvm_mapping.F90 @@ -25,7 +25,7 @@ module fvm_mapping private public :: phys2dyn_forcings_fvm, dyn2phys, dyn2phys_vector, dyn2phys_all_vars,dyn2fvm_mass_vars - public :: phys2dyn,fvm2dyn,dyn2fvm + public :: phys2dyn,fvm2dyn,dyn2fvm,cslam2gll save integer :: save_max_overlap real(kind=r8), allocatable, dimension(:,:,:,:,:) :: save_air_mass_overlap @@ -35,6 +35,12 @@ module fvm_mapping real(kind=r8), allocatable, dimension(:,:,:,:) :: save_overlap_area integer , allocatable, dimension(:,:,:,:,:) :: save_overlap_idx integer , allocatable, dimension(:,:,:,:) :: save_num_overlap + + interface fvm2dyn + module procedure fvm2dynt1 + module procedure fvm2dyntn + end interface fvm2dyn + contains ! ! map all mass variables from gll to fvm @@ -53,8 +59,7 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ integer :: ie,i,j,k,m_cnst,nq integer :: iret - real (kind=r8), dimension(:,:,:,:,:) , allocatable :: fld_phys, fld_gll, fld_fvm - real (kind=r8), allocatable, dimension(:,:,:,:,:) :: qgll + real (kind=r8), dimension(:,:,:,:,:) , allocatable :: fld_phys, fld_gll real (kind=r8) :: element_ave ! ! for tensor product Lagrange interpolation @@ -64,17 +69,6 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ character(len=*), parameter :: subname = 'phys2dyn_forcings_fvm (SE)' - allocate(qgll(np,np,nlev,thermodynamic_active_species_num,nets:nete), stat=iret) - call check_allocate(iret, subname, & - 'qgll(np,np,nlev,thermodynamic_active_species_num,nets:nete)', & - file=__FILE__, line=__LINE__) - - do ie=nets,nete - do nq=1,thermodynamic_active_species_num - qgll(:,:,:,nq,ie) = elem(ie)%state%Qdp(:,:,:,nq,tl_qdp)/elem(ie)%state%dp3d(:,:,:,tl_f) - end do - end do - if (no_cslam) then call endrun("phys2dyn_forcings_fvm: no cslam case: NOT SUPPORTED") else if (nc.ne.fv_nphys) then @@ -96,7 +90,7 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ call check_allocate(iret, subname, 'fld_gll(np,np,nlev,3,nets:nete)', & file=__FILE__, line=__LINE__) - allocate(llimiter(nflds), stat=iret) + allocate(llimiter(3), stat=iret) call check_allocate(iret, subname, 'llimiter(nflds)', & file=__FILE__, line=__LINE__) @@ -123,7 +117,9 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ ! ! do mapping of fu,fv,ft ! - call phys2dyn(hybrid,elem,fld_phys(:,:,:,1:3,:),fld_gll(:,:,:,1:3,:),nets,nete,nlev,3,fvm,llimiter(1:3),2,.true.) + call phys2dyn(hybrid,elem,fld_phys(:,:,:,1:3,:),fld_gll,nets,nete,nlev,3,fvm,llimiter, & + istart_vector=2,halo_filled=.true.) + do ie=nets,nete elem(ie)%derived%fT(:,:,:) = fld_gll(:,:,:,1,ie) elem(ie)%derived%fM(:,:,1,:) = fld_gll(:,:,:,2,ie) @@ -144,44 +140,7 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ end do end do call t_stopf('p2d-pg2:phys2fvm') - - ! - ! overwrite SE Q with cslam Q - ! - nflds = thermodynamic_active_species_num - allocate(fld_gll(np,np,nlev,nflds,nets:nete), stat=iret) - call check_allocate(iret, subname, 'fld_gll(np,np,nlev,nflds,nets:nete)', & - file=__FILE__, line=__LINE__) - - allocate(fld_fvm(1-nhc:nc+nhc,1-nhc:nc+nhc,nlev,nflds,nets:nete), stat=iret) - call check_allocate(iret, subname, 'fld_fvm(1-nhc:nc+nhc,1-nhc:nc+nhc,nlev,nflds,nets:nete)', & - file=__FILE__, line=__LINE__) - - do ie=nets,nete - ! - ! compute cslam updated Q value - do m_cnst=1,thermodynamic_active_species_num - fld_fvm(1:nc,1:nc,:,m_cnst,ie) = fvm(ie)%c(1:nc,1:nc,:,thermodynamic_active_species_idx(m_cnst))+& - fvm(ie)%fc(1:nc,1:nc,:,thermodynamic_active_species_idx(m_cnst))/fvm(ie)%dp_fvm(1:nc,1:nc,:) - enddo - end do - call t_startf('p2d-pg2:fvm2dyn') - llimiter(1:nflds) = .false. - call fvm2dyn(fld_fvm,fld_gll(:,:,:,1:nflds,:),hybrid,nets,nete,nlev,nflds,fvm,llimiter(1:nflds)) - call t_stopf('p2d-pg2:fvm2dyn') - ! - ! fld_gll now holds q cslam value on gll grid - ! - ! convert fld_gll to increment (q_new-q_old) - ! - do ie=nets,nete - do m_cnst=1,thermodynamic_active_species_num - elem(ie)%derived%fq(:,:,:,m_cnst) =& - fld_gll(:,:,:,m_cnst,ie)-qgll(:,:,:,m_cnst,ie) - end do - end do - deallocate(fld_fvm) - !deallocate arrays allocated in dyn2phys_all_vars + !deallocate arrays allocated in dyn2phys_all_vars deallocate(save_air_mass_overlap,save_q_phys,save_q_overlap,& save_overlap_area,save_num_overlap,save_overlap_idx,save_dp_phys) else @@ -194,7 +153,7 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ !***************************************************************************************** ! ! nflds is ft, fu, fv, + thermo species - nflds = 3+thermodynamic_active_species_num + nflds = 3 allocate(fld_phys(1-nhc_phys:fv_nphys+nhc_phys,1-nhc_phys:fv_nphys+nhc_phys,nlev,nflds,nets:nete), stat=iret) call check_allocate(iret, subname, & 'fld_phys(1-nhc_phys:fv_nphys+nhc_phys,1-nhc_phys:fv_nphys+nhc_phys,nlev,nflds,nets:nete)', & @@ -217,18 +176,8 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ fld_phys(1:fv_nphys,1:fv_nphys,:,1,ie) = fvm(ie)%ft(1:fv_nphys,1:fv_nphys,:) fld_phys(1:fv_nphys,1:fv_nphys,:,2,ie) = fvm(ie)%fm(1:fv_nphys,1:fv_nphys,1,:) fld_phys(1:fv_nphys,1:fv_nphys,:,3,ie) = fvm(ie)%fm(1:fv_nphys,1:fv_nphys,2,:) - ! - ! compute cslam mixing ratio with physics update - ! - do m_cnst=1,thermodynamic_active_species_num - do k=1,nlev - fld_phys(1:fv_nphys,1:fv_nphys,k,m_cnst+3,ie) = & - fvm(ie)%c(1:fv_nphys,1:fv_nphys,k,thermodynamic_active_species_idx(m_cnst))+& - fvm(ie)%fc_phys(1:fv_nphys,1:fv_nphys,k,thermodynamic_active_species_idx(m_cnst)) - end do - end do - end do - ! + end do + ! ! do mapping ! call phys2dyn(hybrid,elem,fld_phys,fld_gll,nets,nete,nlev,nflds,fvm,llimiter,2) @@ -238,22 +187,16 @@ subroutine phys2dyn_forcings_fvm(elem, fvm, hybrid,nets,nete,no_cslam, tl_f, tl_ elem(ie)%derived%fM(:,:,2,:) = fld_gll(:,:,:,3,ie) end do do ie=nets,nete - do m_cnst=1,thermodynamic_active_species_num - ! - ! convert fq so that it will effectively overwrite SE q with CSLAM q - ! - elem(ie)%derived%fq(:,:,:,m_cnst) = fld_gll(:,:,:,m_cnst+3,ie)-& - qgll(:,:,:,m_cnst,ie) - end do do m_cnst = 1,ntrac fvm(ie)%fc(1:nc,1:nc,:,m_cnst) = fvm(ie)%fc_phys(1:nc,1:nc,:,m_cnst)*fvm(ie)%dp_fvm(1:nc,1:nc,:) end do end do end if - deallocate(fld_phys,llimiter,fld_gll,qgll) + deallocate(fld_phys,llimiter) end subroutine phys2dyn_forcings_fvm - subroutine fvm2dyn(fld_fvm,fld_gll,hybrid,nets,nete,numlev,num_flds,fvm,llimiter) + ! for multiple fields + subroutine fvm2dyntn(fld_fvm,fld_gll,hybrid,nets,nete,numlev,num_flds,fvm,llimiter,halo_filled) use dimensions_mod, only: np, nhc, nc use hybrid_mod , only: hybrid_t use bndry_mod , only: ghost_exchange @@ -266,7 +209,10 @@ subroutine fvm2dyn(fld_fvm,fld_gll,hybrid,nets,nete,numlev,num_flds,fvm,llimiter type (hybrid_t) , intent(in) :: hybrid type(fvm_struct) , intent(in) :: fvm(nets:nete) logical , intent(in) :: llimiter(num_flds) + logical, optional , intent(in) :: halo_filled !optional if boundary exchange for fld_fvm has already been called + integer :: ie, iwidth + logical :: fill_halo ! !********************************************* ! @@ -274,13 +220,20 @@ subroutine fvm2dyn(fld_fvm,fld_gll,hybrid,nets,nete,numlev,num_flds,fvm,llimiter ! !********************************************* ! - do ie=nets,nete - call ghostpack(ghostBufQnhc_s, fld_fvm(:,:,:,:,ie),numlev*num_flds,0,ie) - end do - call ghost_exchange(hybrid,ghostbufQnhc_s,location='fvm2dyn') - do ie=nets,nete - call ghostunpack(ghostbufQnhc_s, fld_fvm(:,:,:,:,ie),numlev*num_flds,0,ie) - end do + fill_halo = .true. + if (present(halo_filled)) then + fill_halo = .not. halo_filled + end if + + if (fill_halo) then + do ie=nets,nete + call ghostpack(ghostBufQnhc_s, fld_fvm(:,:,:,:,ie),numlev*num_flds,0,ie) + end do + call ghost_exchange(hybrid,ghostbufQnhc_s,location='fvm2dyntn') + do ie=nets,nete + call ghostunpack(ghostbufQnhc_s, fld_fvm(:,:,:,:,ie),numlev*num_flds,0,ie) + end do + end if ! ! mapping ! @@ -290,8 +243,56 @@ subroutine fvm2dyn(fld_fvm,fld_gll,hybrid,nets,nete,numlev,num_flds,fvm,llimiter call tensor_lagrange_interp(fvm(ie)%cubeboundary,np,nc,nhc,numlev,num_flds,fld_fvm(:,:,:,:,ie),& fld_gll(:,:,:,:,ie),llimiter,iwidth,fvm(ie)%norm_elem_coord) end do - end subroutine fvm2dyn + end subroutine fvm2dyntn + + ! for single field + subroutine fvm2dynt1(fld_fvm,fld_gll,hybrid,nets,nete,numlev,fvm,llimiter,halo_filled) + use dimensions_mod, only: np, nhc, nc + use hybrid_mod , only: hybrid_t + use bndry_mod , only: ghost_exchange + use edge_mod , only: ghostpack,ghostunpack + use fvm_mod , only: ghostBufQnhc_t1 + ! + integer , intent(in) :: nets,nete,numlev + real (kind=r8), intent(inout) :: fld_fvm(1-nhc:nc+nhc,1-nhc:nc+nhc,numlev,1,nets:nete) + real (kind=r8), intent(out) :: fld_gll(np,np,numlev,1,nets:nete) + type (hybrid_t) , intent(in) :: hybrid + type(fvm_struct) , intent(in) :: fvm(nets:nete) + logical , intent(in) :: llimiter(1) + logical, optional , intent(in) :: halo_filled!optional if boundary exchange for fld_fvm has already been called + + integer :: ie, iwidth + logical :: fill_halo + ! + !********************************************* + ! + ! halo exchange + ! + !********************************************* + ! + fill_halo = .true. + if (present(halo_filled)) then + fill_halo = .not. halo_filled + end if + if (fill_halo) then + do ie=nets,nete + call ghostpack(ghostBufQnhc_t1, fld_fvm(:,:,:,1,ie),numlev,0,ie) + end do + call ghost_exchange(hybrid,ghostbufQnhc_t1,location='fvm2dynt1') + do ie=nets,nete + call ghostunpack(ghostbufQnhc_t1, fld_fvm(:,:,:,1,ie),numlev,0,ie) + end do + end if + ! + ! mapping + ! + iwidth=2 + do ie=nets,nete + call tensor_lagrange_interp(fvm(ie)%cubeboundary,np,nc,nhc,numlev,1,fld_fvm(:,:,:,:,ie),& + fld_gll(:,:,:,:,ie),llimiter,iwidth,fvm(ie)%norm_elem_coord) + end do + end subroutine fvm2dynt1 subroutine fill_halo_phys(fld_phys,hybrid,nets,nete,num_lev,num_flds) use dimensions_mod, only: nhc_phys, fv_nphys @@ -330,7 +331,7 @@ end subroutine fill_halo_phys ! must call fill_halo_phys before calling this subroutine ! subroutine phys2dyn(hybrid,elem,fld_phys,fld_gll,nets,nete,num_lev,num_flds,fvm,llimiter,istart_vector,halo_filled) - use dimensions_mod, only: np, nhc_phys, fv_nphys + use dimensions_mod, only: np, nhc_phys, fv_nphys use hybrid_mod, only : hybrid_t type (hybrid_t), intent(in) :: hybrid ! distributed parallel structure (shared) integer , intent(in) :: nets,nete,num_flds,num_lev @@ -512,7 +513,7 @@ subroutine dyn2phys_all_vars(nets,nete,elem,fvm,& do ie=nets,nete tmp = 1.0_r8 inv_area = 1.0_r8/dyn2phys(tmp,elem(ie)%metdet(:,:)) - phis_phys(:,ie) = RESHAPE(fvm(ie)%phis_physgrid,SHAPE(phis_phys(:,ie))) + phis_phys(:,ie) = RESHAPE(dyn2phys(elem(ie)%state%phis(:,:),elem(ie)%metdet(:,:),inv_area),SHAPE(phis_phys(:,ie))) ps_phys(:,ie) = ptop if (nc.ne.fv_nphys) then tmp = 1.0_r8 @@ -542,7 +543,7 @@ subroutine dyn2phys_all_vars(nets,nete,elem,fvm,& ! no mapping needed - just copy fields into physics structure ! dp3d_phys(:,k,ie) = RESHAPE(fvm(ie)%dp_fvm(1:nc,1:nc,k),SHAPE(dp3d_phys(:,k,ie))) - ps_phys(:,ie) = ps_phys(:,ie)+RESHAPE(fvm(ie)%dp_fvm(1:nc,1:nc,k),SHAPE(ps_phys(:,ie))) + ps_phys(:,ie) = ps_phys(:,ie)+RESHAPE(fvm(ie)%dp_fvm(1:nc,1:nc,k),SHAPE(ps_phys(:,ie))) do m_cnst=1,num_trac q_phys(:,k,m_cnst,ie) = RESHAPE(fvm(ie)%c(1:nc,1:nc,k,m_cnst),SHAPE(q_phys(:,k,m_cnst,ie))) end do @@ -1074,11 +1075,11 @@ subroutine phys2fvm(ie,k,fvm,fq_phys,fqdp_fvm,num_trac) mass_forcing_phys = 0.0_r8 do h=1,num jdx = save_overlap_idx(1,h,jx,jy,ie); jdy = save_overlap_idx(2,h,jx,jy,ie) - q_prev = save_q_overlap(h,jx,jy,k,m_cnst,ie) + q_prev = save_q_overlap(h,jx,jy,k,m_cnst,ie) #ifndef skip_high_order_fq_map save_q_overlap(h,jx,jy,k,m_cnst,ie) = save_q_overlap(h,jx,jy,k,m_cnst,ie)+fq_phys_overlap(h,jx,jy) save_q_overlap(h,jx,jy,k,m_cnst,ie) = MIN(save_q_overlap(h,jx,jy,k,m_cnst,ie),phys_cdp_max(jx,jy)) - save_q_overlap(h,jx,jy,k,m_cnst,ie) = MAX(save_q_overlap(h,jx,jy,k,m_cnst,ie),phys_cdp_min(jx,jy)) + save_q_overlap(h,jx,jy,k,m_cnst,ie) = MAX(save_q_overlap(h,jx,jy,k,m_cnst,ie),phys_cdp_min(jx,jy)) mass_forcing = (save_q_overlap(h,jx,jy,k,m_cnst,ie)-q_prev)*save_air_mass_overlap(h,jx,jy,k,ie) mass_forcing_phys = mass_forcing_phys + mass_forcing fqdp_fvm(jdx,jdy,m_cnst) = fqdp_fvm(jdx,jdy,m_cnst)+mass_forcing @@ -1236,7 +1237,7 @@ subroutine get_fq_overlap(ie,k,fvm,fq_phys,max_overlap,fq_phys_overlap,num_trac) do m_cnst=1,num_trac fq_phys_overlap(idx,jx,jy,m_cnst) = & (fvm%dp_fvm(jdx,jdy,k)*SUM(weights_all_phys2fvm_local(h,:)*recons_q(:,jx,jy,m_cnst))+& - fq_phys(jx,jy,m_cnst)*dp_tmp)/save_air_mass_overlap(idx,jx,jy,k,ie) + fq_phys(jx,jy,m_cnst)*dp_tmp)/save_air_mass_overlap(idx,jx,jy,k,ie) end do end do end subroutine get_fq_overlap @@ -1335,13 +1336,13 @@ subroutine get_q_overlap_save(ie,k,fvm,q_fvm,num_trac,q_phys) num_overlap(:,:) = 0 q_phys = 0.0_r8 do h=1,jall_fvm2phys(ie) - jx = weights_lgr_index_all_fvm2phys(h,1,ie); jy = weights_lgr_index_all_fvm2phys(h,2,ie) + jx = weights_lgr_index_all_fvm2phys(h,1,ie); jy = weights_lgr_index_all_fvm2phys(h,2,ie) jdx = weights_eul_index_all_fvm2phys(h,1,ie); jdy = weights_eul_index_all_fvm2phys(h,2,ie) num_overlap(jx,jy) = num_overlap(jx,jy)+1 idx = num_overlap(jx,jy) - dp_fvm_tmp = fvm%dp_fvm(jdx,jdy,k) + dp_fvm_tmp = fvm%dp_fvm(jdx,jdy,k) dp_tmp = save_air_mass_overlap(idx,jx,jy,k,ie)-dp_fvm_tmp*weights_all_fvm2phys(h,1,ie) #ifdef PCoM dp_tmp = save_air_mass_overlap(idx,jx,jy,k,ie) @@ -1364,6 +1365,82 @@ subroutine get_q_overlap_save(ie,k,fvm,q_fvm,num_trac,q_phys) save_q_phys(:,:,k,m_cnst,ie) = q_phys(:,:,m_cnst) end do end subroutine get_q_overlap_save - + ! + ! Routine to overwrite thermodynamic active tracers on the GLL grid with CSLAM values + ! by Lagrange interpolation from 3x3 CSLAM grid to GLL grid. + ! + subroutine cslam2gll(elem, fvm, hybrid,nets,nete, tl_f, tl_qdp) + use dimensions_mod, only: nc,nlev,np,nhc + use hybrid_mod, only: hybrid_t + use air_composition, only: thermodynamic_active_species_num, thermodynamic_active_species_idx + use fvm_mod, only: ghostBuf_cslam2gll + use bndry_mod, only: ghost_exchange + use edge_mod, only: ghostpack,ghostunpack + use cam_logfile, only: iulog + type (element_t), intent(inout):: elem(:) + type(fvm_struct), intent(inout):: fvm(:) + + type (hybrid_t), intent(in) :: hybrid ! distributed parallel structure (shared) + integer, intent(in) :: nets, nete, tl_f, tl_qdp + + integer :: ie,i,j,k,m_cnst,nq,iret + real (kind=r8), dimension(:,:,:,:,:) , allocatable :: fld_fvm, fld_gll + character(len=*), parameter :: subname = 'cslam2gll' + ! + ! for tensor product Lagrange interpolation + ! + integer :: nflds + logical, allocatable :: llimiter(:) + call t_startf('cslam2gll') + nflds = thermodynamic_active_species_num + + !Allocate variables + !------------------ + allocate(fld_fvm(1-nhc:nc+nhc,1-nhc:nc+nhc,nlev,nflds,nets:nete), stat=iret) + call check_allocate(iret, subname, 'fld_fvm(1-nhc:nc+nhc,1-nhc:nc+nhc,nlev,nflds,nets:nete)', & + file=__FILE__, line=__LINE__) + + allocate(fld_gll(np,np,nlev,thermodynamic_active_species_num,nets:nete),stat=iret) + call check_allocate(iret, subname, 'fld_gll(np,np,nlev,thermodynamic_active_species_num,nets:nete)', & + file=__FILE__, line=__LINE__) + + allocate(llimiter(nflds), stat=iret) + call check_allocate(iret, subname, 'llimiter(nflds)', & + file=__FILE__, line=__LINE__) + !------------------ + + llimiter(1:nflds) = .false. + do ie=nets,nete + do m_cnst=1,thermodynamic_active_species_num + do k=1,nlev + fld_fvm(1:nc,1:nc,k,m_cnst,ie) = & + fvm(ie)%c(1:nc,1:nc,k,thermodynamic_active_species_idx(m_cnst)) + end do + end do + end do + call t_startf('fvm:fill_halo_cslam2gll') + do ie=nets,nete + call ghostpack(ghostBuf_cslam2gll, fld_fvm(:,:,:,:,ie),nlev*nflds,0,ie) + end do + + call ghost_exchange(hybrid,ghostBuf_cslam2gll,location='cslam2gll') + do ie=nets,nete + call ghostunpack(ghostBuf_cslam2gll, fld_fvm(:,:,:,:,ie),nlev*nflds,0,ie) + end do + call t_stopf('fvm:fill_halo_cslam2gll') + ! + ! do mapping + ! + call fvm2dyn(fld_fvm,fld_gll,hybrid,nets,nete,nlev,nflds,fvm,llimiter,halo_filled=.true.) + + do ie=nets,nete + do m_cnst=1,thermodynamic_active_species_num + elem(ie)%state%qdp(:,:,:,m_cnst,tl_qdp) = fld_gll(:,:,:,m_cnst,ie)*& + elem(ie)%state%dp3d(:,:,:,tl_f) + end do + end do + deallocate(fld_fvm, fld_gll, llimiter) + call t_stopf('cslam2gll') + end subroutine cslam2gll end module fvm_mapping diff --git a/src/dynamics/se/dycore/fvm_mod.F90 b/src/dynamics/se/dycore/fvm_mod.F90 index 72b4a01e..77c88010 100644 --- a/src/dynamics/se/dycore/fvm_mod.F90 +++ b/src/dynamics/se/dycore/fvm_mod.F90 @@ -26,6 +26,7 @@ module fvm_mod type (EdgeBuffer_t) :: edgeveloc type (EdgeBuffer_t), public :: ghostBufQnhc_s + type (EdgeBuffer_t), public :: ghostBufQnhc_t1 type (EdgeBuffer_t), public :: ghostBufQnhc_vh type (EdgeBuffer_t), public :: ghostBufQnhc_h type (EdgeBuffer_t), public :: ghostBufQ1_h @@ -35,6 +36,7 @@ module fvm_mod type (EdgeBuffer_t), public :: ghostBufQnhcJet_h type (EdgeBuffer_t), public :: ghostBufFluxJet_h type (EdgeBuffer_t), public :: ghostBufPG_s + type (EdgeBuffer_t), public :: ghostBuf_cslam2gll interface fill_halo_fvm module procedure fill_halo_fvm_noprealloc @@ -65,7 +67,7 @@ subroutine fill_halo_fvm_noprealloc(elem,fvm,hybrid,nets,nete,ndepth,kmin,kmax,k ! ! - if(kmin .ne. 1 .or. kmax .ne. nlev) then + if(kmin .ne. 1 .or. kmax .ne. nlev) then print *,'WARNING: fill_halo_fvm_noprealloc does not support the passing of non-contigous arrays' print *,'WARNING: incorrect answers are likely' endif @@ -118,7 +120,7 @@ subroutine fill_halo_fvm_prealloc(cellghostbuf,elem,fvm,hybrid,nets,nete,ndepth, integer,intent(in) :: ndepth ! depth of halo integer,intent(in) :: kmin,kmax ! min and max vertical level integer,intent(in) :: ksize ! the total number of vertical - logical, optional :: active ! indicates if te current thread is active + logical, optional :: active ! indicates if te current thread is active integer :: ie,i1,i2,kblk,q,kptr ! ! @@ -134,7 +136,7 @@ subroutine fill_halo_fvm_prealloc(cellghostbuf,elem,fvm,hybrid,nets,nete,ndepth, i2=nc+ndepth kblk = kmax-kmin+1 if(FVM_TIMERS) call t_startf('FVM:pack') - if(lactive) then + if(lactive) then do ie=nets,nete kptr = kmin-1 call ghostpack(cellghostbuf, fvm(ie)%dp_fvm(i1:i2,i1:i2,kmin:kmax),kblk, kptr,ie) @@ -150,7 +152,7 @@ subroutine fill_halo_fvm_prealloc(cellghostbuf,elem,fvm,hybrid,nets,nete,ndepth, if(FVM_TIMERS) call t_stopf('FVM:Communication') !-----------------------------------------------------------------------------------! if(FVM_TIMERS) call t_startf('FVM:Unpack') - if(lactive) then + if(lactive) then do ie=nets,nete kptr = kmin-1 call ghostunpack(cellghostbuf, fvm(ie)%dp_fvm(i1:i2,i1:i2,kmin:kmax),kblk, kptr,ie) @@ -493,6 +495,7 @@ subroutine fvm_init2(elem,fvm,hybrid,nets,nete) ! changes the values for reverse call initghostbuffer(hybrid%par,ghostBufQnhc_s,elem,nlev*(ntrac+1),nhc,nc,nthreads=1) + call initghostbuffer(hybrid%par,ghostBufQnhc_t1,elem,nlev, nhc,nc,nthreads=1) call initghostbuffer(hybrid%par,ghostBufQnhc_h,elem,nlev*(ntrac+1),nhc,nc,nthreads=horz_num_threads) call initghostbuffer(hybrid%par,ghostBufQnhc_vh,elem,nlev*(ntrac+1),nhc,nc,nthreads=vert_num_threads*horz_num_threads) klev = kmax_jet-kmin_jet+1 @@ -500,13 +503,14 @@ subroutine fvm_init2(elem,fvm,hybrid,nets,nete) call initghostbuffer(hybrid%par,ghostBufQ1_vh,elem,klev*(ntrac+1),1,nc,nthreads=vert_num_threads*horz_num_threads) ! call initghostbuffer(hybrid%par,ghostBufFlux_h,elem,4*nlev,nhe,nc,nthreads=horz_num_threads) call initghostbuffer(hybrid%par,ghostBufFlux_vh,elem,4*nlev,nhe,nc,nthreads=vert_num_threads*horz_num_threads) + call initghostbuffer(hybrid%par,ghostBuf_cslam2gll,elem,nlev*thermodynamic_active_species_num,nhc,nc,nthreads=1) ! ! preallocate buffers for physics-dynamics coupling ! if (fv_nphys.ne.nc) then call initghostbuffer(hybrid%par,ghostBufPG_s,elem,nlev*(4+ntrac),nhc_phys,fv_nphys,nthreads=1) else - call initghostbuffer(hybrid%par,ghostBufPG_s,elem,nlev*(3+thermodynamic_active_species_num),nhc_phys,fv_nphys,nthreads=1) + call initghostbuffer(hybrid%par,ghostBufPG_s,elem,nlev*3,nhc_phys,fv_nphys,nthreads=1) end if if (fvm_supercycling.ne.fvm_supercycling_jet) then diff --git a/src/dynamics/se/dycore/global_norms_mod.F90 b/src/dynamics/se/dycore/global_norms_mod.F90 index 667e5693..a77ce33b 100644 --- a/src/dynamics/se/dycore/global_norms_mod.F90 +++ b/src/dynamics/se/dycore/global_norms_mod.F90 @@ -157,7 +157,7 @@ function global_integral(elem, h,hybrid,npts,nets,nete) result(I_sphere) real (kind=r8) :: da real (kind=r8) :: J_tmp(nets:nete) ! -! This algorythm is independent of thread count and task count. +! This algorithm is independent of thread count and task count. ! This is a requirement of consistancy checking in cam. ! J_tmp = 0.0_r8 @@ -203,25 +203,25 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& ! worse viscosity CFL (given by dtnu) is not violated by reducing ! viscosity coefficient in regions where CFL is violated ! - use hybrid_mod, only: hybrid_t, PrintHybrid + use hybrid_mod, only: hybrid_t use element_mod, only: element_t - use dimensions_mod, only: np,ne,nelem,nelemd,nc,nhe,use_cslam,nlev,large_Courant_incr - use dimensions_mod, only: nu_scale_top,nu_div_lev,nu_lev + use dimensions_mod, only: np,ne,nelem,nc,nhe,use_cslam,nlev,large_Courant_incr + use dimensions_mod, only: nu_scale_top,nu_div_lev,nu_lev,nu_t_lev use quadrature_mod, only: gausslobatto, quadrature_t use reduction_mod, only: ParallelMin,ParallelMax use dynconst, only: ra, rearth, cpair - use control_mod, only: nu, nu_div, nu_q, nu_p, nu_t, nu_top, fine_ne, rk_stage_user, max_hypervis_courant + use control_mod, only: nu, nu_div, nu_q, nu_p, nu_t, nu_top, fine_ne, max_hypervis_courant use control_mod, only: tstep_type, hypervis_power, hypervis_scaling + use control_mod, only: sponge_del4_nu_div_fac, sponge_del4_nu_fac, sponge_del4_lev use cam_abortutils, only: endrun use parallel_mod, only: global_shared_buf, global_shared_sum use edge_mod, only: initedgebuffer, FreeEdgeBuffer, edgeVpack, edgeVunpack use bndry_mod, only: bndry_exchange - use time_mod, only: tstep use mesh_mod, only: MeshUseMeshFile use dimensions_mod, only: ksponge_end, kmvis_ref, kmcnd_ref,rho_ref - + use std_atm_profile,only: std_atm_height type(element_t) , intent(inout) :: elem(:) integer , intent(in) :: nets,nete type (hybrid_t) , intent(in) :: hybrid @@ -237,14 +237,14 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& real (kind=r8) :: max_min_dx,min_min_dx,min_max_dx,max_unif_dx ! used for normalizing scalar HV real (kind=r8) :: max_normDinv, min_normDinv ! used for CFL real (kind=r8) :: min_area, max_area,max_ratio !min/max element area - real (kind=r8) :: avg_area, avg_min_dx + real (kind=r8) :: avg_area, avg_min_dx,tot_area,tot_area_rad real (kind=r8) :: min_hypervis, max_hypervis, avg_hypervis, stable_hv real (kind=r8) :: normDinv_hypervis real (kind=r8) :: x, y, noreast, nw, se, sw real (kind=r8), dimension(np,np,nets:nete) :: zeta real (kind=r8) :: lambda_max, lambda_vis, min_gw, lambda,umax, ugw - real (kind=r8) :: press,scale1,scale2,scale3, max_laplace - integer :: ie,corner, i, j, rowind, colind, k + real (kind=r8) :: scale1,scale2,max_laplace,z(nlev) + integer :: ie, i, j, rowind, colind, k type (quadrature_t) :: gp character(LEN=256) :: rk_str @@ -252,10 +252,11 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& real (kind=r8) :: dt_max_adv, dt_max_gw, dt_max_tracer_se, dt_max_tracer_fvm real (kind=r8) :: dt_max_hypervis, dt_max_hypervis_tracer, dt_max_laplacian_top - real(kind=r8) :: I_sphere + real(kind=r8) :: I_sphere, nu_max, nu_div_max real(kind=r8) :: h(np,np,nets:nete) - + logical :: top_000_032km, top_032_042km, top_042_090km, top_090_140km, top_140_600km ! model top location ranges + logical :: nu_set,div_set,lev_set ! Eigenvalues calculated by folks at UMich (Paul U & Jared W) select case (np) @@ -336,6 +337,7 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& enddo call wrap_repro_sum(nvars=2, comm=hybrid%par%comm) avg_area = global_shared_sum(1)/real(nelem, r8) + tot_area_rad = global_shared_sum(1) avg_min_dx = global_shared_sum(2)/real(nelem, r8) min_area = ParallelMin(min_area,hybrid) @@ -347,15 +349,18 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& min_max_dx = ParallelMin(min_max_dx,hybrid) max_ratio = ParallelMax(max_ratio,hybrid) ! Physical units for area - min_area = min_area*rearth*rearth/1000000._r8 + min_area = min_area*rearth*rearth/1000000._r8!m2 (rearth is in units of km) max_area = max_area*rearth*rearth/1000000._r8 avg_area = avg_area*rearth*rearth/1000000._r8 + tot_area = tot_area_rad*rearth*rearth/1000000._r8 if (hybrid%masterthread) then write(iulog,* )"" write(iulog,* )"Running Global Integral Diagnostic..." write(iulog,*)"Area of unit sphere is",I_sphere write(iulog,*)"Should be 1.0 to round off..." write(iulog,'(a,f9.3)') 'Element area: max/min',(max_area/min_area) + write(iulog,'(a,E23.15)') 'Total Grid area: ',(tot_area) + write(iulog,'(a,E23.15)') 'Total Grid area rad^2: ',(tot_area_rad) if (.not.MeshUseMeshFile) then write(iulog,'(a,f6.3,f8.2)') "Average equatorial node spacing (deg, km) = ", & real(90, r8)/real(ne*(np-1), r8), pi*rearth/(2000.0_r8*real(ne*(np-1), r8)) @@ -539,41 +544,146 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& end do end do enddo !rowind - enddo !colind + enddo !colind endif deallocate(gp%points) deallocate(gp%weights) call automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min_dx,nu_p ,1.0_r8 ,'_p ') - call automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min_dx,nu ,0.5_r8,' ') - if (ptop>100.0_r8) then + call automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min_dx,nu ,1.0_r8,' ') + call automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min_dx,nu_div,2.5_r8 ,'_div') + + if (nu_q<0) nu_q = nu_p ! necessary for consistency + if (nu_t<0) nu_t = nu_p ! temperature damping is always equal to nu_p + + nu_div_lev(:) = nu_div + nu_lev(:) = nu + nu_t_lev(:) = nu_p + + ! + ! sponge layer strength needed for stability depends on model top location + ! + top_000_032km = .false. + top_032_042km = .false. + top_042_090km = .false. + top_090_140km = .false. + top_140_600km = .false. + nu_set = sponge_del4_nu_fac < 0 + div_set = sponge_del4_nu_div_fac < 0 + lev_set = sponge_del4_lev < 0 + if (ptop>1000.0_r8) then + ! + ! low top; usually idealized test cases + ! + top_000_032km = .true. + if (hybrid%masterthread) write(iulog,* )"Model top damping configuration: top_000_032km" + else if (ptop>100.0_r8) then + ! + ! CAM6 top (~225 Pa) or CAM7 low top + ! + top_032_042km = .true. + if (hybrid%masterthread) write(iulog,* )"Model top damping configuration: top_032_042km" + else if (ptop>1e-1_r8) then ! - ! CAM setting + ! CAM7 top (~4.35e-1 Pa) ! - call automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min_dx,nu_div,2.5_r8 ,'_div') - nu_div_lev(:) = nu_div - nu_lev(:) = nu + top_042_090km = .true. + if (hybrid%masterthread) write(iulog,* )"Model top damping configuration: top_042_090km" + else if (ptop>1E-4_r8) then + ! + ! WACCM top (~4.5e-4 Pa) + ! + top_090_140km = .true. + if (hybrid%masterthread) write(iulog,* )"Model top damping configuration: top_090_140km" else ! - ! WACCM setting + ! WACCM-x - geospace (~4e-7 Pa) ! - call automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min_dx,nu_div,2.5_r8 ,'_div') - if (hybrid%masterthread) write(iulog,*) ": sponge layer viscosity scaling factor" + top_140_600km = .true. + if (hybrid%masterthread) write(iulog,* )"Model top damping configuration: top_140_600km" + end if + ! + ! Logging text for sponge layer configuration + ! + if (hybrid%masterthread .and. (nu_set .or. div_set .or. lev_set)) then + write(iulog,* )"" + write(iulog,* )"Sponge layer del4 coefficient defaults based on model top location:" + end if + ! + ! if user or namelist is not specifying sponge del4 settings here are best guesses (empirically determined) + ! + if (top_042_090km) then + if (sponge_del4_lev <0) sponge_del4_lev = 4 + if (sponge_del4_nu_fac <0) sponge_del4_nu_fac = 3.375_r8 !max value without having to increase subcycling of div4 + if (sponge_del4_nu_div_fac<0) sponge_del4_nu_div_fac = 3.375_r8 !max value without having to increase subcycling of div4 + else if (top_090_140km.or.top_140_600km) then ! defaults for waccm(x) + if (sponge_del4_lev <0) sponge_del4_lev = 20 + if (sponge_del4_nu_fac <0) sponge_del4_nu_fac = 5.0_r8 + if (sponge_del4_nu_div_fac<0) sponge_del4_nu_div_fac = 10.0_r8 + else + if (sponge_del4_lev <0) sponge_del4_lev = 1 + if (sponge_del4_nu_fac <0) sponge_del4_nu_fac = 1.0_r8 + if (sponge_del4_nu_div_fac<0) sponge_del4_nu_div_fac = 1.0_r8 + end if + + ! set max wind speed for diagnostics + umax = 120.0_r8 + if (top_042_090km) then + umax = 240._r8 + else if (top_090_140km) then + umax = 300._r8 + else if (top_140_600km) then + umax = 800._r8 + end if + ! + ! Log sponge layer configuration + ! + if (hybrid%masterthread) then + if (nu_set) then + write(iulog, '(a,e9.2)') ' sponge_del4_nu_fac = ',sponge_del4_nu_fac + end if + + if (div_set) then + write(iulog, '(a,e9.2)') ' sponge_del4_nu_div_fac = ',sponge_del4_nu_div_fac + end if + + if (lev_set) then + write(iulog, '(a,i0)') ' sponge_del4_lev = ',sponge_del4_lev + end if + write(iulog,* )"" + end if + + nu_max = sponge_del4_nu_fac*nu_p + nu_div_max = sponge_del4_nu_div_fac*nu_p + do k=1,nlev + ! Vertical profile from FV dycore (see Lauritzen et al. 2012 DOI:10.1177/1094342011410088) + scale1 = 0.5_r8*(1.0_r8+tanh(2.0_r8*log(pmid(sponge_del4_lev)/pmid(k)))) + if (sponge_del4_nu_div_fac /= 1.0_r8) then + nu_div_lev(k) = (1.0_r8-scale1)*nu_div+scale1*nu_div_max + end if + if (sponge_del4_nu_fac /= 1.0_r8) then + nu_lev(k) = (1.0_r8-scale1)*nu +scale1*nu_max + nu_t_lev(k) = (1.0_r8-scale1)*nu_p +scale1*nu_max + end if + end do + + if (hybrid%masterthread)then + write(iulog,*) "z computed from barometric formula (using US std atmosphere)" + call std_atm_height(pmid(:),z(:)) + write(iulog,*) "k,pmid_ref,z,nu_lev,nu_t_lev,nu_div_lev" do k=1,nlev - press = pmid(k) - - scale1 = 0.5_r8*(1.0_r8+tanh(2.0_r8*log(100.0_r8/press))) - nu_div_lev(k) = (1.0_r8-scale1)*nu_div+scale1*2.0_r8*nu_div - nu_div_lev(k) = nu_div - nu_lev(k) = (1.0_r8-scale1)*nu +scale1*nu_p - nu_lev(k) = nu - if (hybrid%masterthread) write(iulog,*) "nu_lev=",k,nu_lev(k) - if (hybrid%masterthread) write(iulog,*) "nu_div_lev=",k,nu_div_lev(k) + write(iulog,'(i3,5e11.4)') k,pmid(k),z(k),nu_lev(k),nu_t_lev(k),nu_div_lev(k) end do - end if + if (nu_top>0) then + write(iulog,*) ": ksponge_end = ",ksponge_end + write(iulog,*) ": sponge layer Laplacian damping" + write(iulog,*) "k, p, z, nu_scale_top, nu (actual Laplacian damping coefficient)" - if (nu_q<0) nu_q = nu_p ! necessary for consistency - if (nu_t<0) nu_t = nu_p ! temperature damping is always equal to nu_p + do k=1,ksponge_end + write(iulog,'(i3,4e11.4)') k,pmid(k),z(k),nu_scale_top(k),nu_scale_top(k)*nu_top + end do + end if + end if !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! @@ -600,25 +710,15 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& write(iulog,'(a,f12.8,a)') 'Model top is ',ptop,'Pa' write(iulog,'(a)') ' ' write(iulog,'(a)') 'Timestepping methods used in dynamical core:' - write(iulog,'(a)') + write(iulog,'(a)') write(iulog,*) rk_str write(iulog,'(a)') ' * Spectral-element advection uses SSP preservation RK3' write(iulog,'(a)') ' * Viscosity operators use forward Euler' - if (use_cslam) then - write(iulog,'(a)') ' * CSLAM uses two time-levels backward trajectory method' - end if end if S_laplacian = 2.0_r8 !using forward Euler for sponge diffusion S_hypervis = 2.0_r8 !using forward Euler for hyperviscosity S_rk_tracer = 2.0_r8 - ! - ! estimate max winds - ! - if (ptop>100.0_r8) then - umax = 120.0_r8 - else - umax = 400.0_r8 - end if + ugw = 342.0_r8 !max gravity wave speed dt_max_adv = S_rk/(umax*max_normDinv*lambda_max*ra) @@ -626,14 +726,15 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& dt_max_tracer_se = S_rk_tracer*min_gw/(umax*max_normDinv*ra) if (use_cslam) then if (large_Courant_incr) then - dt_max_tracer_fvm = real(nhe, r8)*(4.0_r8*pi*real(Rearth, r8)/real(4.0_r8*ne*nc, r8))/umax + dt_max_tracer_fvm = dble(nhe)*(4.0_r8*pi*Rearth/dble(4.0_r8*ne*nc))/umax else - dt_max_tracer_fvm = real(nhe, r8)*(2.0_r8*pi*real(Rearth, r8)/real(4.0_r8*ne*nc, r8))/umax + dt_max_tracer_fvm = dble(nhe)*(2.0_r8*pi*Rearth/dble(4.0_r8*ne*nc))/umax end if else dt_max_tracer_fvm = -1.0_r8 end if - dt_max_hypervis = s_hypervis/(MAX(MAXVAL(nu_div_lev(:)),MAXVAL(nu_lev(:)))*normDinv_hypervis) + nu_max = MAX(MAXVAL(nu_div_lev(:)),MAXVAL(nu_lev(:)),MAXVAL(nu_t_lev(:))) + dt_max_hypervis = s_hypervis/(nu_max*normDinv_hypervis) dt_max_hypervis_tracer = s_hypervis/(nu_q*normDinv_hypervis) max_laplace = MAX(MAXVAL(nu_scale_top(:))*nu_top,MAXVAL(kmvis_ref(:)/rho_ref(:))) @@ -654,12 +755,12 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& 's ',dt_dyn_visco_actual,'s' if (dt_dyn_visco_actual>dt_max_hypervis) write(iulog,*) 'WARNING: dt_dyn_vis theoretically unstable' if (.not.use_cslam) then - write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_se (time-stepping tracers ; q ) < ',dt_max_tracer_se,'s ',& - dt_tracer_se_actual,'s' - if (dt_tracer_se_actual>dt_max_tracer_se) write(iulog,*) 'WARNING: dt_tracer_se theoretically unstable' - write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_vis (hyperviscosity tracers; q ) < ',dt_max_hypervis_tracer,'s',& - dt_tracer_visco_actual,'s' - if (dt_tracer_visco_actual>dt_max_hypervis_tracer) write(iulog,*) 'WARNING: dt_tracer_hypervis theoretically unstable' + write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_se (time-stepping tracers ; q ) < ',dt_max_tracer_se,'s ',& + dt_tracer_se_actual,'s' + if (dt_tracer_se_actual>dt_max_tracer_se) write(iulog,*) 'WARNING: dt_tracer_se theoretically unstable' + write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_vis (hyperviscosity tracers; q ) < ',dt_max_hypervis_tracer,'s',& + dt_tracer_visco_actual,'s' + if (dt_tracer_visco_actual>dt_max_hypervis_tracer) write(iulog,*) 'WARNING: dt_tracer_hypervis theoretically unstable' end if if (use_cslam) then write(iulog,'(a,f10.2,a,f10.2,a)') '* dt_tracer_fvm (time-stepping tracers ; q ) < ',dt_max_tracer_fvm,& @@ -674,8 +775,14 @@ subroutine print_cfl(elem,hybrid,nets,nete,dtnu,ptop,pmid,& write(iulog,'(a,f10.2,a,f10.2,a)') '* dt (del2 sponge ; u,v,T,dM) < ',& dt_max_laplacian_top,'s',dt_dyn_del2_actual,'s' - if (dt_dyn_del2_actual>dt_max_laplacian_top) & - write(iulog,*) 'WARNING: theoretically unstable in sponge; increase se_hypervis_subcycle_sponge' + if (dt_dyn_del2_actual>dt_max_laplacian_top) then + if (k==1) then + write(iulog,*) 'WARNING: theoretically unstable in sponge; increase se_hypervis_subcycle_sponge',& + ' (this WARNING can sometimes be ignored in level 1)' + else + write(iulog,*) 'WARNING: theoretically unstable in sponge; increase se_hypervis_subcycle_sponge' + endif + end if end do write(iulog,*) ' ' if (hypervis_power /= 0) then @@ -1105,7 +1212,9 @@ subroutine automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min if (nu < 0) then if (ne <= 0) then - if (hypervis_scaling/=0) then + if (hypervis_power/=0) then + call endrun('ERROR: Automatic scaling of scalar viscosity not implemented') + else if (hypervis_scaling/=0) then nu_min = factor*nu_fac*(max_min_dx*1000.0_r8)**uniform_res_hypervis_scaling nu_max = factor*nu_fac*(min_min_dx*1000.0_r8)**uniform_res_hypervis_scaling nu = factor*nu_min @@ -1114,11 +1223,9 @@ subroutine automatically_set_viscosity_coefficients(hybrid,ne,max_min_dx,min_min write(iulog,'(a,2e9.2,a,2f9.2)') "Value at min/max grid spacing: ",nu_min,nu_max,& " Max/min grid spacing (km) = ",max_min_dx,min_min_dx end if - nu = nu_min*(2.0_r8*rearth/(3.0_r8*max_min_dx*1000.0_r8))**hypervis_scaling/(rearth**4._r8) + nu = nu_min*(2.0_r8*rearth/(3.0_r8*max_min_dx*1000.0_r8))**hypervis_scaling/(rearth**4) if (hybrid%masterthread) & write(iulog,'(a,a,a,e9.3)') "Nu_tensor",TRIM(str)," = ",nu - else if (hypervis_power/=0) then - call endrun('ERROR: Automatic scaling of scalar viscosity not implemented') end if else nu = factor*nu_fac*((30.0_r8/ne)*110000.0_r8)**uniform_res_hypervis_scaling diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index fb96a7d6..26443a43 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -10,7 +10,7 @@ module prim_advance_mod private save - public :: prim_advance_exp, prim_advance_init, applyCAMforcing, calc_tot_energy_dynamics, compute_omega + public :: prim_advance_exp, prim_advance_init, applyCAMforcing, tot_energy_dyn, compute_omega type (EdgeBuffer_t) :: edge3,edgeOmega,edgeSponge real (kind=r8), allocatable :: ur_weights(:) @@ -31,7 +31,9 @@ subroutine prim_advance_init(par, elem) character(len=*), parameter :: subname = 'prim_advance_init (SE)' call initEdgeBuffer(par,edge3 ,elem,4*nlev ,bndry_type=HME_BNDRY_P2P, nthreads=horz_num_threads) - call initEdgeBuffer(par,edgeSponge,elem,4*ksponge_end,bndry_type=HME_BNDRY_P2P, nthreads=horz_num_threads) + if (ksponge_end>0) then + call initEdgeBuffer(par,edgeSponge,elem,4*ksponge_end,bndry_type=HME_BNDRY_P2P, nthreads=horz_num_threads) + end if call initEdgeBuffer(par,edgeOmega ,elem,nlev ,bndry_type=HME_BNDRY_P2P, nthreads=horz_num_threads) if(.not. allocated(ur_weights)) then @@ -67,13 +69,13 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net use element_mod, only: element_t use hybvcoord_mod, only: hvcoord_t use hybrid_mod, only: hybrid_t - use time_mod, only: TimeLevel_t, timelevel_qdp, tevolve + use se_dyn_time_mod, only: TimeLevel_t, timelevel_qdp, tevolve use fvm_control_volume_mod, only: fvm_struct implicit none type (element_t), intent(inout), target :: elem(:) - type(fvm_struct) , intent(in) :: fvm(:) + type(fvm_struct) , intent(inout) :: fvm(:) type (derivative_t) , intent(in) :: deriv type (hvcoord_t) :: hvcoord type (hybrid_t) , intent(in) :: hybrid @@ -84,14 +86,12 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net ! Local real (kind=r8) :: dt_vis, eta_ave_w - real (kind=r8) :: dp(np,np) integer :: ie,nm1,n0,np1,k,qn0,m_cnst, nq + real (kind=r8) :: inv_cp_full(np,np,nlev,nets:nete) real (kind=r8) :: qwater(np,np,nlev,thermodynamic_active_species_num,nets:nete) integer :: qidx(thermodynamic_active_species_num) real (kind=r8) :: kappa(np,np,nlev,nets:nete) - real (kind=r8) :: inv_cp_full(np,np,nlev,nets:nete) - call t_startf('prim_advance_exp') nm1 = tl%nm1 n0 = tl%n0 @@ -118,9 +118,6 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net ! (K&G 2nd order method has CFL=4. tiny CFL improvement not worth 2nd order) ! - if (dry_air_species_num > 0) & - call endrun('ERROR: SE dycore not ready for species dependent thermodynamics - ABORT') - call omp_set_nested(.true.) ! default weights for computing mean dynamics fluxes @@ -138,18 +135,18 @@ subroutine prim_advance_exp(elem, fvm, deriv, hvcoord, hybrid,dt, tl, nets, net ! ! make sure Q is updated ! - qwater(:,:,:,nq,ie) = elem(ie)%state%Qdp(:,:,:,m_cnst,qn0)/elem(ie)%state%dp3d(:,:,:,n0) + qwater(:,:,:,nq,ie) = elem(ie)%state%Qdp(:,:,:,m_cnst,qn0)/elem(ie)%state%dp3d(:,:,:,n0) end do end do ! ! compute Cp and kappa=Rdry/cpdry here and not in RK-stages since Q stays constant => Cp and kappa also stays constant ! do ie=nets,nete - call get_cp(qwater(:,:,:,:,ie), & - .true.,inv_cp_full(:,:,:,ie),active_species_idx_dycore=qidx) + call get_cp(qwater(:,:,:,:,ie),.true.,& + inv_cp_full(:,:,:,ie), active_species_idx_dycore=qidx) end do do ie=nets,nete - call get_kappa_dry(qwater(:,:,:,:,ie),qidx,kappa(:,:,:,ie)) + call get_kappa_dry(qwater(:,:,:,:,ie), qidx, kappa(:,:,:,ie)) end do @@ -388,7 +385,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu ! ! tracers ! - if (qsize>0.and.dt_local_tracer>0) then + if (.not.use_cslam.and.dt_local_tracer>0) then #if (defined COLUMN_OPENMP) !$omp parallel do num_threads(tracer_num_threads) private(q,k,i,j,v1) #endif @@ -444,10 +441,9 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu if (use_cslam) ftmp_fvm(:,:,:,:,ie) = 0.0_r8 end if - - if (ftype_conserve==1) then - call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,np1_qdp),MASS_MIXING_RATIO, & - thermodynamic_active_species_idx_dycore,elem(ie)%state%dp3d(:,:,:,np1),pdel) + if (ftype_conserve==1.and..not.use_cslam) then + call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,np1_qdp), MASS_MIXING_RATIO, & + thermodynamic_active_species_idx_dycore, elem(ie)%state%dp3d(:,:,:,np1), pdel) do k=1,nlev do j=1,np do i = 1,np @@ -477,29 +473,28 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu else call output_qdp_var_dynamics(ftmp(:,:,:,:,:),np,qsize,nets,nete,'PDC') end if - if (ftype==1.and.nsubstep==1) call calc_tot_energy_dynamics(elem,fvm,nets,nete,np1,np1_qdp,'p2d') + if (ftype==1.and.nsubstep==1) call tot_energy_dyn(elem,fvm,nets,nete,np1,np1_qdp,'p2d') if (use_cslam) deallocate(ftmp_fvm) + call t_stopf('applyCAMforc') end subroutine applyCAMforcing - subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2,eta_ave_w,inv_cp_full,hvcoord) ! ! take one timestep of: ! u(:,:,:,np) = u(:,:,:,np) + dt2*nu*laplacian**order ( u ) - ! T(:,:,:,np) = T(:,:,:,np) + dt2*nu_s*laplacian**order ( T ) + ! T(:,:,:,np) = T(:,:,:,np) + dt2*nu_t*laplacian**order ( T ) ! ! ! For correct scaling, dt2 should be the same 'dt2' used in the leapfrog advace ! ! - use dynconst, only: gravit, cappa, cpair, tref, lapse_rate - use dyn_thermo, only: get_dp_ref - use dimensions_mod, only: np, nlev, nc, use_cslam, npsq, qsize - use dimensions_mod, only: hypervis_dynamic_ref_state,ksponge_end + use physconst, only: cappa, cpair + use cam_thermo, only: get_molecular_diff_coef, get_rho_dry + use dimensions_mod, only: np, nlev, nc, use_cslam, npsq, qsize, ksponge_end use dimensions_mod, only: nu_scale_top,nu_lev,kmvis_ref,kmcnd_ref,rho_ref,km_sponge_factor - use dimensions_mod, only: kmvisi_ref,kmcndi_ref,rhoi_ref + use dimensions_mod, only: nu_t_lev use control_mod, only: nu, nu_t, hypervis_subcycle,hypervis_subcycle_sponge, nu_p, nu_top - use control_mod, only: molecular_diff + use control_mod, only: molecular_diff,sponge_del4_lev use hybrid_mod, only: hybrid_t!, get_loop_ranges use element_mod, only: element_t use derivative_mod, only: derivative_t, laplace_sphere_wk, vlaplace_sphere_wk, vlaplace_sphere_wk_mol @@ -510,14 +505,13 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, use viscosity_mod, only: biharmonic_wk_dp3d use hybvcoord_mod, only: hvcoord_t use fvm_control_volume_mod, only: fvm_struct - use air_composition, only: thermodynamic_active_species_idx_dycore - use dyn_thermo, only: get_molecular_diff_coef,get_rho_dry -!Un-comment once history output has been resolved in CAMDEN -JN: + use air_composition, only: thermodynamic_active_species_idx_dycore +!Un-comment once constituents and history outputs are enabled -JN: ! use cam_history, only: outfld, hist_fld_active type (hybrid_t) , intent(in) :: hybrid type (element_t) , intent(inout), target :: elem(:) - type(fvm_struct) , intent(in) :: fvm(:) + type(fvm_struct) , intent(inout) :: fvm(:) type (EdgeBuffer_t), intent(inout):: edge3 type (derivative_t), intent(in ) :: deriv integer , intent(in) :: nets,nete, nt, qn0 @@ -530,8 +524,6 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, integer :: kbeg, kend, kblk real (kind=r8), dimension(np,np,2,nlev,nets:nete) :: vtens real (kind=r8), dimension(np,np,nlev,nets:nete) :: ttens, dptens - real (kind=r8), dimension(np,np,nlev,nets:nete) :: dp3d_ref, T_ref - real (kind=r8), dimension(np,np,nets:nete) :: ps_ref real (kind=r8), dimension(0:np+1,0:np+1,nlev) :: corners real (kind=r8), dimension(2,2,2) :: cflux real (kind=r8) :: temp (np,np,nlev) @@ -540,60 +532,19 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, type (EdgeDescriptor_t) :: desc real (kind=r8), dimension(np,np) :: lap_t,lap_dp - real (kind=r8), dimension(np,np) :: tmp, tmp2 real (kind=r8), dimension(np,np,ksponge_end,nets:nete):: kmvis,kmcnd,rho_dry - real (kind=r8), dimension(np,np,ksponge_end+1):: kmvisi,kmcndi - real (kind=r8), dimension(np,np,ksponge_end+1):: pint,rhoi_dry - real (kind=r8), dimension(np,np,ksponge_end ):: pmid real (kind=r8), dimension(np,np,nlev) :: tmp_kmvis,tmp_kmcnd real (kind=r8), dimension(np,np,2) :: lap_v - real (kind=r8) :: v1,v2,v1new,v2new,dt,heating,T0,T1 + real (kind=r8) :: v1,v2,v1new,v2new,dt,heating real (kind=r8) :: laplace_fluxes(nc,nc,4) real (kind=r8) :: rhypervis_subcycle real (kind=r8) :: nu_ratio1, ptop, inv_rho - real (kind=r8), dimension(ksponge_end) :: dtemp,du,dv real (kind=r8) :: nu_temp, nu_dp, nu_velo if (nu_t == 0 .and. nu == 0 .and. nu_p==0 ) return; ptop = hvcoord%hyai(1)*hvcoord%ps0 - if (hypervis_dynamic_ref_state) then - ! - ! use dynamic reference pressure (P. Callaghan) - ! - call calc_dp3d_reference(elem,edge3,hybrid,nets,nete,nt,hvcoord,dp3d_ref) - do ie=nets,nete - ps_ref(:,:,ie) = ptop + sum(elem(ie)%state%dp3d(:,:,:,nt),3) - end do - else - ! - ! use static reference pressure (hydrostatic balance incl. effect of topography) - ! - do ie=nets,nete - call get_dp_ref(hvcoord%hyai, hvcoord%hybi, hvcoord%ps0,& - elem(ie)%state%phis(:,:),dp3d_ref(:,:,:,ie),ps_ref(:,:,ie)) - end do - endif - ! - ! reference temperature profile (Simmons and Jiabin, 1991, QJRMS, Section 2a) - ! - ! Tref = T0+T1*Exner - ! T1 = .0065*Tref*Cp/g ! = ~191 - ! T0 = Tref-T1 ! = ~97 - ! - T1 = lapse_rate*Tref*cpair/gravit - T0 = Tref-T1 - do ie=nets,nete - do k=1,nlev - dp3d_ref(:,:,k,ie) = ((hvcoord%hyai(k+1)-hvcoord%hyai(k))*hvcoord%ps0 + & - (hvcoord%hybi(k+1)-hvcoord%hybi(k))*ps_ref(:,:,ie)) - tmp = hvcoord%hyam(k)*hvcoord%ps0+hvcoord%hybm(k)*ps_ref(:,:,ie) - tmp2 = (tmp/hvcoord%ps0)**cappa - T_ref(:,:,k,ie) = (T0+T1*tmp2) - end do - end do - kbeg=1; kend=nlev kblk = kend - kbeg + 1 @@ -605,11 +556,10 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! do ic=1,hypervis_subcycle - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dBH') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dBH') rhypervis_subcycle=1.0_r8/real(hypervis_subcycle,kind=r8) - call biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid,nt,nets,nete,kbeg,kend,& - dp3d_ref,T_ref) + call biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid,nt,nets,nete,kbeg,kend) do ie=nets,nete ! compute mean flux @@ -620,7 +570,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, do j=1,np do i=1,np elem(ie)%derived%dpdiss_ave(i,j,k)=elem(ie)%derived%dpdiss_ave(i,j,k)+& - rhypervis_subcycle*eta_ave_w*elem(ie)%state%dp3d(i,j,k,nt) + rhypervis_subcycle*eta_ave_w*(elem(ie)%state%dp3d(i,j,k,nt)-elem(ie)%derived%dp_ref(i,j,k)) elem(ie)%derived%dpdiss_biharmonic(i,j,k)=elem(ie)%derived%dpdiss_biharmonic(i,j,k)+& rhypervis_subcycle*eta_ave_w*dptens(i,j,k,ie) enddo @@ -637,7 +587,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, !DIR_VECTOR_ALIGNED do j=1,np do i=1,np - ttens(i,j,k,ie) = -nu_t*ttens(i,j,k,ie) + ttens(i,j,k,ie) = -nu_t_lev(k)*ttens(i,j,k,ie) dptens(i,j,k,ie) = -nu_p*dptens(i,j,k,ie) vtens(i,j,1,k,ie) = -nu_lev(k)*vtens(i,j,1,k,ie) vtens(i,j,2,k,ie) = -nu_lev(k)*vtens(i,j,2,k,ie) @@ -766,10 +716,13 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, enddo end do - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dCH') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dCH') do ie=nets,nete !$omp parallel do num_threads(vert_num_threads), private(k,i,j,v1,v2,heating) - do k=kbeg,kend + do k=sponge_del4_lev+2,nlev + ! + ! only do "frictional heating" away from sponge + ! !OMP_COLLAPSE_SIMD !DIR_VECTOR_ALIGNED do j=1,np @@ -786,7 +739,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, enddo enddo enddo - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dAH') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dAH') end do ! @@ -795,7 +748,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, ! sponge layer damping ! !*************************************************************** - + ! call t_startf('sponge_diff') ! ! compute coefficients for horizontal diffusion @@ -803,8 +756,8 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, if (molecular_diff==1) then do ie=nets,nete call get_rho_dry(elem(ie)%state%Qdp(:,:,:,1:qsize,qn0), & - elem(ie)%state%T(:,:,:,nt),ptop,elem(ie)%state%dp3d(:,:,:,nt),& - .true.,rho_dry=rho_dry(:,:,:,ie), & + elem(ie)%state%T(:,:,:,nt), ptop, elem(ie)%state%dp3d(:,:,:,nt),& + .true., rho_dry=rho_dry(:,:,:,ie), & active_species_idx_dycore=thermodynamic_active_species_idx_dycore) end do @@ -812,8 +765,8 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, ! ! compute molecular diffusion and thermal conductivity coefficients at mid-levels ! - call get_molecular_diff_coef(elem(ie)%state%T(:,:,:,nt),.false.,km_sponge_factor(1:ksponge_end),kmvis(:,:,:,ie),kmcnd(:,:,:,ie),qsize,& - elem(ie)%state%Qdp(:,:,:,1:qsize,qn0),fact=1.0_r8/elem(ie)%state%dp3d(:,:,1:ksponge_end,nt),& + call get_molecular_diff_coef(elem(ie)%state%T(:,:,:,nt), .false., km_sponge_factor(1:ksponge_end), kmvis(:,:,:,ie),& + kmcnd(:,:,:,ie), elem(ie)%state%Qdp(:,:,:,1:qsize,qn0), fact=1.0_r8/elem(ie)%state%dp3d(:,:,1:ksponge_end,nt),& active_species_idx_dycore=thermodynamic_active_species_idx_dycore) end do ! @@ -848,7 +801,7 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, call outfld('nu_kmcnd_dp',RESHAPE(tmp_kmcnd(:,:,:), (/npsq,nlev/)), npsq, ie) end do end if -#endif + ! ! scale by reference value ! @@ -858,18 +811,19 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, kmvis(:,:,k,ie) = kmvis(:,:,k,ie)/kmvis_ref(k) end do end do +#endif end if ! ! Horizontal Laplacian diffusion ! dt=dt2/hypervis_subcycle_sponge - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dBS') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dBS') kblk = ksponge_end do ic=1,hypervis_subcycle_sponge rhypervis_subcycle=1.0_r8/real(hypervis_subcycle_sponge,kind=r8) do ie=nets,nete do k=1,ksponge_end - if (nu_top>0.or.molecular_diff>0) then + if (nu_top>0.or.molecular_diff>1) then !************************************************************** ! ! traditional sponge formulation (constant coefficients) @@ -1018,42 +972,42 @@ subroutine advance_hypervis_dp(edge3,elem,fvm,hybrid,deriv,nt,qn0,nets,nete,dt2, vtens(i,j,2,k,ie)=dt*vtens(i,j,2,k,ie)*elem(ie)%rspheremp(i,j) ttens(i,j,k,ie)=dt*ttens(i,j,k,ie)*elem(ie)%rspheremp(i,j) elem(ie)%state%dp3d(i,j,k,nt)=elem(ie)%state%dp3d(i,j,k,nt)*elem(ie)%rspheremp(i,j) + ! update v first (gives better results than updating v after heating) + elem(ie)%state%v(i,j,:,k,nt)=elem(ie)%state%v(i,j,:,k,nt) + vtens(i,j,:,k,ie) + elem(ie)%state%T(i,j, k,nt)=elem(ie)%state%T(i,j, k,nt) + ttens(i,j, k,ie) enddo enddo enddo - !$omp parallel do num_threads(vert_num_threads) private(k,i,j,v1,v2,v1new,v2new) - do k=1,ksponge_end - !OMP_COLLAPSE_SIMD - !DIR_VECTOR_ALIGNED - do j=1,np - do i=1,np - ! update v first (gives better results than updating v after heating) - elem(ie)%state%v(i,j,:,k,nt)=elem(ie)%state%v(i,j,:,k,nt) + & - vtens(i,j,:,k,ie) - elem(ie)%state%T(i,j,k,nt)=elem(ie)%state%T(i,j,k,nt) & - +ttens(i,j,k,ie) - - v1new=elem(ie)%state%v(i,j,1,k,nt) - v2new=elem(ie)%state%v(i,j,2,k,nt) - v1 =elem(ie)%state%v(i,j,1,k,nt)- vtens(i,j,1,k,ie) - v2 =elem(ie)%state%v(i,j,2,k,nt)- vtens(i,j,2,k,ie) - ! - ! frictional heating - ! - heating = 0.5_r8*(v1new*v1new+v2new*v2new-(v1*v1+v2*v2)) - elem(ie)%state%T(i,j,k,nt)=elem(ie)%state%T(i,j,k,nt) & - -heating*inv_cp_full(i,j,k,ie) + if (molecular_diff.ne.1) then + ! + ! no frictional heating for artificial sponge + ! + !$omp parallel do num_threads(vert_num_threads) private(k,i,j,v1,v2,v1new,v2new) + do k=1,ksponge_end + !OMP_COLLAPSE_SIMD + !DIR_VECTOR_ALIGNED + do j=1,np + do i=1,np + v1new=elem(ie)%state%v(i,j,1,k,nt) + v2new=elem(ie)%state%v(i,j,2,k,nt) + v1 =elem(ie)%state%v(i,j,1,k,nt)- vtens(i,j,1,k,ie) + v2 =elem(ie)%state%v(i,j,2,k,nt)- vtens(i,j,2,k,ie) + ! + ! frictional heating + ! + heating = 0.5_r8*(v1new*v1new+v2new*v2new-(v1*v1+v2*v2)) + elem(ie)%state%T(i,j,k,nt)=elem(ie)%state%T(i,j,k,nt) & + -heating*inv_cp_full(i,j,k,ie) + enddo enddo enddo - enddo + end if end do end do call t_stopf('sponge_diff') - call calc_tot_energy_dynamics(elem,fvm,nets,nete,nt,qn0,'dAS') + call tot_energy_dyn(elem,fvm,nets,nete,nt,qn0,'dAS') end subroutine advance_hypervis_dp - - subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& deriv,nets,nete,eta_ave_w,inv_cp_full,qwater,qidx,kappa) ! =================================== @@ -1075,15 +1029,8 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& ! allows us to fuse these two loops for more cache reuse ! ! =================================== - use air_composition, only: thermodynamic_active_species_num - use air_composition, only: thermodynamic_active_species_idx_dycore - use air_composition, only: dry_air_species_num - use dyn_thermo, only: get_gz_given_dp_Tv_Rdry - use dyn_thermo, only: get_virtual_temp, get_cp_dry - use dyn_thermo, only: get_R_dry - - !SE dycore: - use dimensions_mod, only: np, nc, nlev, use_cslam, ksponge_end + use dimensions_mod, only: np, nc, nlev, use_cslam + use control_mod, only: pgf_formulation use hybrid_mod, only: hybrid_t use element_mod, only: element_t use derivative_mod, only: derivative_t, divergence_sphere, gradient_sphere, vorticity_sphere @@ -1092,7 +1039,10 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& use edgetype_mod, only: edgedescriptor_t use bndry_mod, only: bndry_exchange use hybvcoord_mod, only: hvcoord_t - use time_mod, only: tevolve + use cam_thermo, only: get_gz, get_virtual_temp + use air_composition, only: thermodynamic_active_species_num, dry_air_species_num + use air_composition, only: get_cp_dry, get_R_dry + use physconst, only: tref,cpair,rga,lapse_rate implicit none integer, intent(in) :: np1,nm1,n0,nets,nete @@ -1123,11 +1073,9 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& real (kind=r8), dimension(np,np) :: vgrad_T ! v.grad(T) real (kind=r8), dimension(np,np) :: Ephi ! kinetic energy + PHI term real (kind=r8), dimension(np,np,2,nlev) :: grad_p_full - real (kind=r8), dimension(np,np,2,nlev) :: grad_p_m_pmet! gradient(p - p_met) real (kind=r8), dimension(np,np,nlev) :: vort ! vorticity - real (kind=r8), dimension(np,np,nlev) :: p_dry ! pressure dry real (kind=r8), dimension(np,np,nlev) :: dp_dry ! delta pressure dry - real (kind=r8), dimension(np,np,nlev) :: R_dry + real (kind=r8), dimension(np,np,nlev) :: R_dry, cp_dry! real (kind=r8), dimension(np,np,nlev) :: p_full ! pressure real (kind=r8), dimension(np,np,nlev) :: dp_full real (kind=r8), dimension(np,np) :: exner @@ -1137,17 +1085,17 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& real (kind=r8) :: vtens1(np,np,nlev),vtens2(np,np,nlev),ttens(np,np,nlev) real (kind=r8) :: stashdp3d (np,np,nlev),tempdp3d(np,np), tempflux(nc,nc,4) real (kind=r8) :: ckk, term, T_v(np,np,nlev) - real (kind=r8), dimension(np,np,2) :: grad_exner + real (kind=r8), dimension(np,np,2) :: pgf_term + real (kind=r8), dimension(np,np,2) :: grad_exner,grad_logexner + real (kind=r8) :: T0,T1 real (kind=r8), dimension(np,np) :: theta_v - real (kind=r8), dimension(np,np,nlev) :: cp_dry - type (EdgeDescriptor_t):: desc real (kind=r8) :: sum_water(np,np,nlev), density_inv(np,np) real (kind=r8) :: E,v1,v2,glnps1,glnps2 integer :: i,j,k,kptr,ie - real (kind=r8) :: u_m_umet, v_m_vmet, t_m_tmet, ptop + real (kind=r8) :: ptop !JMD call t_barrierf('sync_compute_and_apply_rhs', hybrid%par%comm) call t_adj_detailf(+1) @@ -1157,17 +1105,16 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& ! ! compute virtual temperature and sum_water ! - call get_virtual_temp(qwater(:,:,:,:,ie),& - t_v(:,:,:),temp=elem(ie)%state%T(:,:,:,n0),sum_q =sum_water(:,:,:),& - active_species_idx_dycore=qidx) - call get_R_dry(qwater(:,:,:,:,ie),qidx,R_dry) - call get_cp_dry(qwater(:,:,:,:,ie),qidx,cp_dry) + call get_virtual_temp(qwater(:,:,:,:,ie), t_v(:,:,:),temp=elem(ie)%state%T(:,:,:,n0),& + sum_q =sum_water(:,:,:), active_species_idx_dycore=qidx) + call get_R_dry(qwater(:,:,:,:,ie), qidx, R_dry) + call get_cp_dry(qwater(:,:,:,:,ie), qidx, cp_dry) do k=1,nlev dp_dry(:,:,k) = elem(ie)%state%dp3d(:,:,k,n0) dp_full(:,:,k) = sum_water(:,:,k)*dp_dry(:,:,k) end do - call get_gz_given_dp_Tv_Rdry(dp_full,T_v,R_dry,elem(ie)%state%phis,ptop,phi,pmid=p_full) + call get_gz(dp_full, T_v, R_dry, elem(ie)%state%phis, ptop, phi, pmid=p_full) do k=1,nlev ! vertically lagrangian code: we advect dp3d instead of ps ! we also need grad(p) at all levels (not just grad(ps)) @@ -1283,32 +1230,53 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& ! vtemp = gradient_sphere(Ephi(:,:),deriv,elem(ie)%Dinv) call gradient_sphere(Ephi(:,:),deriv,elem(ie)%Dinv,vtemp) density_inv(:,:) = R_dry(:,:,k)*T_v(:,:,k)/p_full(:,:,k) - - if (dry_air_species_num==0) then - exner(:,:)=(p_full(:,:,k)/hvcoord%ps0)**kappa(:,:,k,ie) - theta_v(:,:)=T_v(:,:,k)/exner(:,:) - call gradient_sphere(exner(:,:),deriv,elem(ie)%Dinv,grad_exner) - - grad_exner(:,:,1) = real(cp_dry(:,:,k), r8)*theta_v(:,:)*grad_exner(:,:,1) - grad_exner(:,:,2) = real(cp_dry(:,:,k), r8)*theta_v(:,:)*grad_exner(:,:,2) + if (ie==1) write(*,*) "xxx pgf_formulation",pgf_formulation + if (pgf_formulation==1.or.(pgf_formulation==3.and.hvcoord%hybm(k)>0._r8)) then + if (dry_air_species_num==0) then + exner(:,:)=(p_full(:,:,k)/hvcoord%ps0)**kappa(:,:,k,ie) + theta_v(:,:)=T_v(:,:,k)/exner(:,:) + call gradient_sphere(exner(:,:),deriv,elem(ie)%Dinv,grad_exner) + pgf_term(:,:,1) = cp_dry(:,:,k)*theta_v(:,:)*grad_exner(:,:,1) + pgf_term(:,:,2) = cp_dry(:,:,k)*theta_v(:,:)*grad_exner(:,:,2) + else + exner(:,:)=(p_full(:,:,k)/hvcoord%ps0)**kappa(:,:,k,ie) + theta_v(:,:)=T_v(:,:,k)/exner(:,:) + call gradient_sphere(exner(:,:),deriv,elem(ie)%Dinv,grad_exner) + call gradient_sphere(kappa(:,:,k,ie),deriv,elem(ie)%Dinv,grad_kappa_term) + suml = exner(:,:)*LOG(p_full(:,:,k)/hvcoord%ps0) + grad_kappa_term(:,:,1)=-suml*grad_kappa_term(:,:,1) + grad_kappa_term(:,:,2)=-suml*grad_kappa_term(:,:,2) + pgf_term(:,:,1) = cp_dry(:,:,k)*theta_v(:,:)*(grad_exner(:,:,1)+grad_kappa_term(:,:,1)) + pgf_term(:,:,2) = cp_dry(:,:,k)*theta_v(:,:)*(grad_exner(:,:,2)+grad_kappa_term(:,:,2)) + end if + ! balanced ref profile correction: + ! reference temperature profile (Simmons and Jiabin, 1991, QJRMS, Section 2a) + ! + ! Tref = T0+T1*Exner + ! T1 = .0065*Tref*Cp/g ! = ~191 + ! T0 = Tref-T1 ! = ~97 + ! + T1 = lapse_rate*Tref*cpair*rga + T0 = Tref-T1 + if (hvcoord%hybm(k)>0) then + !only apply away from constant pressure levels + call gradient_sphere(log(exner(:,:)),deriv,elem(ie)%Dinv,grad_logexner) + pgf_term(:,:,1)=pgf_term(:,:,1) + & + cpair*T0*(grad_logexner(:,:,1)-grad_exner(:,:,1)/exner(:,:)) + pgf_term(:,:,2)=pgf_term(:,:,2) + & + cpair*T0*(grad_logexner(:,:,2)-grad_exner(:,:,2)/exner(:,:)) + end if + elseif (pgf_formulation==2.or.pgf_formulation==3) then + pgf_term(:,:,1) = density_inv(:,:)*grad_p_full(:,:,1,k) + pgf_term(:,:,2) = density_inv(:,:)*grad_p_full(:,:,2,k) else - exner(:,:)=(p_full(:,:,k)/hvcoord%ps0)**kappa(:,:,k,ie) - theta_v(:,:)=T_v(:,:,k)/exner(:,:) - call gradient_sphere(exner(:,:),deriv,elem(ie)%Dinv,grad_exner) - - call gradient_sphere(kappa(:,:,k,ie),deriv,elem(ie)%Dinv,grad_kappa_term) - suml = exner(:,:)*LOG(p_full(:,:,k)/hvcoord%ps0) - grad_kappa_term(:,:,1)=-suml*grad_kappa_term(:,:,1) - grad_kappa_term(:,:,2)=-suml*grad_kappa_term(:,:,2) - - grad_exner(:,:,1) = real(cp_dry(:,:,k), r8)*theta_v(:,:)*(grad_exner(:,:,1)+grad_kappa_term(:,:,1)) - grad_exner(:,:,2) = real(cp_dry(:,:,k), r8)*theta_v(:,:)*(grad_exner(:,:,2)+grad_kappa_term(:,:,2)) + call endrun('ERROR: bad choice of pgf_formulation (must be 1, 2, or 3)') end if do j=1,np do i=1,np - glnps1 = grad_exner(i,j,1) - glnps2 = grad_exner(i,j,2) + glnps1 = pgf_term(i,j,1) + glnps2 = pgf_term(i,j,2) v1 = elem(ie)%state%v(i,j,1,k,n0) v2 = elem(ie)%state%v(i,j,2,k,n0) @@ -1456,7 +1424,6 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& call t_adj_detailf(-1) end subroutine compute_and_apply_rhs - ! ! corner fluxes for CSLAM ! @@ -1521,40 +1488,53 @@ subroutine distribute_flux_at_corners(cflux, corners, getmapP) cflux(2,2,2) = (corners(np ,np+1) - corners(np,np )) endif end subroutine distribute_flux_at_corners -!xxx tot_energy_dyn not merged in yet - subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suffix) - use dynconst, only: gravit, cpair, rearth, omega - use dyn_thermo, only: get_dp, get_cp - use cam_thermo, only: MASS_MIXING_RATIO - use air_composition, only: thermodynamic_active_species_idx_dycore - use hycoef, only: hyai, ps0 - use string_utils, only: strlist_get_ind -!Un-comment once constituents and history outputs are enabled -JN: -! use cam_history, only: outfld, hist_fld_active -! use constituents, only: cnst_get_ind - !SE dycore: + subroutine tot_energy_dyn(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suffix) + use dimensions_mod, only: npsq,nlev,np,nc,use_cslam,qsize + use physconst, only: rga, rearth, omega use element_mod, only: element_t - use dimensions_mod, only: npsq,nlev,np,nc,ntrac,qsize +!Un-comment once constituents and history outputs are enabled -JN: +! use cam_history, only: outfld +! use cam_history_support, only: max_fieldname_len +! use constituents, only: cnst_get_ind + use string_utils, only: strlist_get_ind + use hycoef, only: hyai, ps0 use fvm_control_volume_mod, only: fvm_struct + use cam_thermo, only: get_dp, MASS_MIXING_RATIO +! ,wvidx,wlidx,wiidx,seidx,keidx,moidx,mridx,ttidx,teidx, & +! poidx,thermo_budget_num_vars,thermo_budget_vars + use cam_thermo, only: get_hydrostatic_energy + use air_composition, only: thermodynamic_active_species_idx_dycore, get_cp + use air_composition, only: thermodynamic_active_species_num, thermodynamic_active_species_idx_dycore + use air_composition, only: thermodynamic_active_species_liq_num,thermodynamic_active_species_liq_idx + use air_composition, only: thermodynamic_active_species_ice_num,thermodynamic_active_species_ice_idx use dimensions_mod, only: cnst_name_gll + use dyn_tests_utils, only: vcoord=>vc_dry_pressure +! use cam_budget, only: thermo_budget_history !------------------------------Arguments-------------------------------- - type (element_t) , intent(in) :: elem(:) - type(fvm_struct) , intent(in) :: fvm(:) + type (element_t) , intent(inout) :: elem(:) + type(fvm_struct) , intent(inout) :: fvm(:) integer , intent(in) :: tl, tl_qdp,nets,nete character*(*) , intent(in) :: outfld_name_suffix ! suffix for "outfld" names !---------------------------Local storage------------------------------- - real(kind=r8) :: se(npsq) ! Dry Static energy (J/m2) - real(kind=r8) :: ke(npsq) ! kinetic energy (J/m2) + real(kind=r8) :: se(np,np) ! Enthalpy energy (J/m2) + real(kind=r8) :: ke(np,np) ! kinetic energy (J/m2) + real(kind=r8) :: po(np,np) ! PHIS term in energy equation (J/m2) + real(kind=r8) :: wv(np,np) ! water vapor + real(kind=r8) :: liq(np,np) ! liquid + real(kind=r8) :: ice(np,np) ! ice + real(kind=r8) :: q(np,nlev,qsize) + integer :: qidx(thermodynamic_active_species_num) real(kind=r8) :: cdp_fvm(nc,nc,nlev) - real(kind=r8) :: se_tmp - real(kind=r8) :: ke_tmp - real(kind=r8) :: ps(np,np) + real(kind=r8) :: cdp(np,np,nlev) + real(kind=r8) :: ptop(np,np) real(kind=r8) :: pdel(np,np,nlev) + real(kind=r8) :: cp(np,np,nlev) + ! ! global axial angular momentum (AAM) can be separated into one part (mr) associatedwith the relative motion ! of the atmosphere with respect to the planets surface (also known as wind AAM) and another part (mo) @@ -1565,26 +1545,17 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf real(kind=r8) :: mo(npsq) ! mass AAM real(kind=r8) :: mr_cnst, mo_cnst, cos_lat, mr_tmp, mo_tmp - real(kind=r8) :: cp(np,np,nlev) - - integer :: ie,i,j,k + integer :: ie,i,j,k,m_cnst,nq,idx integer :: ixwv,ixcldice, ixcldliq, ixtt ! CLDICE, CLDLIQ and test tracer indices - character(len=16) :: name_out1,name_out2,name_out3,name_out4,name_out5,name_out6 - - !----------------------------------------------------------------------- - !Un-comment once history outputs are enabled -JN: #if 0 + character(len=max_fieldname_len) :: name_out(thermo_budget_num_vars) - name_out1 = 'SE_' //trim(outfld_name_suffix) - name_out2 = 'KE_' //trim(outfld_name_suffix) - name_out3 = 'WV_' //trim(outfld_name_suffix) - name_out4 = 'WL_' //trim(outfld_name_suffix) - name_out5 = 'WI_' //trim(outfld_name_suffix) - name_out6 = 'TT_' //trim(outfld_name_suffix) - - if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2).or.hist_fld_active(name_out3).or.& - hist_fld_active(name_out4).or.hist_fld_active(name_out5).or.hist_fld_active(name_out6)) then + !----------------------------------------------------------------------- + if (thermo_budget_history) then + do i=1,thermo_budget_num_vars + name_out(i)=trim(thermo_budget_vars(i))//'_'//trim(outfld_name_suffix) + end do if (use_cslam) then ixwv = 1 @@ -1602,72 +1573,104 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf ! ! Compute frozen static energy in 3 parts: KE, SE, and energy associated with vapor and liquid ! + do nq=1,thermodynamic_active_species_num + qidx(nq) = nq + end do do ie=nets,nete - se = 0.0_r8 - ke = 0.0_r8 - call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,tl_qdp),MASS_MIXING_RATIO,thermodynamic_active_species_idx_dycore,& - elem(ie)%state%dp3d(:,:,:,tl),pdel,ps=ps,ptop=hyai(1)*ps0) call get_cp(elem(ie)%state%Qdp(:,:,:,1:qsize,tl_qdp),& - .false.,cp,dp_dry=elem(ie)%state%dp3d(:,:,:,tl),& + .false., cp, factor=1.0_r8/elem(ie)%state%dp3d(:,:,:,tl),& active_species_idx_dycore=thermodynamic_active_species_idx_dycore) - do k = 1, nlev - do j=1,np - do i = 1, np - ! - ! kinetic energy - ! - ke_tmp = 0.5_r8*(elem(ie)%state%v(i,j,1,k,tl)**2+ elem(ie)%state%v(i,j,2,k,tl)**2)*pdel(i,j,k)/gravit - se_tmp = cp(i,j,k)*elem(ie)%state%T(i,j,k,tl)*pdel(i,j,k)/gravit - se (i+(j-1)*np) = se (i+(j-1)*np) + se_tmp - ke (i+(j-1)*np) = ke (i+(j-1)*np) + ke_tmp - end do - end do - end do - + ptop = hyai(1)*ps0 do j=1,np - do i = 1, np - se(i+(j-1)*np) = se(i+(j-1)*np) + elem(ie)%state%phis(i,j)*ps(i,j)/gravit + !get mixing ratio of thermodynamic active species only + !(other tracers not used in get_hydrostatic_energy) + do nq=1,thermodynamic_active_species_num + m_cnst = thermodynamic_active_species_idx_dycore(nq) + q(:,:,m_cnst) = elem(ie)%state%Qdp(:,j,:,m_cnst,tl_qdp)/& + elem(ie)%state%dp3d(:,j,:,tl) end do + call get_hydrostatic_energy(q, & + .false., elem(ie)%state%dp3d(:,j,:,tl), cp(:,j,:), elem(ie)%state%v(:,j,1,:,tl), & + elem(ie)%state%v(:,j,2,:,tl), elem(ie)%state%T(:,j,:,tl), vcoord, ptop=ptop(:,j),& + phis=elem(ie)%state%phis(:,j), dycore_idx=.true., & + se=se(:,j), po=po(:,j), ke=ke(:,j), wv=wv(:,j), liq=liq(:,j), ice=ice(:,j)) end do ! ! Output energy diagnostics on GLL grid ! - call outfld(name_out1 ,se ,npsq,ie) - call outfld(name_out2 ,ke ,npsq,ie) + call outfld(name_out(poidx) ,po ,npsq,ie) + call outfld(name_out(seidx) ,se ,npsq,ie) + call outfld(name_out(keidx) ,ke ,npsq,ie) + call outfld(name_out(teidx) ,ke+se+po ,npsq,ie) ! ! mass variables are output on CSLAM grid if using CSLAM else GLL grid ! if (use_cslam) then - if (ixwv>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixwv)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out3,ie) - end if - if (ixcldliq>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixcldliq)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out4,ie) - end if - if (ixcldice>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixcldice)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out5,ie) - end if - if (ixtt>0) then - cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixtt)*fvm(ie)%dp_fvm(1:nc,1:nc,:) - call util_function(cdp_fvm,nc,nlev,name_out6,ie) - end if + if (ixwv>0) then + cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixwv)*fvm(ie)%dp_fvm(1:nc,1:nc,:) + call util_function(cdp_fvm,nc,nlev,name_out(wvidx),ie) + end if + ! + ! sum over liquid water + ! + if (thermodynamic_active_species_liq_num>0) then + cdp_fvm = 0.0_r8 + do nq = 1,thermodynamic_active_species_liq_num + cdp_fvm = cdp_fvm + fvm(ie)%c(1:nc,1:nc,:,thermodynamic_active_species_liq_idx(nq))& + *fvm(ie)%dp_fvm(1:nc,1:nc,:) + end do + call util_function(cdp_fvm,nc,nlev,name_out(wlidx),ie) + end if + ! + ! sum over ice water + ! + if (thermodynamic_active_species_ice_num>0) then + cdp_fvm = 0.0_r8 + do nq = 1,thermodynamic_active_species_ice_num + cdp_fvm = cdp_fvm + fvm(ie)%c(1:nc,1:nc,:,thermodynamic_active_species_ice_idx(nq))& + *fvm(ie)%dp_fvm(1:nc,1:nc,:) + end do + call util_function(cdp_fvm,nc,nlev,name_out(wiidx),ie) + end if + if (ixtt>0) then + cdp_fvm = fvm(ie)%c(1:nc,1:nc,:,ixtt)*fvm(ie)%dp_fvm(1:nc,1:nc,:) + call util_function(cdp_fvm,nc,nlev,name_out(ttidx),ie) + end if else - call util_function(elem(ie)%state%qdp(:,:,:,1 ,tl_qdp),np,nlev,name_out3,ie) - if (ixcldliq>0) call util_function(elem(ie)%state%qdp(:,:,:,ixcldliq,tl_qdp),np,nlev,name_out4,ie) - if (ixcldice>0) call util_function(elem(ie)%state%qdp(:,:,:,ixcldice,tl_qdp),np,nlev,name_out5,ie) - if (ixtt>0 ) call util_function(elem(ie)%state%qdp(:,:,:,ixtt ,tl_qdp),np,nlev,name_out6,ie) + cdp = elem(ie)%state%qdp(:,:,:,1,tl_qdp) + call util_function(cdp,np,nlev,name_out(wvidx),ie) + ! + ! sum over liquid water + ! + if (thermodynamic_active_species_liq_num>0) then + cdp = 0.0_r8 + do idx = 1,thermodynamic_active_species_liq_num + cdp = cdp + elem(ie)%state%qdp(:,:,:,thermodynamic_active_species_liq_idx(idx),tl_qdp) + end do + call util_function(cdp,np,nlev,name_out(wlidx),ie) + end if + ! + ! sum over ice water + ! + if (thermodynamic_active_species_ice_num>0) then + cdp = 0.0_r8 + do idx = 1,thermodynamic_active_species_ice_num + cdp = cdp + elem(ie)%state%qdp(:,:,:,thermodynamic_active_species_ice_idx(idx),tl_qdp) + end do + call util_function(cdp,np,nlev,name_out(wiidx),ie) + end if + if (ixtt>0) then + cdp = elem(ie)%state%qdp(:,:,:,ixtt ,tl_qdp) + call util_function(cdp,np,nlev,name_out(ttidx),ie) + end if end if - end do - end if - ! - ! Axial angular momentum diagnostics - ! - ! Code follows - ! - ! Lauritzen et al., (2014): Held-Suarez simulations with the Community Atmosphere Model + end do + ! + ! Axial angular momentum diagnostics + ! + ! Code follows + ! + ! Lauritzen et al., (2014): Held-Suarez simulations with the Community Atmosphere Model ! Spectral Element (CAM-SE) dynamical core: A global axial angularmomentum analysis using Eulerian ! and floating Lagrangian vertical coordinates. J. Adv. Model. Earth Syst. 6,129-140, ! doi:10.1002/2013MS000268 @@ -1675,19 +1678,16 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf ! MR is equation (6) without \Delta A and sum over areas (areas are in units of radians**2) ! MO is equation (7) without \Delta A and sum over areas (areas are in units of radians**2) ! - name_out1 = 'MR_' //trim(outfld_name_suffix) - name_out2 = 'MO_' //trim(outfld_name_suffix) - if ( hist_fld_active(name_out1).or.hist_fld_active(name_out2)) then call strlist_get_ind(cnst_name_gll, 'CLDLIQ', ixcldliq, abort=.false.) call strlist_get_ind(cnst_name_gll, 'CLDICE', ixcldice, abort=.false.) - mr_cnst = rearth**3/gravit - mo_cnst = omega*rearth**4/gravit + mr_cnst = rga*rearth**3 + mo_cnst = rga*omega*rearth**4 do ie=nets,nete mr = 0.0_r8 mo = 0.0_r8 - call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,tl_qdp),MASS_MIXING_RATIO,thermodynamic_active_species_idx_dycore,& - elem(ie)%state%dp3d(:,:,:,tl),pdel,ps=ps,ptop=hyai(1)*ps0) + call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,tl_qdp), MASS_MIXING_RATIO, thermodynamic_active_species_idx_dycore,& + elem(ie)%state%dp3d(:,:,:,tl), pdel) do k = 1, nlev do j=1,np do i = 1, np @@ -1700,14 +1700,12 @@ subroutine calc_tot_energy_dynamics(elem,fvm,nets,nete,tl,tl_qdp,outfld_name_suf end do end do end do - call outfld(name_out1 ,mr ,npsq,ie) - call outfld(name_out2 ,mo ,npsq,ie) + call outfld(name_out(mridx) ,mr ,npsq,ie) + call outfld(name_out(moidx) ,mo ,npsq,ie) end do - end if - + endif ! if thermo budget history #endif - - end subroutine calc_tot_energy_dynamics + end subroutine tot_energy_dyn subroutine output_qdp_var_dynamics(qdp,nx,num_trac,nets,nete,outfld_name) use dimensions_mod, only: nlev,ntrac @@ -1756,7 +1754,7 @@ end subroutine output_qdp_var_dynamics ! column integrate mass-variable and outfld ! subroutine util_function(f_in,nx,nz,name_out,ie) - use dynconst, only: gravit + use physconst, only: rga !Un-comment once history outputs are enabled -JN: ! use cam_history, only: outfld, hist_fld_active integer, intent(in) :: nx,nz,ie @@ -1764,12 +1762,10 @@ subroutine util_function(f_in,nx,nz,name_out,ie) character(len=16), intent(in) :: name_out real(kind=r8) :: f_out(nx*nx) integer :: i,j,k - real(kind=r8) :: inv_g !Un-comment once history outputs are enabled -JN: #if 0 if (hist_fld_active(name_out)) then f_out = 0.0_r8 - inv_g = 1.0_r8/gravit do k = 1, nz do j = 1, nx do i = 1, nx @@ -1777,21 +1773,21 @@ subroutine util_function(f_in,nx,nz,name_out,ie) end do end do end do - f_out = f_out*inv_g + f_out = f_out*rga call outfld(name_out,f_out,nx*nx,ie) end if #endif end subroutine util_function subroutine compute_omega(hybrid,n0,qn0,elem,deriv,nets,nete,dt,hvcoord) - use control_mod, only : nu_p, hypervis_subcycle - use dimensions_mod, only : np, nlev, qsize - use hybrid_mod, only : hybrid_t - use element_mod, only : element_t - use derivative_mod, only : divergence_sphere, derivative_t,gradient_sphere - use hybvcoord_mod, only : hvcoord_t - use edge_mod, only : edgevpack, edgevunpack - use bndry_mod, only : bndry_exchange + use control_mod, only: nu_p, hypervis_subcycle + use dimensions_mod, only: np, nlev, qsize + use hybrid_mod, only: hybrid_t + use element_mod, only: element_t + use derivative_mod, only: divergence_sphere, derivative_t,gradient_sphere + use hybvcoord_mod, only: hvcoord_t + use edge_mod, only: edgevpack, edgevunpack + use bndry_mod, only: bndry_exchange use viscosity_mod, only: biharmonic_wk_omega use air_composition,only: thermodynamic_active_species_num use air_composition,only: thermodynamic_active_species_idx_dycore @@ -1810,13 +1806,13 @@ subroutine compute_omega(hybrid,n0,qn0,elem,deriv,nets,nete,dt,hvcoord) real (kind=r8) :: dp_full(np,np,nlev) real (kind=r8) :: p_full(np,np,nlev),grad_p_full(np,np,2),vgrad_p_full(np,np,nlev) real (kind=r8) :: divdp_full(np,np,nlev),vdp_full(np,np,2) - real(kind=r8) :: Otens(np,np ,nlev,nets:nete), dt_hyper, sum_water(np,np,nlev) + real(kind=r8) :: Otens(np,np ,nlev,nets:nete), dt_hyper logical, parameter :: del4omega = .true. do ie=nets,nete - call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,qn0),MASS_MIXING_RATIO,& - thermodynamic_active_species_idx_dycore,elem(ie)%state%dp3d(:,:,:,n0),dp_full) + call get_dp(elem(ie)%state%Qdp(:,:,:,1:qsize,qn0), MASS_MIXING_RATIO,& + thermodynamic_active_species_idx_dycore, elem(ie)%state%dp3d(:,:,:,n0), dp_full) do k=1,nlev if (k==1) then p_full(:,:,k) = hvcoord%hyai(k)*hvcoord%ps0 + dp_full(:,:,k)/2 @@ -1898,292 +1894,4 @@ subroutine compute_omega(hybrid,n0,qn0,elem,deriv,nets,nete,dt,hvcoord) !call FreeEdgeBuffer(edgeOmega) end subroutine compute_omega - - subroutine calc_dp3d_reference(elem,edge3,hybrid,nets,nete,nt,hvcoord,dp3d_ref) - ! - ! calc_dp3d_reference: When the del^4 horizontal damping is applied to dp3d - ! the values are implicitly affected by natural variations - ! due to surface topography. - ! - ! To account for these physicaly correct variations, use - ! the current state values to compute appropriate - ! reference values for the current (lagrangian) ETA-surfaces. - ! Damping should then be applied to values relative to - ! this reference. - !======================================================================= - use hybvcoord_mod , only: hvcoord_t - use dynconst, only: rair, cappa - use element_mod, only: element_t - use dimensions_mod, only: np,nlev - use hybrid_mod, only: hybrid_t - use edge_mod, only: edgevpack, edgevunpack - use bndry_mod, only: bndry_exchange - ! - ! Passed variables - !------------------- - type(element_t ),target,intent(inout):: elem(:) - type(EdgeBuffer_t) ,intent(inout):: edge3 - type(hybrid_t ) ,intent(in ):: hybrid - integer ,intent(in ):: nets,nete - integer ,intent(in ):: nt - type(hvcoord_t ) ,intent(in ):: hvcoord - real(kind=r8) ,intent(out ):: dp3d_ref(np,np,nlev,nets:nete) - ! - ! Local Values - !-------------- - real(kind=r8):: Phis_avg(np,np, nets:nete) - real(kind=r8):: Phi_avg (np,np,nlev,nets:nete) - real(kind=r8):: RT_avg (np,np,nlev,nets:nete) - real(kind=r8):: P_val (np,np,nlev) - real(kind=r8):: Ps_val (np,np) - real(kind=r8):: Phi_val (np,np,nlev) - real(kind=r8):: Phi_ival(np,np) - real(kind=r8):: I_Phi (np,np,nlev+1) - real(kind=r8):: Alpha (np,np,nlev ) - real(kind=r8):: I_P (np,np,nlev+1) - real(kind=r8):: DP_avg (np,np,nlev) - real(kind=r8):: P_avg (np,np,nlev) - real(kind=r8):: Ps_avg (np,np) - real(kind=r8):: Ps_ref (np,np) - real(kind=r8):: RT_lapse(np,np) - real(kind=r8):: dlt_Ps (np,np) - real(kind=r8):: dPhi (np,np,nlev) - real(kind=r8):: dPhis (np,np) - real(kind=r8):: E_Awgt,E_phis,E_phi(nlev),E_T(nlev),Lapse0,Expon0 - integer :: ie,ii,jj,kk,kptr - - ! Loop over elements - !-------------------- - do ie=nets,nete - - ! Calculate Pressure values from dp3dp - !-------------------------------------- - P_val(:,:,1) = hvcoord%hyai(1)*hvcoord%ps0 + elem(ie)%state%dp3d(:,:,1,nt)*0.5_r8 - do kk=2,nlev - P_val(:,:,kk) = P_val(:,:,kk-1) & - + elem(ie)%state%dp3d(:,:,kk-1,nt)*0.5_r8 & - + elem(ie)%state%dp3d(:,:,kk ,nt)*0.5_r8 - end do - Ps_val(:,:) = P_val(:,:,nlev) + elem(ie)%state%dp3d(:,:,nlev,nt)*0.5_r8 - - ! Calculate (dry) geopotential values - !-------------------------------------- - dPhi (:,:,:) = 0.5_r8*(rair*elem(ie)%state%T (:,:,:,nt) & - *elem(ie)%state%dp3d(:,:,:,nt) & - /P_val(:,:,:) ) - Phi_val (:,:,nlev) = elem(ie)%state%phis(:,:) + dPhi(:,:,nlev) - Phi_ival(:,:) = elem(ie)%state%phis(:,:) + dPhi(:,:,nlev)*2._r8 - do kk=(nlev-1),1,-1 - Phi_val (:,:,kk) = Phi_ival(:,:) + dPhi(:,:,kk) - Phi_ival(:,:) = Phi_val (:,:,kk) + dPhi(:,:,kk) - end do - - ! Calculate Element averages - !---------------------------- - E_Awgt = 0.0_r8 - E_phis = 0.0_r8 - E_phi(:) = 0._r8 - E_T (:) = 0._r8 - do jj=1,np - do ii=1,np - E_Awgt = E_Awgt + elem(ie)%spheremp(ii,jj) - E_phis = E_phis + elem(ie)%spheremp(ii,jj)*elem(ie)%state%phis(ii,jj) - E_phi (:) = E_phi (:) + elem(ie)%spheremp(ii,jj)*Phi_val(ii,jj,:) - E_T (:) = E_T (:) + elem(ie)%spheremp(ii,jj)*elem(ie)%state%T(ii,jj,:,nt) - end do - end do - - Phis_avg(:,:,ie) = E_phis/E_Awgt - do kk=1,nlev - Phi_avg(:,:,kk,ie) = E_phi(kk) /E_Awgt - RT_avg (:,:,kk,ie) = E_T (kk)*rair/E_Awgt - end do - end do ! ie=nets,nete - - ! Boundary Exchange of average values - !------------------------------------- - do ie=nets,nete - Phis_avg(:,:,ie) = elem(ie)%spheremp(:,:)*Phis_avg(:,:,ie) - do kk=1,nlev - Phi_avg(:,:,kk,ie) = elem(ie)%spheremp(:,:)*Phi_avg(:,:,kk,ie) - RT_avg (:,:,kk,ie) = elem(ie)%spheremp(:,:)*RT_avg (:,:,kk,ie) - end do - kptr = 0 - call edgeVpack(edge3,Phi_avg(:,:,:,ie),nlev,kptr,ie) - kptr = nlev - call edgeVpack(edge3,RT_avg (:,:,:,ie),nlev,kptr,ie) - kptr = 2*nlev - call edgeVpack(edge3,Phis_avg (:,:,ie),1 ,kptr,ie) - end do ! ie=nets,nete - - call bndry_exchange(hybrid,edge3,location='calc_dp3d_reference') - - do ie=nets,nete - kptr = 0 - call edgeVunpack(edge3,Phi_avg(:,:,:,ie),nlev,kptr,ie) - kptr = nlev - call edgeVunpack(edge3,RT_avg (:,:,:,ie),nlev,kptr,ie) - kptr = 2*nlev - call edgeVunpack(edge3,Phis_avg (:,:,ie),1 ,kptr,ie) - Phis_avg(:,:,ie) = elem(ie)%rspheremp(:,:)*Phis_avg(:,:,ie) - do kk=1,nlev - Phi_avg(:,:,kk,ie) = elem(ie)%rspheremp(:,:)*Phi_avg(:,:,kk,ie) - RT_avg (:,:,kk,ie) = elem(ie)%rspheremp(:,:)*RT_avg (:,:,kk,ie) - end do - end do ! ie=nets,nete - - ! Loop over elements - !-------------------- - do ie=nets,nete - - ! Fill elements with uniformly varying average values - !----------------------------------------------------- - call fill_element(Phis_avg(1,1,ie)) - do kk=1,nlev - call fill_element(Phi_avg(1,1,kk,ie)) - call fill_element(RT_avg (1,1,kk,ie)) - end do - - ! Integrate upward to compute Alpha == (dp3d/P) - !---------------------------------------------- - I_Phi(:,:,nlev+1) = Phis_avg(:,:,ie) - do kk=nlev,1,-1 - I_Phi(:,:,kk) = 2._r8* Phi_avg(:,:,kk,ie) - I_Phi(:,:,kk+1) - Alpha(:,:,kk) = 2._r8*(Phi_avg(:,:,kk,ie) - I_Phi(:,:,kk+1))/RT_avg(:,:,kk,ie) - end do - - ! Integrate downward to compute corresponding average pressure values - !--------------------------------------------------------------------- - I_P(:,:,1) = hvcoord%hyai(1)*hvcoord%ps0 - do kk=1,nlev - DP_avg(:,:,kk ) = I_P(:,:,kk)*(2._r8 * Alpha(:,:,kk))/(2._r8 - Alpha(:,:,kk)) - P_avg (:,:,kk ) = I_P(:,:,kk)*(2._r8 )/(2._r8 - Alpha(:,:,kk)) - I_P (:,:,kk+1) = I_P(:,:,kk)*(2._r8 + Alpha(:,:,kk))/(2._r8 - Alpha(:,:,kk)) - end do - Ps_avg(:,:) = I_P(:,:,nlev+1) - - ! Determine an appropriate d/d lapse rate near the surface - ! OPTIONALLY: Use dry adiabatic lapse rate or environmental lapse rate. - !----------------------------------------------------------------------- - if(.FALSE.) then - ! DRY ADIABATIC laspe rate - !------------------------------ - RT_lapse(:,:) = -1._r8*cappa - else - ! ENVIRONMENTAL (empirical) laspe rate - !-------------------------------------- - RT_lapse(:,:) = (RT_avg (:,:,nlev-1,ie)-RT_avg (:,:,nlev,ie)) & - /(Phi_avg(:,:,nlev-1,ie)-Phi_avg(:,:,nlev,ie)) - endif - - ! Calcualte reference surface pressure - !-------------------------------------- - dPhis(:,:) = elem(ie)%state%phis(:,:)-Phis_avg(:,:,ie) - do jj=1,np - do ii=1,np - if (abs(RT_lapse(ii,jj)) .gt. 1.e-3_r8) then - Lapse0 = RT_lapse(ii,jj)/RT_avg(ii,jj,nlev,ie) - Expon0 = (-1._r8/RT_lapse(ii,jj)) - Ps_ref(ii,jj) = Ps_avg(ii,jj)*((1._r8 + Lapse0*dPhis(ii,jj))**Expon0) - else - Ps_ref(ii,jj) = Ps_avg(ii,jj)*exp(-dPhis(ii,jj)/RT_avg(ii,jj,nlev,ie)) - endif - end do - end do - - ! Calculate reference dp3d values - !--------------------------------- - dlt_Ps(:,:) = Ps_ref(:,:) - Ps_avg(:,:) - do kk=1,nlev - dp3d_ref(:,:,kk,ie) = DP_avg(:,:,kk) + (hvcoord%hybi(kk+1) & - -hvcoord%hybi(kk ))*dlt_Ps(:,:) - end do - - end do ! ie=nets,nete - - ! End Routine - !------------ - return - end subroutine calc_dp3d_reference - !============================================================================= - - - !============================================================================= - subroutine fill_element(Eval) - ! - ! fill_element_bilin: Fill in element gridpoints using local bi-linear - ! interpolation of nearby average values. - ! - ! NOTE: This routine is hard coded for NP=4, if a - ! different value of NP is used... bad things - ! will happen. - !======================================================================= - use dimensions_mod,only: np - ! - ! Passed variables - !------------------- - real(kind=r8),intent(inout):: Eval(np,np) - ! - ! Local Values - !-------------- - real(kind=r8):: X0 - real(kind=r8):: S1,S2,S3,S4 - real(kind=r8):: C1,C2,C3,C4 - real(kind=r8):: E1,E2,E3,E4,E0 - - X0 = sqrt(1._r8/5._r8) - - ! Set the "known" values Eval - !---------------------------- - S1 = (Eval(1 ,2 )+Eval(1 ,3 ))/2._r8 - S2 = (Eval(2 ,np)+Eval(3 ,np))/2._r8 - S3 = (Eval(np,2 )+Eval(np,3 ))/2._r8 - S4 = (Eval(2 ,1 )+Eval(3 ,1 ))/2._r8 - C1 = Eval(1 ,1 ) - C2 = Eval(1 ,np) - C3 = Eval(np,np) - C4 = Eval(np,1 ) - - ! E0 OPTION: Element Center value: - !--------------------------------- - IF(.FALSE.) THEN - ! Use ELEMENT AVERAGE value contained in (2,2) - !---------------------------------------------- - E0 = Eval(2,2) - ELSE - ! Use AVG OF SIDE VALUES after boundary exchange of E0 (smooting option) - !----------------------------------------------------------------------- - E0 = (S1 + S2 + S3 + S4)/4._r8 - ENDIF - - ! Calc interior values along center axes - !---------------------------------------- - E1 = E0 + X0*(S1-E0) - E2 = E0 + X0*(S2-E0) - E3 = E0 + X0*(S3-E0) - E4 = E0 + X0*(S4-E0) - - ! Calculate Side Gridpoint Values for Eval - !------------------------------------------ - Eval(1 ,2 ) = S1 + X0*(C1-S1) - Eval(1 ,3 ) = S1 + X0*(C2-S1) - Eval(2 ,np) = S2 + X0*(C2-S2) - Eval(3 ,np) = S2 + X0*(C3-S2) - Eval(np,2 ) = S3 + X0*(C4-S3) - Eval(np,3 ) = S3 + X0*(C3-S3) - Eval(2 ,1 ) = S4 + X0*(C1-S4) - Eval(3 ,1 ) = S4 + X0*(C4-S4) - - ! Calculate interior values - !--------------------------- - Eval(2 ,2 ) = E1 + X0*(Eval(2 ,1 )-E1) - Eval(2 ,3 ) = E1 + X0*(Eval(2 ,np)-E1) - Eval(3 ,2 ) = E3 + X0*(Eval(3 ,1 )-E3) - Eval(3 ,3 ) = E3 + X0*(Eval(3 ,np)-E3) - - ! End Routine - !------------ - return - end subroutine fill_element - end module prim_advance_mod diff --git a/src/dynamics/se/dycore/prim_advection_mod.F90 b/src/dynamics/se/dycore/prim_advection_mod.F90 index 8cd327d2..e0add527 100644 --- a/src/dynamics/se/dycore/prim_advection_mod.F90 +++ b/src/dynamics/se/dycore/prim_advection_mod.F90 @@ -22,7 +22,7 @@ module prim_advection_mod use element_mod, only: element_t use fvm_control_volume_mod, only: fvm_struct use hybvcoord_mod, only: hvcoord_t - use time_mod, only: TimeLevel_t, TimeLevel_Qdp + use se_dyn_time_mod, only: TimeLevel_t, TimeLevel_Qdp use control_mod, only: nu_q, nu_p, limiter_option, hypervis_subcycle_q, rsplit use edge_mod, only: edgevpack, edgevunpack, initedgebuffer, initedgesbuffer @@ -44,7 +44,7 @@ module prim_advection_mod public :: prim_advec_tracers_fvm public :: vertical_remap - type (EdgeBuffer_t) :: edgeAdv, edgeAdvp1, edgeAdvQminmax, edgeAdv1, edgeveloc + type (EdgeBuffer_t) :: edgeAdv, edgeAdvp1, edgeAdvQminmax, edgeveloc integer,parameter :: DSSeta = 1 integer,parameter :: DSSomega = 2 @@ -62,7 +62,7 @@ module prim_advection_mod subroutine Prim_Advec_Init1(par, elem) - use dimensions_mod, only: nlev, qsize, nelemd,ntrac, use_cslam + use dimensions_mod, only: nlev, qsize, nelemd,ntrac,use_cslam use parallel_mod, only: parallel_t, boundaryCommMethod use cam_abortutils, only: check_allocate type(parallel_t) :: par @@ -91,17 +91,17 @@ subroutine Prim_Advec_Init1(par, elem) ! allocate largest one first ! Currently this is never freed. If it was, only this first one should ! be freed, as only it knows the true size of the buffer. - call initEdgeBuffer(par,edgeAdvp1,elem,qsize*nlev + nlev,bndry_type=boundaryCommMethod,& - nthreads=horz_num_threads*advec_remap_num_threads) - call initEdgeBuffer(par,edgeAdv,elem,qsize*nlev,bndry_type=boundaryCommMethod, & - nthreads=horz_num_threads*advec_remap_num_threads) - ! This is a different type of buffer pointer allocation - ! used for determine the minimum and maximum value from - ! neighboring elements - call initEdgeSBuffer(par,edgeAdvQminmax,elem,qsize*nlev*2,bndry_type=boundaryCommMethod, & - nthreads=horz_num_threads*advec_remap_num_threads) - - call initEdgeBuffer(par,edgeAdv1,elem,nlev,bndry_type=boundaryCommMethod) + if (.not.use_cslam) then + call initEdgeBuffer(par,edgeAdvp1,elem,qsize*nlev + nlev,bndry_type=boundaryCommMethod,& + nthreads=horz_num_threads*advec_remap_num_threads) + call initEdgeBuffer(par,edgeAdv,elem,qsize*nlev,bndry_type=boundaryCommMethod, & + nthreads=horz_num_threads*advec_remap_num_threads) + ! This is a different type of buffer pointer allocation + ! used for determine the minimum and maximum value from + ! neighboring elements + call initEdgeSBuffer(par,edgeAdvQminmax,elem,qsize*nlev*2,bndry_type=boundaryCommMethod, & + nthreads=horz_num_threads*advec_remap_num_threads) + end if call initEdgeBuffer(par,edgeveloc,elem,2*nlev,bndry_type=boundaryCommMethod) @@ -231,9 +231,9 @@ end subroutine euler_step_driver !----------------------------------------------------------------------------- !----------------------------------------------------------------------------- subroutine Prim_Advec_Tracers_remap_rk2( elem , deriv , hvcoord , hybrid , dt , tl , nets , nete ) - use derivative_mod, only : divergence_sphere - use control_mod , only : qsplit - use hybrid_mod , only : get_loop_ranges!, PrintHybrid + use derivative_mod, only: divergence_sphere + use control_mod , only: qsplit + use hybrid_mod , only: get_loop_ranges!, PrintHybrid ! use thread_mod , only : omp_set_num_threads, omp_get_thread_num type (element_t) , intent(inout) :: elem(:) @@ -321,7 +321,7 @@ subroutine qdp_time_avg( elem , rkstage , n0_qdp , np1_qdp , hybrid , nets , net use hybrid_mod, only : hybrid_t, get_loop_ranges implicit none type(element_t) , intent(inout) :: elem(:) - integer , intent(in ) :: rkstage , n0_qdp , np1_qdp , nets , nete + integer , intent(in ) :: rkstage , n0_qdp , np1_qdp , nets , nete type(hybrid_t) :: hybrid integer :: i,j,ie,q,k integer :: kbeg,kend,qbeg,qend @@ -961,7 +961,8 @@ subroutine vertical_remap(hybrid,elem,fvm,hvcoord,np1,np1_qdp,nets,nete) use cam_logfile, only: iulog use dynconst, only: pi use air_composition, only: thermodynamic_active_species_idx_dycore - use cam_thermo, only: get_enthalpy, get_virtual_temp, get_dp, MASS_MIXING_RATIO + use dyn_thermo, only: get_enthalpy, get_virtual_temp, get_dp + use cam_thermo, only: MASS_MIXING_RATIO use thread_mod, only: omp_set_nested use control_mod, only: vert_remap_uvTq_alg diff --git a/src/dynamics/se/dycore/prim_driver_mod.F90 b/src/dynamics/se/dycore/prim_driver_mod.F90 index f5715cea..bd9680af 100644 --- a/src/dynamics/se/dycore/prim_driver_mod.F90 +++ b/src/dynamics/se/dycore/prim_driver_mod.F90 @@ -26,10 +26,10 @@ module prim_driver_mod subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) use dimensions_mod, only: irecons_tracer, fvm_supercycling - use dimensions_mod, only: fv_nphys, ntrac, nc + use dimensions_mod, only: fv_nphys, nc use parallel_mod, only: syncmp - use time_mod, only: timelevel_t, tstep, phys_tscale, nsplit, TimeLevel_Qdp - use time_mod, only: nsplit_baseline,rsplit_baseline + use se_dyn_time_mod, only: timelevel_t, tstep, phys_tscale, nsplit, TimeLevel_Qdp + use se_dyn_time_mod, only: nsplit_baseline,rsplit_baseline use prim_state_mod, only: prim_printstate use control_mod, only: runtype, topology, rsplit, qsplit, rk_stage_user, & nu, nu_q, nu_div, hypervis_subcycle, hypervis_subcycle_q, & @@ -40,6 +40,9 @@ subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) use hybvcoord_mod, only: hvcoord_t use prim_advection_mod, only: prim_advec_init2,deriv use prim_advance_mod, only: compute_omega + use physconst, only: rga, cappa, cpair, tref, lapse_rate + use dyn_thermo, only: get_dp_ref + use physconst, only: pstd type (element_t), intent(inout) :: elem(:) type (fvm_struct), intent(inout) :: fvm(:) @@ -56,13 +59,16 @@ subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) ! Local variables ! ================================== + ! variables used to calculate CFL ! variables used to calculate CFL real (kind=r8) :: dtnu ! timestep*viscosity parameter - real (kind=r8) :: dt_dyn_vis ! viscosity timestep used in dynamics - real (kind=r8) :: dt_dyn_del2_sponge, dt_remap + real (kind=r8) :: dt_dyn_del2_sponge real (kind=r8) :: dt_tracer_vis ! viscosity timestep used in tracers + real (kind=r8) :: dt_dyn_vis ! viscosity timestep + real (kind=r8) :: dt_remap ! remapping timestep - real (kind=r8) :: dp + real (kind=r8) :: dp,dp0,T1,T0,pmid_ref(np,np) + real (kind=r8) :: ps_ref(np,np,nets:nete) integer :: i,j,k,ie,t,q integer :: n0,n0_qdp @@ -120,7 +126,7 @@ subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) ! so only now does HOMME learn the timstep. print them out: call print_cfl(elem,hybrid,nets,nete,dtnu,& !p top and p mid levels - hvcoord%hyai(1)*hvcoord%ps0,(hvcoord%hyam(:)+hvcoord%hybm(:))*hvcoord%ps0,& + hvcoord%hyai(1)*hvcoord%ps0,hvcoord%hyam(:)*hvcoord%ps0+hvcoord%hybm(:)*pstd,& !dt_remap,dt_tracer_fvm,dt_tracer_se tstep*qsplit*rsplit,tstep*qsplit*fvm_supercycling,tstep*qsplit,& !dt_dyn,dt_dyn_visco,dt_tracer_visco, dt_phys @@ -138,6 +144,39 @@ subroutine prim_init2(elem, fvm, hybrid, nets, nete, tl, hvcoord) n0=tl%n0 call TimeLevel_Qdp( tl, qsplit, n0_qdp) call compute_omega(hybrid,n0,n0_qdp,elem,deriv,nets,nete,dt_remap,hvcoord) + ! + ! pre-compute pressure-level thickness reference profile + ! + do ie=nets,nete + call get_dp_ref(hvcoord%hyai, hvcoord%hybi, hvcoord%ps0, elem(ie)%state%phis(:,:), & + elem(ie)%derived%dp_ref(:,:,:), ps_ref(:,:,ie)) + end do + ! + ! pre-compute reference temperature profile (Simmons and Jiabin, 1991, QJRMS, Section 2a + ! doi: https://doi.org/10.1002/qj.49711749703c) + ! + ! Tref = T0+T1*Exner + ! T1 = .0065*Tref*Cp/g ! = ~191 + ! T0 = Tref-T1 ! = ~97 + ! + T1 = lapse_rate*Tref*cpair*rga + T0 = Tref-T1 + do ie=nets,nete + do k=1,nlev + pmid_ref =hvcoord%hyam(k)*hvcoord%ps0 + hvcoord%hybm(k)*ps_ref(:,:,ie) + dp0 = ( hvcoord%hyai(k+1) - hvcoord%hyai(k) )*hvcoord%ps0 + & + ( hvcoord%hybi(k+1) - hvcoord%hybi(k) )*hvcoord%ps0 + if (hvcoord%hybm(k)>0) then + elem(ie)%derived%T_ref(:,:,k) = T0+T1*(pmid_ref/hvcoord%ps0)**cappa + ! + ! pel@ucar.edu: resolved noise issue over Antartica + ! + elem(ie)%derived%dp_ref(:,:,k) = elem(ie)%derived%dp_ref(:,:,k)-dp0 + else + elem(ie)%derived%T_ref(:,:,k) = 0.0_r8 + end if + end do + end do if (hybrid%masterthread) write(iulog,*) "initial state:" call prim_printstate(elem, tl, hybrid,nets,nete, fvm) @@ -146,8 +185,7 @@ end subroutine prim_init2 !=======================================================================================================! - - subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubstep, omega_cn) + subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubstep, single_column, omega_cn) ! ! advance all variables (u,v,T,ps,Q,C) from time t to t + dt_q ! @@ -181,17 +219,17 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst ! ! use hybvcoord_mod, only : hvcoord_t - use time_mod, only: TimeLevel_t, timelevel_update, timelevel_qdp, nsplit - use control_mod, only: statefreq,qsplit, rsplit, variable_nsplit + use se_dyn_time_mod, only: TimeLevel_t, timelevel_update, timelevel_qdp, nsplit + use control_mod, only: statefreq,qsplit, rsplit, variable_nsplit, dribble_in_rsplit_loop use prim_advance_mod, only: applycamforcing - use prim_advance_mod, only: calc_tot_energy_dynamics,compute_omega + use prim_advance_mod, only: tot_energy_dyn,compute_omega use prim_state_mod, only: prim_printstate, adjust_nsplit use prim_advection_mod, only: vertical_remap, deriv use thread_mod, only: omp_get_thread_num use perf_mod , only: t_startf, t_stopf use fvm_mod , only: fill_halo_fvm, ghostBufQnhc_h use dimensions_mod, only: use_cslam,fv_nphys - + use fvm_mapping, only: cslam2gll type (element_t) , intent(inout) :: elem(:) type(fvm_struct), intent(inout) :: fvm(:) type (hybrid_t), intent(in) :: hybrid ! distributed parallel structure (shared) @@ -201,6 +239,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst real(kind=r8), intent(in) :: dt ! "timestep dependent" timestep type (TimeLevel_t), intent(inout):: tl integer, intent(in) :: nsubstep ! nsubstep = 1 .. nsplit + logical, intent(in) :: single_column real (kind=r8) , intent(inout):: omega_cn(2,nets:nete) !min and max of vertical Courant number real(kind=r8) :: dt_q, dt_remap, dt_phys @@ -208,7 +247,6 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst real (kind=r8) :: dp_np1(np,np) real (kind=r8) :: dp_start(np,np,nlev+1,nets:nete),dp_end(np,np,nlev,nets:nete) logical :: compute_diagnostics - ! =================================== ! Main timestepping loop ! =================================== @@ -245,12 +283,39 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst call TimeLevel_Qdp( tl, qsplit, n0_qdp) - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%n0,n0_qdp,'dAF') - call ApplyCAMForcing(elem,fvm,tl%n0,n0_qdp,dt_remap,dt_phys,nets,nete,nsubstep) - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%n0,n0_qdp,'dBD') + if (dribble_in_rsplit_loop==0) then + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dAF') + call ApplyCAMForcing(elem,fvm,tl%n0,n0_qdp,dt_remap,dt_phys,nets,nete,nsubstep) + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dBD') + end if do r=1,rsplit if (r.ne.1) call TimeLevel_update(tl,"leapfrog") - call prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,r) + ! + ! if nsplit==1 and physics time-step is long then there will be noise in the + ! pressure field; hence "dripple" in tendencies + ! + if (dribble_in_rsplit_loop==1) then + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dAF') + call ApplyCAMForcing(elem,fvm,tl%n0,n0_qdp,dt,dt_phys,nets,nete,MAX(nsubstep,r)) + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dBD') + end if + ! + ! right after physics overwrite Qdp with CSLAM values + ! + if (use_cslam.and.nsubstep==1.and.r==1) then + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dAF') + call cslam2gll(elem, fvm, hybrid,nets,nete, tl%n0, n0_qdp) + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dBD') + end if + call tot_energy_dyn(elem,fvm,nets,nete,tl%n0,n0_qdp,'dBL') + if (single_column) then + ! Single Column Case + ! Loop over rsplit vertically lagrangian timesteps + call prim_step_scm(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,r) + else + call prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,r,nsubstep==nsplit,dt_remap) + end if + call tot_energy_dyn(elem,fvm,nets,nete,tl%np1,n0_qdp,'dAL') enddo @@ -263,7 +328,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst ! always for tracers !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAD') + call tot_energy_dyn(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAD') if (variable_nsplit.or.compute_diagnostics) then ! @@ -280,9 +345,9 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! time step is complete. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - call calc_tot_energy_dynamics(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAR') + call tot_energy_dyn(elem,fvm,nets,nete,tl%np1,np1_qdp,'dAR') - if (nsubstep==nsplit) then + if (nsubstep==nsplit.and. .not. single_column) then call compute_omega(hybrid,tl%np1,np1_qdp,elem,deriv,nets,nete,dt_remap,hvcoord) end if @@ -326,7 +391,6 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst end do end do end do - if (nsubstep==nsplit.and.variable_nsplit) then call t_startf('adjust_nsplit') call adjust_nsplit(elem, tl, hybrid,nets,nete, fvm, omega_cn) @@ -351,8 +415,7 @@ subroutine prim_run_subcycle(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord,nsubst end subroutine prim_run_subcycle - - subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) + subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep, last_step,dt_remap) ! ! Take qsplit dynamics steps and one tracer step ! for vertically lagrangian option, this subroutine does only the horizontal step @@ -370,7 +433,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) ! tl%n0 time t + dt_q ! use hybvcoord_mod, only: hvcoord_t - use time_mod, only: TimeLevel_t, timelevel_update + use se_dyn_time_mod, only: TimeLevel_t, timelevel_update use control_mod, only: statefreq, qsplit, nu_p use thread_mod, only: omp_get_thread_num use prim_advance_mod, only: prim_advance_exp @@ -381,7 +444,8 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) use dimensions_mod, only: kmin_jet, kmax_jet use fvm_mod, only: ghostBufQnhc_vh,ghostBufQ1_vh, ghostBufFlux_vh use fvm_mod, only: ghostBufQ1_h,ghostBufQnhcJet_h, ghostBufFluxJet_h - + use se_dyn_time_mod, only: timelevel_qdp + use fvm_mapping, only: cslam2gll #ifdef waccm_debug use cam_history, only: outfld #endif @@ -396,6 +460,8 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) real(kind=r8), intent(in) :: dt ! "timestep dependent" timestep type (TimeLevel_t), intent(inout) :: tl integer, intent(in) :: rstep ! vertical remap subcycling step + logical, intent(in) :: last_step! last step before d_p_coupling + real(kind=r8), intent(in) :: dt_remap type (hybrid_t):: hybridnew,hybridnew2 real(kind=r8) :: st, st1, dp, dt_q @@ -403,6 +469,7 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) integer :: ithr integer :: region_num_threads integer :: kbeg,kend + integer :: n0_qdp, np1_qdp real (kind=r8) :: tempdp3d(np,np), x real (kind=r8) :: tempmass(nc,nc) @@ -480,7 +547,6 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) end do end if #endif - ! current dynamics state variables: ! derived%dp = dp at start of timestep ! derived%vn0 = mean horiz. flux: U*dp @@ -500,32 +566,19 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) ! special case in CAM: if CSLAM tracers are turned on , qsize=1 but this tracer should ! not be advected. This will be cleaned up when the physgrid is merged into CAM trunk ! Currently advecting all species - if (qsize > 0) then !xxx change when not double advecting - + if (.not.use_cslam) then call t_startf('prim_advec_tracers_remap') - if(use_cslam) then - ! Deactivate threading in the tracer dimension if this is a CSLAM run - region_num_threads = 1 - else - region_num_threads=tracer_num_threads - endif + region_num_threads=tracer_num_threads call omp_set_nested(.true.) !$OMP PARALLEL NUM_THREADS(region_num_threads), DEFAULT(SHARED), PRIVATE(hybridnew) - if(use_cslam) then - ! Deactivate threading in the tracer dimension if this is a CSLAM run - hybridnew = config_thread_region(hybrid,'serial') - else - hybridnew = config_thread_region(hybrid,'tracer') - endif + hybridnew = config_thread_region(hybrid,'tracer') call Prim_Advec_Tracers_remap(elem, deriv,hvcoord,hybridnew,dt_q,tl,nets,nete) !$OMP END PARALLEL call omp_set_nested(.false.) call t_stopf('prim_advec_tracers_remap') - end if - ! - ! only run fvm transport every fvm_supercycling rstep - ! - if (use_cslam) then + else + ! + ! only run fvm transport every fvm_supercycling rstep ! ! FVM transport ! @@ -557,7 +610,9 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) fvm(ie)%psc(i,j) = sum(fvm(ie)%dp_fvm(i,j,:)) + hvcoord%hyai(1)*hvcoord%ps0 end do end do - end do + end do + call TimeLevel_Qdp( tl, qsplit, n0_qdp, np1_qdp) + if (.not.last_step) call cslam2gll(elem, fvm, hybrid,nets,nete, tl%np1, np1_qdp) else if ((mod(rstep,fvm_supercycling_jet) == 0)) then ! ! shorter fvm time-step in jet region @@ -572,11 +627,84 @@ subroutine prim_step(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) (/nc*nc,nlev/)), nc*nc, ie) end do #endif - endif + endif end subroutine prim_step + subroutine prim_step_scm(elem, fvm, hybrid,nets,nete, dt, tl, hvcoord, rstep) + ! + ! prim_step version for single column model (SCM) + ! Here we simply want to compute the floating level tendency + ! based on the prescribed large scale vertical velocity + ! Take qsplit dynamics steps and one tracer step + ! for vertically lagrangian option, this subroutine does only + ! the horizontal step + ! + ! input: + ! tl%nm1 not used + ! tl%n0 data at time t + ! tl%np1 new values at t+dt_q + ! + ! then we update timelevel pointers: + ! tl%nm1 = tl%n0 + ! tl%n0 = tl%np1 + ! so that: + ! tl%nm1 tracers: t dynamics: t+(qsplit-1)*dt + ! tl%n0 time t + dt_q + ! + use hybvcoord_mod, only: hvcoord_t + use se_dyn_time_mod, only: TimeLevel_t, timelevel_update + use control_mod, only: statefreq, qsplit, nu_p + use prim_advection_mod, only: deriv + use hybrid_mod, only: config_thread_region, get_loop_ranges + type (element_t) , intent(inout) :: elem(:) + type(fvm_struct), intent(inout) :: fvm(:) + type (hybrid_t), intent(in) :: hybrid ! distributed parallel structure (shared) + type (hvcoord_t), intent(in) :: hvcoord ! hybrid vertical coordinate struct + integer, intent(in) :: nets ! starting thread element number (private) + integer, intent(in) :: nete ! ending thread element number (private) + real(kind=r8), intent(in) :: dt ! "timestep dependent" timestep + type (TimeLevel_t), intent(inout) :: tl + integer, intent(in) :: rstep ! vertical remap subcycling step + + integer :: ie,n + ! =============== + ! initialize mean flux accumulation variables and save some variables at n0 + ! for use by advection + ! =============== + do ie=nets,nete + elem(ie)%derived%vn0=0 ! mean horizontal mass flux + if (nu_p>0) then + elem(ie)%derived%dpdiss_ave=0 + elem(ie)%derived%dpdiss_biharmonic=0 + endif + elem(ie)%derived%dp(:,:,:)=elem(ie)%state%dp3d(:,:,:,tl%n0) + enddo + + ! =============== + ! Dynamical Step + ! =============== +#ifdef scam + call t_startf('set_prescribed_scm') + + call set_prescribed_scm(elem, fvm, deriv, hvcoord, & + hybrid, dt, tl, nets, nete) + + call t_stopf('set_prescribed_scm') + + do n=2,qsplit + call TimeLevel_update(tl,"leapfrog") + + call t_startf('set_prescribed_scm') + + call set_prescribed_scm(elem, fvm, deriv, hvcoord, & + hybrid, dt, tl, nets, nete) + + call t_stopf('set_prescribed_scm') + enddo +#endif + end subroutine prim_step_scm !=======================================================================================================! diff --git a/src/dynamics/se/dycore/prim_init.F90 b/src/dynamics/se/dycore/prim_init.F90 index 76d3a635..b884ca80 100644 --- a/src/dynamics/se/dycore/prim_init.F90 +++ b/src/dynamics/se/dycore/prim_init.F90 @@ -30,7 +30,7 @@ subroutine prim_init1(elem, fvm, par, Tl) use element_mod, only: element_t, allocate_element_dims, allocate_element_desc use fvm_mod, only: fvm_init1 use mesh_mod, only: MeshUseMeshFile - use time_mod, only: timelevel_init, timelevel_t + use se_dyn_time_mod, only: timelevel_init, timelevel_t use mass_matrix_mod, only: mass_matrix use derivative_mod, only: allocate_subcell_integration_matrix_cslam use derivative_mod, only: allocate_subcell_integration_matrix_physgrid diff --git a/src/dynamics/se/dycore/prim_state_mod.F90 b/src/dynamics/se/dycore/prim_state_mod.F90 index 28ca9cdc..84f9aee2 100644 --- a/src/dynamics/se/dycore/prim_state_mod.F90 +++ b/src/dynamics/se/dycore/prim_state_mod.F90 @@ -4,7 +4,7 @@ module prim_state_mod use dimensions_mod, only: nlev, np, nc, qsize_d, ntrac use parallel_mod, only: ordered use hybrid_mod, only: hybrid_t - use time_mod, only: timelevel_t, TimeLevel_Qdp, time_at + use se_dyn_time_mod, only: timelevel_t, TimeLevel_Qdp, time_at use control_mod, only: qsplit, statediag_numtrac use global_norms_mod, only: global_integrals_general use element_mod, only: element_t @@ -26,7 +26,7 @@ subroutine prim_printstate(elem, tl,hybrid,nets,nete, fvm, omega_cn) use air_composition, only: thermodynamic_active_species_idx_dycore, dry_air_species_num use air_composition, only: thermodynamic_active_species_num,thermodynamic_active_species_idx use cam_control_mod, only: initial_run - use time_mod, only: tstep + use se_dyn_time_mod, only: tstep use control_mod, only: rsplit, qsplit use perf_mod, only: t_startf, t_stopf use cam_abortutils, only: check_allocate @@ -409,10 +409,10 @@ end subroutine prim_printstate_cslam_gamma subroutine adjust_nsplit(elem, tl,hybrid,nets,nete, fvm, omega_cn) use dimensions_mod, only: ksponge_end use dimensions_mod, only: fvm_supercycling, fvm_supercycling_jet - use time_mod, only: tstep + use se_dyn_time_mod, only: tstep use control_mod, only: rsplit, qsplit use perf_mod, only: t_startf, t_stopf - use time_mod, only: nsplit, nsplit_baseline,rsplit_baseline + use se_dyn_time_mod, only: nsplit, nsplit_baseline,rsplit_baseline use control_mod, only: qsplit, rsplit use time_manager, only: get_step_size use cam_abortutils, only: endrun diff --git a/src/dynamics/se/dycore/se_dyn_time_mod.F90 b/src/dynamics/se/dycore/se_dyn_time_mod.F90 index df0a7b53..716c34ad 100644 --- a/src/dynamics/se/dycore/se_dyn_time_mod.F90 +++ b/src/dynamics/se/dycore/se_dyn_time_mod.F90 @@ -1,4 +1,4 @@ -module time_mod +module se_dyn_time_mod !------------------ use shr_kind_mod, only: r8=>shr_kind_r8 !------------------ @@ -133,4 +133,4 @@ subroutine TimeLevel_update(tl,uptype) !$OMP BARRIER end subroutine TimeLevel_update -end module time_mod +end module se_dyn_time_mod diff --git a/src/dynamics/se/dycore/viscosity_mod.F90 b/src/dynamics/se/dycore/viscosity_mod.F90 index 83be78b5..42bca4bd 100644 --- a/src/dynamics/se/dycore/viscosity_mod.F90 +++ b/src/dynamics/se/dycore/viscosity_mod.F90 @@ -1,15 +1,15 @@ module viscosity_mod ! ! This module should be renamed "global_deriv_mod.F90" -! -! It is a collection of derivative operators that must be applied to the field -! over the sphere (as opposed to derivative operators that can be applied element +! +! It is a collection of derivative operators that must be applied to the field +! over the sphere (as opposed to derivative operators that can be applied element ! by element) ! ! use shr_kind_mod, only: r8=>shr_kind_r8 use thread_mod, only: max_num_threads, omp_get_num_threads - use dimensions_mod, only: np, nc, nlev,qsize,nelemd + use dimensions_mod, only: np, nc, nlev,nlevp, qsize,nelemd use hybrid_mod, only: hybrid_t, get_loop_ranges, config_thread_region use parallel_mod, only: parallel_t use element_mod, only: element_t @@ -50,11 +50,9 @@ module viscosity_mod CONTAINS -subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid,nt,nets,nete,kbeg,kend,& - dp3d_ref,T_ref) +subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid,nt,nets,nete,kbeg,kend) use derivative_mod, only : subcell_Laplace_fluxes use dimensions_mod, only : use_cslam, nu_div_lev,nu_lev - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! compute weak biharmonic operator ! input: h,v (stored in elem()%, in lat-lon coordinates @@ -68,101 +66,95 @@ subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid, real (kind=r8), intent(out), dimension(nc,nc,4,nlev,nets:nete) :: dpflux real (kind=r8), dimension(np,np,2,nlev,nets:nete) :: vtens real (kind=r8), dimension(np,np,nlev,nets:nete) :: ttens,dptens - real (kind=r8), dimension(np,np,nlev,nets:nete), optional :: dp3d_ref,T_ref type (EdgeBuffer_t) , intent(inout) :: edge3 type (derivative_t) , intent(in) :: deriv - ! local integer :: i,j,k,kptr,ie,kblk ! real (kind=r8), dimension(:,:), pointer :: rspheremv real (kind=r8), dimension(np,np) :: tmp real (kind=r8), dimension(np,np) :: tmp2 real (kind=r8), dimension(np,np,2) :: v + + real (kind=r8), dimension(np,np,nlev) :: lap_p_wk + real (kind=r8), dimension(np,np,nlevp) :: T_i + + real (kind=r8) :: nu_ratio1, nu_ratio2 logical var_coef1 - + kblk = kend - kbeg + 1 - + if (use_cslam) dpflux = 0 - !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) + !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) !so tensor is only used on second call to laplace_sphere_wk var_coef1 = .true. if(hypervis_scaling > 0) var_coef1 = .false. - - - do ie=nets,nete + do ie=nets,nete !$omp parallel do num_threads(vert_num_threads) private(k,tmp) do k=kbeg,kend - nu_ratio1=1 - nu_ratio2=1 - if (nu_div_lev(k)/=nu_lev(k)) then - if(hypervis_scaling /= 0) then - ! we have a problem with the tensor in that we cant seperate - ! div and curl components. So we do, with tensor V: - ! nu * (del V del ) * ( nu_ratio * grad(div) - curl(curl)) - nu_ratio1=nu_div_lev(k)/nu_lev(k) - nu_ratio2=1 - else - nu_ratio1=sqrt(nu_div_lev(k)/nu_lev(k)) - nu_ratio2=sqrt(nu_div_lev(k)/nu_lev(k)) - endif - endif - - if (present(T_ref)) then - tmp=elem(ie)%state%T(:,:,k,nt)-T_ref(:,:,k,ie) - else - tmp=elem(ie)%state%T(:,:,k,nt) - end if + nu_ratio1=1 + nu_ratio2=1 + if (nu_div_lev(k)/=nu_lev(k)) then + if(hypervis_scaling /= 0) then + ! we have a problem with the tensor in that we cant seperate + ! div and curl components. So we do, with tensor V: + ! nu * (del V del ) * ( nu_ratio * grad(div) - curl(curl)) + nu_ratio1=nu_div_lev(k)/nu_lev(k) + nu_ratio2=1 + else + nu_ratio1=sqrt(nu_div_lev(k)/nu_lev(k)) + nu_ratio2=sqrt(nu_div_lev(k)/nu_lev(k)) + endif + endif + + tmp=elem(ie)%state%T(:,:,k,nt)-elem(ie)%derived%T_ref(:,:,k) call laplace_sphere_wk(tmp,deriv,elem(ie),ttens(:,:,k,ie),var_coef=var_coef1) - if (present(dp3d_ref)) then - tmp=elem(ie)%state%dp3d(:,:,k,nt)-dp3d_ref(:,:,k,ie) - else - tmp=elem(ie)%state%dp3d(:,:,k,nt) - end if + + tmp=elem(ie)%state%dp3d(:,:,k,nt)-elem(ie)%derived%dp_ref(:,:,k) call laplace_sphere_wk(tmp,deriv,elem(ie),dptens(:,:,k,ie),var_coef=var_coef1) call vlaplace_sphere_wk(elem(ie)%state%v(:,:,:,k,nt),deriv,elem(ie),.true.,vtens(:,:,:,k,ie), & var_coef=var_coef1,nu_ratio=nu_ratio1) enddo - + kptr = kbeg - 1 call edgeVpack(edge3,ttens(:,:,kbeg:kend,ie),kblk,kptr,ie) - - kptr = kbeg - 1 + nlev + + kptr = kbeg - 1 + nlev call edgeVpack(edge3,vtens(:,:,1,kbeg:kend,ie),kblk,kptr,ie) - - kptr = kbeg - 1 + 2*nlev + + kptr = kbeg - 1 + 2*nlev call edgeVpack(edge3,vtens(:,:,2,kbeg:kend,ie),kblk,kptr,ie) - - kptr = kbeg - 1 + 3*nlev + + kptr = kbeg - 1 + 3*nlev call edgeVpack(edge3,dptens(:,:,kbeg:kend,ie),kblk,kptr,ie) enddo - + call bndry_exchange(hybrid,edge3,location='biharmonic_wk_dp3d') - + do ie=nets,nete !CLEAN rspheremv => elem(ie)%rspheremp(:,:) - + kptr = kbeg - 1 call edgeVunpack(edge3,ttens(:,:,kbeg:kend,ie),kblk,kptr,ie) - - kptr = kbeg - 1 + nlev + + kptr = kbeg - 1 + nlev call edgeVunpack(edge3,vtens(:,:,1,kbeg:kend,ie),kblk,kptr,ie) - - kptr = kbeg - 1 + 2*nlev + + kptr = kbeg - 1 + 2*nlev call edgeVunpack(edge3,vtens(:,:,2,kbeg:kend,ie),kblk,kptr,ie) - - kptr = kbeg - 1 + 3*nlev + + kptr = kbeg - 1 + 3*nlev call edgeVunpack(edge3,dptens(:,:,kbeg:kend,ie),kblk,kptr,ie) - + if (use_cslam) then do k=1,nlev -!CLEAN tmp(:,:)= rspheremv(:,:)*dptens(:,:,k,ie) - tmp(:,:)= elem(ie)%rspheremp(:,:)*dptens(:,:,k,ie) - call subcell_Laplace_fluxes(tmp, deriv, elem(ie), np, nc,dpflux(:,:,:,k,ie)) +!CLEAN tmp(:,:)= rspheremv(:,:)*dptens(:,:,k,ie) + tmp(:,:)= elem(ie)%rspheremp(:,:)*dptens(:,:,k,ie) + call subcell_Laplace_fluxes(tmp, deriv, elem(ie), np, nc,dpflux(:,:,:,k,ie)) enddo endif - + ! apply inverse mass matrix, then apply laplace again !$omp parallel do num_threads(vert_num_threads) private(k,v,tmp,tmp2) do k=kbeg,kend @@ -179,7 +171,7 @@ subroutine biharmonic_wk_dp3d(elem,dptens,dpflux,ttens,vtens,deriv,edge3,hybrid, v(:,:,2)=elem(ie)%rspheremp(:,:)*vtens(:,:,2,k,ie) call vlaplace_sphere_wk(v(:,:,:),deriv,elem(ie),.true.,vtens(:,:,:,k,ie), & var_coef=.true.,nu_ratio=nu_ratio2) - + enddo enddo !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -194,7 +186,7 @@ subroutine biharmonic_wk_omega(elem,ptens,deriv,edge3,hybrid,nets,nete,kbeg,kend real (kind=r8), dimension(np,np,nlev,nets:nete) :: ptens type (EdgeBuffer_t) , intent(inout) :: edge3 type (derivative_t) , intent(in) :: deriv - + ! local integer :: i,j,k,kptr,ie,kblk real (kind=r8), dimension(:,:), pointer :: rspheremv @@ -203,37 +195,37 @@ subroutine biharmonic_wk_omega(elem,ptens,deriv,edge3,hybrid,nets,nete,kbeg,kend real (kind=r8), dimension(np,np,2) :: v real (kind=r8) :: nu_ratio1, nu_ratio2 logical var_coef1 - + kblk = kend - kbeg + 1 - - !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) + + !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) !so tensor is only used on second call to laplace_sphere_wk var_coef1 = .true. if(hypervis_scaling > 0) var_coef1 = .false. - + nu_ratio1=1 nu_ratio2=1 - + do ie=nets,nete - + !$omp parallel do num_threads(vert_num_threads) private(k,tmp) do k=kbeg,kend - tmp=elem(ie)%derived%omega(:,:,k) + tmp=elem(ie)%derived%omega(:,:,k) call laplace_sphere_wk(tmp,deriv,elem(ie),ptens(:,:,k,ie),var_coef=var_coef1) enddo - + kptr = kbeg - 1 call edgeVpack(edge3,ptens(:,:,kbeg:kend,ie),kblk,kptr,ie) enddo - + call bndry_exchange(hybrid,edge3,location='biharmonic_wk_omega') - + do ie=nets,nete rspheremv => elem(ie)%rspheremp(:,:) - + kptr = kbeg - 1 call edgeVunpack(edge3,ptens(:,:,kbeg:kend,ie),kblk,kptr,ie) - + ! apply inverse mass matrix, then apply laplace again !$omp parallel do num_threads(vert_num_threads) private(k,tmp) do k=kbeg,kend @@ -261,14 +253,14 @@ subroutine biharmonic_wk_scalar(elem,qtens,deriv,edgeq,hybrid,nets,nete) ! local integer :: k,kptr,i,j,ie,ic,q -integer :: kbeg,kend,qbeg,qend +integer :: kbeg,kend,qbeg,qend real (kind=r8), dimension(np,np) :: lap_p logical var_coef1 integer :: kblk,qblk ! The per thead size of the vertical and tracers call get_loop_ranges(hybrid,kbeg=kbeg,kend=kend,qbeg=qbeg,qend=qend) - !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) + !if tensor hyperviscosity with tensor V is used, then biharmonic operator is (\grad\cdot V\grad) (\grad \cdot \grad) !so tensor is only used on second call to laplace_sphere_wk var_coef1 = .true. if(hypervis_scaling > 0) var_coef1 = .false. @@ -278,7 +270,7 @@ subroutine biharmonic_wk_scalar(elem,qtens,deriv,edgeq,hybrid,nets,nete) qblk = qend - qbeg + 1 ! calculate size of the block of tracers do ie=nets,nete - do q=qbeg,qend + do q=qbeg,qend do k=kbeg,kend lap_p(:,:)=qtens(:,:,k,q,ie) call laplace_sphere_wk(lap_p,deriv,elem(ie),qtens(:,:,k,q,ie),var_coef=var_coef1) @@ -290,11 +282,11 @@ subroutine biharmonic_wk_scalar(elem,qtens,deriv,edgeq,hybrid,nets,nete) call bndry_exchange(hybrid,edgeq,location='biharmonic_wk_scalar') - + do ie=nets,nete ! apply inverse mass matrix, then apply laplace again - do q=qbeg,qend + do q=qbeg,qend kptr = nlev*(q-1) + kbeg - 1 call edgeVunpack(edgeq, qtens(:,:,kbeg:kend,q,ie),kblk,kptr,ie) do k=kbeg,kend @@ -310,7 +302,7 @@ end subroutine biharmonic_wk_scalar subroutine make_C0(zeta,elem,hybrid,nets,nete) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! apply DSS (aka assembly procedure) to zeta. +! apply DSS (aka assembly procedure) to zeta. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! type (hybrid_t) , intent(in) :: hybrid @@ -346,7 +338,7 @@ subroutine make_C0(zeta,elem,hybrid,nets,nete) enddo enddo -call FreeEdgeBuffer(edge1) +call FreeEdgeBuffer(edge1) end subroutine @@ -414,7 +406,7 @@ subroutine make_C0_vector(v,elem,hybrid,nets,nete) enddo enddo -call FreeEdgeBuffer(edge2) +call FreeEdgeBuffer(edge2) #endif end subroutine @@ -425,11 +417,11 @@ subroutine make_C0_vector(v,elem,hybrid,nets,nete) subroutine compute_zeta_C0_contra(zeta,elem,hybrid,nets,nete,nt) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! compute C0 vorticity. That is, solve: +! compute C0 vorticity. That is, solve: ! < PHI, zeta > = ! ! input: v (stored in elem()%, in contra-variant coordinates) -! output: zeta(:,:,:,:) +! output: zeta(:,:,:,:) ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -464,11 +456,11 @@ subroutine compute_zeta_C0_contra(zeta,elem,hybrid,nets,nete,nt) subroutine compute_div_C0_contra(zeta,elem,hybrid,nets,nete,nt) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! compute C0 divergence. That is, solve: +! compute C0 divergence. That is, solve: ! < PHI, zeta > = ! ! input: v (stored in elem()%, in contra-variant coordinates) -! output: zeta(:,:,:,:) +! output: zeta(:,:,:,:) ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -501,11 +493,11 @@ subroutine compute_div_C0_contra(zeta,elem,hybrid,nets,nete,nt) subroutine compute_zeta_C0_par(zeta,elem,par,nt) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! compute C0 vorticity. That is, solve: +! compute C0 vorticity. That is, solve: ! < PHI, zeta > = ! ! input: v (stored in elem()%, in lat-lon coordinates) -! output: zeta(:,:,:,:) +! output: zeta(:,:,:,:) ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! type (parallel_t) :: par @@ -528,11 +520,11 @@ subroutine compute_zeta_C0_par(zeta,elem,par,nt) subroutine compute_div_C0_par(zeta,elem,par,nt) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! compute C0 divergence. That is, solve: +! compute C0 divergence. That is, solve: ! < PHI, zeta > = ! ! input: v (stored in elem()%, in lat-lon coordinates) -! output: zeta(:,:,:,:) +! output: zeta(:,:,:,:) ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -557,11 +549,11 @@ subroutine compute_div_C0_par(zeta,elem,par,nt) subroutine compute_zeta_C0_hybrid(zeta,elem,hybrid,nets,nete,nt) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! compute C0 vorticity. That is, solve: +! compute C0 vorticity. That is, solve: ! < PHI, zeta > = ! ! input: v (stored in elem()%, in lat-lon coordinates) -! output: zeta(:,:,:,:) +! output: zeta(:,:,:,:) ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -592,11 +584,11 @@ subroutine compute_zeta_C0_hybrid(zeta,elem,hybrid,nets,nete,nt) subroutine compute_div_C0_hybrid(zeta,elem,hybrid,nets,nete,nt) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -! compute C0 divergence. That is, solve: +! compute C0 divergence. That is, solve: ! < PHI, zeta > = ! ! input: v (stored in elem()%, in lat-lon coordinates) -! output: zeta(:,:,:,:) +! output: zeta(:,:,:,:) ! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -632,22 +624,22 @@ subroutine compute_div_C0_hybrid(zeta,elem,hybrid,nets,nete,nt) subroutine neighbor_minmax(hybrid,edgeMinMax,nets,nete,min_neigh,max_neigh) - + type (hybrid_t) , intent(in) :: hybrid type (EdgeBuffer_t) , intent(inout) :: edgeMinMax integer :: nets,nete real (kind=r8) :: min_neigh(nlev,qsize,nets:nete) real (kind=r8) :: max_neigh(nlev,qsize,nets:nete) integer :: kblk, qblk - ! local + ! local integer:: ie, q, k, kptr integer:: kbeg, kend, qbeg, qend call get_loop_ranges(hybrid,kbeg=kbeg,kend=kend,qbeg=qbeg,qend=qend) - + kblk = kend - kbeg + 1 ! calculate size of the block of vertical levels qblk = qend - qbeg + 1 ! calculate size of the block of tracers - + do ie=nets,nete do q = qbeg, qend kptr = nlev*(q - 1) + kbeg - 1 @@ -656,7 +648,7 @@ subroutine neighbor_minmax(hybrid,edgeMinMax,nets,nete,min_neigh,max_neigh) call edgeSpack(edgeMinMax,max_neigh(kbeg:kend,q,ie),kblk,kptr,ie) enddo enddo - + call bndry_exchange(hybrid,edgeMinMax,location='neighbor_minmax') do ie=nets,nete @@ -672,7 +664,7 @@ subroutine neighbor_minmax(hybrid,edgeMinMax,nets,nete,min_neigh,max_neigh) enddo end subroutine neighbor_minmax - + subroutine neighbor_minmax_start(hybrid,edgeMinMax,nets,nete,min_neigh,max_neigh) @@ -684,7 +676,7 @@ subroutine neighbor_minmax_start(hybrid,edgeMinMax,nets,nete,min_neigh,max_neigh integer :: kblk, qblk integer :: kbeg, kend, qbeg, qend - ! local + ! local integer :: ie,q, k,kptr call get_loop_ranges(hybrid,kbeg=kbeg,kend=kend,qbeg=qbeg,qend=qend) diff --git a/src/dynamics/se/dyn_comp.F90 b/src/dynamics/se/dyn_comp.F90 index 8d13866e..28805141 100644 --- a/src/dynamics/se/dyn_comp.F90 +++ b/src/dynamics/se/dyn_comp.F90 @@ -43,7 +43,7 @@ module dyn_comp qsize, use_cslam use element_mod, only: element_t, elem_state_t use fvm_control_volume_mod, only: fvm_struct -use time_mod, only: nsplit +use se_dyn_time_mod, only: nsplit use edge_mod, only: initEdgeBuffer, edgeVpack, edgeVunpack, FreeEdgeBuffer use edgetype_mod, only: EdgeBuffer_t use bndry_mod, only: bndry_exchange @@ -115,8 +115,9 @@ subroutine dyn_readnl(NLFileName) use control_mod, only: fine_ne, hypervis_power, hypervis_scaling use control_mod, only: max_hypervis_courant, statediag_numtrac,refined_mesh use control_mod, only: molecular_diff, pgf_formulation, dribble_in_rsplit_loop + use control_mod, only: sponge_del4_nu_div_fac, sponge_del4_nu_fac, sponge_del4_lev use dimensions_mod, only: ne, npart - use dimensions_mod, only: hypervis_dynamic_ref_state,large_Courant_incr + use dimensions_mod, only: large_Courant_incr use dimensions_mod, only: fvm_supercycling, fvm_supercycling_jet use dimensions_mod, only: kmin_jet, kmax_jet use params_mod, only: SFCURVE @@ -129,7 +130,6 @@ subroutine dyn_readnl(NLFileName) ! Local variables integer :: unitn, ierr,k - real(r8) :: uniform_res_hypervis_scaling,nu_fac ! SE Namelist variables integer :: se_fine_ne @@ -151,6 +151,9 @@ subroutine dyn_readnl(NLFileName) real(r8) :: se_nu_div real(r8) :: se_nu_p real(r8) :: se_nu_top + real(r8) :: se_sponge_del4_nu_fac + real(r8) :: se_sponge_del4_nu_div_fac + integer :: se_sponge_del4_lev integer :: se_qsplit logical :: se_refined_mesh integer :: se_rsplit @@ -162,7 +165,6 @@ subroutine dyn_readnl(NLFileName) integer :: se_horz_num_threads integer :: se_vert_num_threads integer :: se_tracer_num_threads - logical :: se_hypervis_dynamic_ref_state logical :: se_write_restart_unstruct logical :: se_large_Courant_incr integer :: se_fvm_supercycling @@ -170,6 +172,8 @@ subroutine dyn_readnl(NLFileName) integer :: se_kmin_jet integer :: se_kmax_jet real(r8) :: se_molecular_diff + integer :: se_pgf_formulation + real(r8) :: se_dribble_in_rsplit_loop namelist /dyn_se_nl/ & se_fine_ne, & ! For refined meshes @@ -191,6 +195,9 @@ subroutine dyn_readnl(NLFileName) se_nu_div, & se_nu_p, & se_nu_top, & + se_sponge_del4_nu_fac, & + se_sponge_del4_nu_div_fac, & + se_sponge_del4_lev, & se_qsplit, & se_refined_mesh, & se_rsplit, & @@ -205,14 +212,15 @@ subroutine dyn_readnl(NLFileName) se_horz_num_threads, & se_vert_num_threads, & se_tracer_num_threads, & - se_hypervis_dynamic_ref_state,& se_write_restart_unstruct, & se_large_Courant_incr, & se_fvm_supercycling, & se_fvm_supercycling_jet, & se_kmin_jet, & se_kmax_jet, & - se_molecular_diff + se_molecular_diff, & + se_pgf_formulation, & + se_dribble_in_rsplit_loop !-------------------------------------------------------------------------- @@ -258,6 +266,9 @@ subroutine dyn_readnl(NLFileName) call MPI_bcast(se_nu_div, 1, mpi_real8, masterprocid, mpicom, ierr) call MPI_bcast(se_nu_p, 1, mpi_real8, masterprocid, mpicom, ierr) call MPI_bcast(se_nu_top, 1, mpi_real8, masterprocid, mpicom, ierr) + call MPI_bcast(se_sponge_del4_nu_fac, 1, mpi_real8, masterprocid, mpicom, ierr) + call MPI_bcast(se_sponge_del4_nu_div_fac, 1, mpi_real8, masterprocid, mpicom, ierr) + call MPI_bcast(se_sponge_del4_lev, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_qsplit, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_refined_mesh, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_rsplit, 1, mpi_integer, masterprocid, mpicom, ierr) @@ -273,7 +284,6 @@ subroutine dyn_readnl(NLFileName) call MPI_bcast(se_horz_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) call MPI_bcast(se_vert_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) call MPI_bcast(se_tracer_num_threads, 1, MPI_integer, masterprocid, mpicom,ierr) - call MPI_bcast(se_hypervis_dynamic_ref_state, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_write_restart_unstruct, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_large_Courant_incr, 1, mpi_logical, masterprocid, mpicom, ierr) call MPI_bcast(se_fvm_supercycling, 1, mpi_integer, masterprocid, mpicom, ierr) @@ -281,6 +291,8 @@ subroutine dyn_readnl(NLFileName) call MPI_bcast(se_kmin_jet, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_kmax_jet, 1, mpi_integer, masterprocid, mpicom, ierr) call MPI_bcast(se_molecular_diff, 1, mpi_real8, masterprocid, mpicom, ierr) + call MPI_bcast(se_pgf_formulation, 1, mpi_integer, masterprocid, mpicom, ierr) + call MPI_bcast(se_dribble_in_rsplit_loop, 1, mpi_integer, masterprocid, mpicom, ierr) ! If se_npes is set to negative one, then make it match host model: if (se_npes == -1) then se_npes = npes @@ -317,6 +329,9 @@ subroutine dyn_readnl(NLFileName) fine_ne = se_fine_ne ftype = se_ftype statediag_numtrac = MIN(se_statediag_numtrac,num_advected) + sponge_del4_nu_fac = se_sponge_del4_nu_fac + sponge_del4_nu_div_fac = se_sponge_del4_nu_div_fac + sponge_del4_lev = se_sponge_del4_lev hypervis_power = se_hypervis_power hypervis_scaling = se_hypervis_scaling hypervis_subcycle = se_hypervis_subcycle @@ -343,7 +358,6 @@ subroutine dyn_readnl(NLFileName) vert_remap_uvTq_alg = set_vert_remap(se_vert_remap_T, se_vert_remap_uvTq_alg) vert_remap_tracer_alg = set_vert_remap(se_vert_remap_T, se_vert_remap_tracer_alg) fv_nphys = se_fv_nphys - hypervis_dynamic_ref_state = se_hypervis_dynamic_ref_state large_Courant_incr = se_large_Courant_incr fvm_supercycling = se_fvm_supercycling fvm_supercycling_jet = se_fvm_supercycling_jet @@ -351,15 +365,8 @@ subroutine dyn_readnl(NLFileName) kmax_jet = se_kmax_jet variable_nsplit = .false. molecular_diff = se_molecular_diff - !xxx to merge pgf_formulation = se_pgf_formulation - !xxx to merge dribble_in_rsplit_loop = se_dribble_in_rsplit_loop - if (fv_nphys > 0) then - ! Use finite volume physics grid and CSLAM for tracer advection - use_cslam = .true. - else - ! Use GLL grid for physics and tracer advection - use_cslam = .false. - end if + pgf_formulation = se_pgf_formulation + dribble_in_rsplit_loop = se_dribble_in_rsplit_loop if (rsplit < 1) then call endrun('dyn_readnl: rsplit must be > 0') end if @@ -428,14 +435,20 @@ subroutine dyn_readnl(NLFileName) write(iulog, '(a)') 'Note that nu_q must be the same as nu_p for mass / tracer inconsistency' end if write(iulog, '(a,e9.2)') 'dyn_readnl: se_nu_top = ',se_nu_top + write(iulog, *) 'dyn_readnl: se_sponge_del4_nu_fac = ',se_sponge_del4_nu_fac + if (se_sponge_del4_nu_fac < 0) write(iulog, '(a)') ' (automatically set based on model top location)' + write(iulog, *) 'dyn_readnl: se_sponge_del4_nu_div_fac = ',se_sponge_del4_nu_div_fac + if (se_sponge_del4_nu_div_fac < 0) write(iulog, '(a)') ' (automatically set based on model top location)' + write(iulog, *) 'dyn_readnl: se_sponge_del4_lev = ',se_sponge_del4_lev + if (se_sponge_del4_lev < 0) write(iulog, '(a)') ' (automatically set based on model top location)' write(iulog, '(a,i0)') 'dyn_readnl: se_qsplit = ',se_qsplit write(iulog, '(a,i0)') 'dyn_readnl: se_rsplit = ',se_rsplit write(iulog, '(a,i0)') 'dyn_readnl: se_statefreq = ',se_statefreq + write(iulog, '(a,i0)') 'dyn_readnl: se_pgf_formulation = ',pgf_formulation write(iulog, '(a,i0)') 'dyn_readnl: se_tstep_type = ',se_tstep_type write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_T = ',trim(se_vert_remap_T) write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_uvTq_alg = ',trim(se_vert_remap_uvTq_alg) write(iulog, '(a,a)') 'dyn_readnl: se_vert_remap_tracer_alg = ',trim(se_vert_remap_tracer_alg) - write(iulog, '(a,l4)') 'dyn_readnl: se_hypervis_dynamic_ref_state = ',hypervis_dynamic_ref_state write(iulog, '(a,i0)') 'dyn_readnl: se_fvm_supercycling = ',fvm_supercycling write(iulog, '(a,i0)') 'dyn_readnl: se_fvm_supercycling_jet = ',fvm_supercycling_jet write(iulog, '(a,i0)') 'dyn_readnl: se_kmin_jet = ',kmin_jet @@ -542,7 +555,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) use cam_pio_utils, only: clean_iodesc_list use air_composition, only: thermodynamic_active_species_num, thermodynamic_active_species_idx use air_composition, only: thermodynamic_active_species_idx_dycore - use dynconst, only: cpair + use dynconst, only: cpair, pstd use dyn_thermo, only: get_molecular_diff_coef_reference !use cam_history, only: addfld, add_default, horiz_only, register_vector_field use gravity_waves_sources, only: gws_init @@ -551,16 +564,16 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) use prim_advance_mod, only: prim_advance_init use thread_mod, only: horz_num_threads use hybrid_mod, only: get_loop_ranges, config_thread_region - use dimensions_mod, only: nu_scale_top, nu_lev, nu_div_lev + use dimensions_mod, only: nu_scale_top use dimensions_mod, only: ksponge_end, kmvis_ref, kmcnd_ref,rho_ref,km_sponge_factor - use dimensions_mod, only: kmvisi_ref, kmcndi_ref,rhoi_ref use dimensions_mod, only: cnst_name_gll, cnst_longname_gll - use dimensions_mod, only: irecons_tracer_lev, irecons_tracer, otau, kord_tr, kord_tr_cslam + use dimensions_mod, only: irecons_tracer_lev, irecons_tracer, kord_tr, kord_tr_cslam use prim_driver_mod, only: prim_init2 - use time_mod, only: time_at + use se_dyn_time_mod, only: time_at use control_mod, only: runtype, nu_top, molecular_diff use test_fvm_mapping, only: test_mapping_addfld use control_mod, only: vert_remap_uvTq_alg, vert_remap_tracer_alg + use std_atm_profile, only: std_atm_height ! Dummy arguments: type(runtime_options), intent(in) :: cam_runtime_opts @@ -568,9 +581,9 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) type(dyn_export_t), intent(out) :: dyn_out ! Local variables - integer :: ithr, nets, nete, ie, k, kmol_end + integer :: nets, nete, ie, k, kmol_end, mfound real(r8), parameter :: Tinit = 300.0_r8 - real(r8) :: press, ptop, tref + real(r8) :: press(1), ptop, tref,z(1) type(hybrid_t) :: hybrid @@ -579,11 +592,14 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) integer :: iret ! variables for initializing energy and axial angular momentum diagnostics - character (len = 3), dimension(12) :: stage = (/"dED","dAF","dBD","dAD","dAR","dBF","dBH","dCH","dAH",'dBS','dAS','p2d'/) - character (len = 70),dimension(12) :: stage_txt = (/& + integer, parameter :: num_stages = 14 + character (len = 4), dimension(num_stages) :: stage = (/"dED","dAF","dBD","dBL","dAL","dAD","dAR","dBF","dBH","dCH","dAH","dBS","dAS","p2d"/) + character (len = 70),dimension(num_stages) :: stage_txt = (/& " end of previous dynamics ",& !dED " from previous remapping or state passed to dynamics",& !dAF - state in beginning of nsplit loop " state after applying CAM forcing ",& !dBD - state after applyCAMforcing + " before floating dynamics ",& !dBL + " after floating dynamics ",& !dAL " before vertical remapping ",& !dAD - state before vertical remapping " after vertical remapping ",& !dAR - state at end of nsplit loop " state passed to parameterizations ",& !dBF @@ -594,22 +610,6 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) " state after sponge layer diffusion ",& !dAS - state after sponge del2 " phys2dyn mapping errors (requires ftype-1) " & !p2d - for assessing phys2dyn mapping errors /) - character (len = 2) , dimension(8) :: vars = (/"WV" ,"WL" ,"WI" ,"SE" ,"KE" ,"MR" ,"MO" ,"TT" /) - !if ntrac>0 then tracers should be output on fvm grid but not energy (SE+KE) and AAM diags - logical , dimension(8) :: massv = (/.true.,.true.,.true.,.false.,.false.,.false.,.false.,.false./) - character (len = 70) , dimension(8) :: vars_descriptor = (/& - "Total column water vapor ",& - "Total column cloud water ",& - "Total column cloud ice ",& - "Total column dry static energy ",& - "Total column kinetic energy ",& - "Total column wind axial angular momentum",& - "Total column mass axial angular momentum",& - "Total column test tracer "/) - character (len = 14), dimension(8) :: & - vars_unit = (/& - "kg/m2 ","kg/m2 ","kg/m2 ","J/m2 ",& - "J/m2 ","kg*m2/s*rad2 ","kg*m2/s*rad2 ","kg/m2 "/) integer :: istage, ivars character (len=108) :: str1, str2, str3 @@ -619,7 +619,6 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) character(len=*), parameter :: subname = 'dyn_init' - real(r8) :: tau0, krange, otau0, scale real(r8) :: km_sponge_factor_local(nlev+1) !---------------------------------------------------------------------------- @@ -692,7 +691,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) thermodynamic_active_species_liq_idx_dycore(m) = thermodynamic_active_species_liq_idx(m) end if if (masterproc) then - write(iulog,*) sub//": m,thermodynamic_active_species_idx_liq_dycore: ",m,thermodynamic_active_species_liq_idx_dycore(m) + write(iulog,*) subname//": m,thermodynamic_active_species_idx_liq_dycore: ",m,thermodynamic_active_species_liq_idx_dycore(m) end if end do do m=1,thermodynamic_active_species_ice_num @@ -706,7 +705,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) thermodynamic_active_species_ice_idx_dycore(m) = thermodynamic_active_species_ice_idx(m) end if if (masterproc) then - write(iulog,*) sub//": m,thermodynamic_active_species_idx_ice_dycore: ",m,thermodynamic_active_species_ice_idx_dycore(m) + write(iulog,*) subname//": m,thermodynamic_active_species_idx_ice_dycore: ",m,thermodynamic_active_species_ice_idx_dycore(m) end if end do #endif @@ -730,6 +729,14 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) if (initial_run) then call read_inidat(dyn_in) +#ifdef scam + if (use_iop .and. masterproc) then + call setiopupdate_init() + call readiopdata( hvcoord%hyam, hvcoord%hybm, hvcoord%hyai, hvcoord%hybi, hvcoord%ps0 ) + call scm_setinitial(dyn_in%elem) + end if + call clean_iodesc +#endif call clean_iodesc_list() end if ! @@ -744,9 +751,6 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) tref = 1000._r8 !mean value at model top for solar max km_sponge_factor = molecular_diff km_sponge_factor_local = molecular_diff - call get_molecular_diff_coef_reference(tref,& - (hvcoord%hyai(:)+hvcoord%hybi(:))*hvcoord%ps0, km_sponge_factor_local,& - kmvisi_ref,kmcndi_ref,rhoi_ref) ! ! get rho, kmvis and kmcnd at mid-levels ! @@ -754,14 +758,17 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) (hvcoord%hyam(:)+hvcoord%hybm(:))*hvcoord%ps0,km_sponge_factor,& kmvis_ref,kmcnd_ref,rho_ref) + if (masterproc) then + write(iulog,*) "Molecular viscosity and thermal conductivity reference profile" + write(iulog,*) "k, p, z, km_sponge_factor, kmvis_ref/rho_ref, kmcnd_ref/(cp*rho_ref):" + end if do k=1,nlev ! only apply molecular viscosity where viscosity is > 1000 m/s^2 if (MIN(kmvis_ref(k)/rho_ref(k),kmcnd_ref(k)/(cpair*rho_ref(k)))>1000.0_r8) then if (masterproc) then - write(iulog,'(a,i3,2e11.4)') "k, p, km_sponge_factor :",k, & - (hvcoord%hyam(k)+hvcoord%hybm(k))*hvcoord%ps0,km_sponge_factor(k) - write(iulog,'(a,2e11.4)') "kmvis_ref/rho_ref, kmcnd_ref/(cp*rho_ref): ", & - kmvis_ref(k)/rho_ref(k),kmcnd_ref(k)/(cpair*rho_ref(k)) + press = hvcoord%hyam(k)*hvcoord%ps0+hvcoord%hybm(k)*pstd + call std_atm_height(press,z) + write(iulog,'(i3,5e11.4)') k,press, z,km_sponge_factor(k),kmvis_ref(k)/rho_ref(k),kmcnd_ref(k)/(cpair*rho_ref(k)) end if kmol_end = k else @@ -783,26 +790,61 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) ! nu_scale_top(:) = 0.0_r8 if (nu_top>0) then - if (masterproc) write(iulog,*) subname//": sponge layer viscosity scaling factor" - do k=1,nlev - press = (hvcoord%hyam(k)+hvcoord%hybm(k))*hvcoord%ps0 - ptop = hvcoord%hyai(1)*hvcoord%ps0 - nu_scale_top(k) = 8.0_r8*(1.0_r8+tanh(1.0_r8*log(ptop/press))) ! tau will be maximum 8 at model top - if (nu_scale_top(k).ge.0.15_r8) then - ksponge_end = k - else - nu_scale_top(k) = 0.0_r8 - end if - end do + ptop = hvcoord%hyai(1)*hvcoord%ps0 + if (ptop>300.0_r8) then + ! + ! for low tops the tanh formulae below makes the sponge excessively deep + ! + nu_scale_top(1) = 4.0_r8 + nu_scale_top(2) = 2.0_r8 + nu_scale_top(3) = 1.0_r8 + ksponge_end = 3 + else if (ptop>100.0_r8) then + ! + ! CAM6 top (~225 Pa) or CAM7 low top + ! + ! For backwards compatibility numbers below match tanh profile + ! used in FV + ! + nu_scale_top(1) = 4.4_r8 + nu_scale_top(2) = 1.3_r8 + nu_scale_top(3) = 3.9_r8 + ksponge_end = 3 + else if (ptop>1e-1_r8) then + ! + ! CAM7 FMT + ! + nu_scale_top(1) = 3.0_r8 + nu_scale_top(2) = 1.0_r8 + nu_scale_top(3) = 0.1_r8 + nu_scale_top(4) = 0.05_r8 + ksponge_end = 4 + else if (ptop>1e-4_r8) then + ! + ! WACCM and WACCM-x + ! + nu_scale_top(1) = 5.0_r8 + nu_scale_top(2) = 5.0_r8 + nu_scale_top(3) = 5.0_r8 + nu_scale_top(4) = 2.0_r8 + nu_scale_top(5) = 1.0_r8 + nu_scale_top(6) = 0.1_r8 + ksponge_end = 6 + end if else - ksponge_end = 0 + ksponge_end = 0 end if ksponge_end = MAX(MAX(ksponge_end,1),kmol_end) if (masterproc) then write(iulog,*) subname//": ksponge_end = ",ksponge_end + write(iulog,*) subname//": sponge layer Laplacian damping" + write(iulog,*) "k, p, z, nu_scale_top, nu (actual Laplacian damping coefficient)" if (nu_top>0) then - do k=1,ksponge_end - write(iulog,'(a,i3,1e11.4)') subname//": nu_scale_top ",k,nu_scale_top(k) + do k=1,ksponge_end+1 + press = (hvcoord%hyam(k)+hvcoord%hybm(k))*hvcoord%ps0 + call std_atm_height(press,z) + write(iulog,'(i3,4e11.4)') k,press,z,& + nu_scale_top(k),nu_scale_top(k)*nu_top end do end if end if @@ -855,7 +897,7 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) ! Energy diagnostics and axial angular momentum diagnostics call addfld ('ABS_dPSdt', horiz_only, 'A', 'Pa/s', 'Absolute surface pressure tendency',gridname='GLL') - if (ntrac>0) then + if (use_cslam) then #ifdef waccm_debug call addfld ('CSLAM_gamma', (/ 'lev' /), 'A', '', 'Courant number from CSLAM', gridname='FVM') #endif @@ -922,7 +964,63 @@ subroutine dyn_init(cam_runtime_opts, dyn_in, dyn_out) !Remove/replace after CAMDEN history output is enabled -JN: #endif - +#ifdef cam_thermo_history + if (thermo_budget_history) then + ! Register stages for budgets + do istage = 1, num_stages + call cam_budget_em_snapshot(TRIM(ADJUSTL(stage(istage))), 'dyn', & + longname=TRIM(ADJUSTL(stage_txt(istage)))) + end do + ! + ! Register tendency (difference) budgets + ! + call cam_budget_em_register('dEdt_floating_dyn' ,'dAL','dBL','dyn','dif', & + longname="dE/dt floating dynamics (dAL-dBL)" ) + call cam_budget_em_register('dEdt_vert_remap' ,'dAR','dAD','dyn','dif', & + longname="dE/dt vertical remapping (dAR-dAD)" ) + call cam_budget_em_register('dEdt_phys_tot_in_dyn','dBD','dAF','dyn','dif', & + longname="dE/dt physics tendency in dynamics (dBD-dAF)" ) + call cam_budget_em_register('dEdt_del4' ,'dCH','dBH','dyn','dif', & + longname="dE/dt del4 (dCH-dBH)" ) + call cam_budget_em_register('dEdt_del4_fric_heat','dAH','dCH','dyn','dif', & + longname="dE/dt del4 frictional heating (dAH-dCH)" ) + call cam_budget_em_register('dEdt_del4_tot' ,'dAH','dBH','dyn','dif', & + longname="dE/dt del4 + del4 frictional heating (dAH-dBH)" ) + call cam_budget_em_register('dEdt_del2_sponge' ,'dAS','dBS','dyn','dif', & + longname="dE/dt del2 sponge (dAS-dBS)" ) + ! + ! Register derived budgets + ! + call cam_budget_em_register('dEdt_dycore' ,'dEdt_floating_dyn','dEdt_vert_remap' ,'dyn','sum', & + longname="dE/dt adiabatic dynamics" ) + call cam_budget_em_register('dEdt_del2_del4_tot' ,'dEdt_del4_tot' ,'dEdt_del2_sponge' ,'dyn','sum', & + longname="dE/dt explicit diffusion total" ) + call cam_budget_em_register('dEdt_residual' ,'dEdt_floating_dyn','dEdt_del2_del4_tot','dyn','dif',& + longname="dE/dt residual (dEdt_floating_dyn-dEdt_del2_del4_tot)" ) + end if + ! + ! add dynamical core tracer tendency output + ! + if (use_cslam) then + do m = 1, pcnst + call addfld(tottnam(m),(/ 'lev' /),'A','kg/kg/s',trim(cnst_name(m))//' horz + vert', & + gridname='FVM') + end do + else + do m = 1, pcnst + call addfld(tottnam(m),(/ 'lev' /),'A','kg/kg/s',trim(cnst_name(m))//' horz + vert', & + gridname='GLL') + end do + end if + call phys_getopts(history_budget_out=history_budget, history_budget_histfile_num_out=budget_hfile_num) + if ( history_budget ) then + call cnst_get_ind('CLDLIQ', ixcldliq) + call cnst_get_ind('CLDICE', ixcldice) + call add_default(tottnam( 1), budget_hfile_num, ' ') + call add_default(tottnam(ixcldliq), budget_hfile_num, ' ') + call add_default(tottnam(ixcldice), budget_hfile_num, ' ') + end if +#endif end subroutine dyn_init !========================================================================================= @@ -932,14 +1030,16 @@ subroutine dyn_run(dyn_state) use air_composition, only: thermodynamic_active_species_idx_dycore !Se dycore: - use prim_advance_mod, only: calc_tot_energy_dynamics use prim_driver_mod, only: prim_run_subcycle use dimensions_mod, only: cnst_name_gll - use time_mod, only: tstep, nsplit, timelevel_qdp + use se_dyn_time_mod, only: tstep, nsplit, timelevel_qdp, tevolve use hybrid_mod, only: config_thread_region, get_loop_ranges use control_mod, only: qsplit, rsplit, ftype_conserve use thread_mod, only: horz_num_threads - use time_mod, only: tevolve +#ifdef scam + use scamMod, only: single_column, use_3dfrc + use se_single_column_mod, only: apply_SC_forcing,ie_scm +#endif type(dyn_export_t), intent(inout) :: dyn_state @@ -959,6 +1059,7 @@ subroutine dyn_run(dyn_state) real(r8), allocatable, dimension(:,:,:) :: ps_before real(r8), allocatable, dimension(:,:,:) :: abs_ps_tend real (kind=r8) :: omega_cn(2,nelemd) !min and max of vertical Courant number + integer :: nets_in,nete_in character(len=*), parameter :: subname = 'dyn_run' @@ -1030,22 +1131,21 @@ subroutine dyn_run(dyn_state) #endif ! convert elem(ie)%derived%fq to mass tendency -!xxx for cslam only merge if (.not.use_cslam) then - do ie = nets, nete - do m = 1, qsize + if (.not.use_cslam) then + do ie = nets, nete + do m = 1, qsize do k = 1, nlev - do j = 1, np - do i = 1, np - dyn_state%elem(ie)%derived%FQ(i,j,k,m) = dyn_state%elem(ie)%derived%FQ(i,j,k,m)* & - rec2dt*dyn_state%elem(ie)%state%dp3d(i,j,k,tl_f) - end do - end do + do j = 1, np + do i = 1, np + dyn_state%elem(ie)%derived%FQ(i,j,k,m) = dyn_state%elem(ie)%derived%FQ(i,j,k,m)* & + rec2dt*dyn_state%elem(ie)%state%dp3d(i,j,k,tl_f) + end do + end do end do - end do - end do - !xxx end if -!xxx for cslam only merge if (ftype_conserve>0.and..not.use_cslam) then - if (ftype_conserve>0) then + end do + end do + end if + if (ftype_conserve>0.and..not.use_cslam) then do ie = nets, nete do k=1,nlev do j=1,np @@ -1061,26 +1161,23 @@ subroutine dyn_run(dyn_state) end do end do end if - if (use_cslam) then - do ie = nets, nete - do m = 1, ntrac - do k = 1, nlev - do j = 1, nc - do i = 1, nc - dyn_state%fvm(ie)%fc(i,j,k,m) = dyn_state%fvm(ie)%fc(i,j,k,m)* & - rec2dt!*dyn_state%fvm(ie)%dp_fvm(i,j,k) - end do - end do - end do + do ie = nets, nete + do m = 1, ntrac + do k = 1, nlev + do j = 1, nc + do i = 1, nc + dyn_state%fvm(ie)%fc(i,j,k,m) = dyn_state%fvm(ie)%fc(i,j,k,m)* & + rec2dt!*dyn_state%fvm(ie)%dp_fvm(i,j,k) + end do + end do end do - end do + end do + end do end if - if (ldiag) then abs_ps_tend(:,:,nets:nete) = 0.0_r8 endif - do n = 1, nsplit_local if (ldiag) then @@ -1088,11 +1185,21 @@ subroutine dyn_run(dyn_state) ps_before(:,:,ie) = dyn_state%elem(ie)%state%psdry(:,:) end do end if - +#ifdef scam + if (single_column) then + nets_in=ie_scm + nete_in=ie_scm + else + nets_in=nets + nete_in=nete + end if ! forward-in-time RK, with subcycling - call prim_run_subcycle(dyn_state%elem, dyn_state%fvm, hybrid, nets, nete, & + call prim_run_subcycle(dyn_state%elem, dyn_state%fvm, hybrid, nets_in, nete_in, & tstep, TimeLevel, hvcoord, n, omega_cn) - +#else + call prim_run_subcycle(dyn_state%elem, dyn_state%fvm, hybrid, nets, nete, & + tstep, TimeLevel, hvcoord, n, .false., omega_cn) +#endif if (ldiag) then do ie = nets, nete abs_ps_tend(:,:,ie) = abs_ps_tend(:,:,ie) + & @@ -1102,7 +1209,6 @@ subroutine dyn_run(dyn_state) end if end do - !Uncomment once "outfld" is enabled in CAMDEN-JN: #if 0 if (ldiag) then @@ -1113,7 +1219,6 @@ subroutine dyn_run(dyn_state) end if #endif - call calc_tot_energy_dynamics(dyn_state%elem,dyn_state%fvm, nets, nete, TimeLevel%n0, n0_qdp,'dBF') !$OMP END PARALLEL !Uncomment once "outfld" is enabled in CAMDEN-JN: @@ -1121,10 +1226,14 @@ subroutine dyn_run(dyn_state) if (ldiag) then deallocate(ps_before,abs_ps_tend) endif +#ifdef SCAM + if (single_column) then + call apply_SC_forcing(dyn_state%elem,hvcoord,TimeLevel,3,.false.) + end if +#endif ! output vars on CSLAM fvm grid call write_dyn_vars(dyn_state) #endif - end subroutine dyn_run !=============================================================================== @@ -1150,7 +1259,7 @@ subroutine read_inidat(dyn_in) use fvm_mapping, only: dyn2fvm_mass_vars use control_mod, only: runtype,initial_global_ave_dry_ps use prim_driver_mod, only: prim_set_dry_mass - + use cam_initfiles, only: scale_dry_air_mass ! Arguments type (dyn_import_t), target, intent(inout) :: dyn_in ! dynamics import @@ -1715,21 +1824,15 @@ subroutine read_inidat(dyn_in) end do end if - ! scale PS to achieve prescribed dry mass following FV dycore (dryairm.F90) -#ifndef planet_mars + ! If scale_dry_air_mass > 0.0 then scale dry air mass to scale_dry_air_mass global average dry pressure if (runtype == 0) then - initial_global_ave_dry_ps = 98288.0_r8 - if (.not. associated(fh_topo)) then - initial_global_ave_dry_ps = 101325._r8 - 245._r8 - end if - if (simple_phys) then - initial_global_ave_dry_ps = 0 !do not scale psdry - end if - if (iam < par%nprocs) then - call prim_set_dry_mass(elem, hvcoord, initial_global_ave_dry_ps, qtmp) - end if - endif -#endif + if (scale_dry_air_mass > 0.0_r8) then + if (iam < par%nprocs) then + call prim_set_dry_mass(elem, hvcoord, scale_dry_air_mass, qtmp) + end if + end if + end if + ! store Q values: ! ! if CSLAM is NOT active then state%Qdp for all constituents @@ -1879,6 +1982,7 @@ subroutine set_phis(dyn_in) integer :: ierr, pio_errtype character(len=max_fieldname_len) :: fieldname + character(len=max_fieldname_len) :: fieldname_gll character(len=max_hcoordname_len):: grid_name integer :: dims(2) integer :: dyn_cols @@ -1946,12 +2050,19 @@ subroutine set_phis(dyn_in) ! Set name of grid object which will be used to read data from file ! into internal data structure via PIO. - if (fv_nphys == 0) then - grid_name = 'GLL' - else - grid_name = 'physgrid_d' +#ifdef scam + if (single_column) then + grid_name = 'SCM' + else +#endif + if (fv_nphys == 0) then + grid_name = 'GLL' + else + grid_name = 'physgrid_d' + end if +#ifdef scam end if - +#endif ! Get number of global columns from the grid object and check that ! it matches the file data. call cam_grid_dimensions(grid_name, dims) @@ -1963,7 +2074,11 @@ subroutine set_phis(dyn_in) call endrun(subname//': dimension ncol not found in bnd_topo file') end if ierr = pio_inq_dimlen(fh_topo, ncol_did, ncol_size) +#ifdef scam + if (ncol_size /= dyn_cols .and. .not. single_column) then +#else if (ncol_size /= dyn_cols) then +#endif if (masterproc) then write(iulog,*) subname//': ncol_size=', ncol_size, ' : dyn_cols=', dyn_cols end if @@ -1971,19 +2086,43 @@ subroutine set_phis(dyn_in) end if fieldname = 'PHIS' -!xxx GLL topo merge fieldname_gll = 'PHIS_gll' - if (dyn_field_exists(fh_topo, trim(fieldname))) then - if (fv_nphys == 0) then - call read_dyn_var(fieldname, fh_topo, 'ncol', phis_tmp) + fieldname_gll = 'PHIS_gll' + if (use_cslam.and.dyn_field_exists(fh_topo, trim(fieldname_gll),required=.false.)) then + ! + ! If physgrid it is recommended to read in PHIS on the GLL grid and then + ! map to the physgrid in d_p_coupling + ! + ! This requires a topo file with PHIS_gll on it ... + ! + if (masterproc) then + write(iulog, *) "Reading in PHIS on GLL grid (mapped to physgrid in d_p_coupling)" + end if + call read_dyn_var(fieldname_gll, fh_topo, 'ncol_gll', phis_tmp) + else if (dyn_field_exists(fh_topo, trim(fieldname))) then + if (.not.use_cslam) then + if (masterproc) then + write(iulog, *) "Reading in PHIS" + end if + call read_dyn_var(fieldname, fh_topo, 'ncol', phis_tmp) else - call read_phys_field_2d(fieldname, fh_topo, 'ncol', phis_phys_tmp) - call map_phis_from_physgrid_to_gll(dyn_in%fvm, elem, phis_phys_tmp, & - phis_tmp, pmask) + ! + ! For backwards compatibility we allow reading in PHIS on the physgrid + ! which is then mapped to the GLL grid and back to the physgrid in d_p_coupling + ! (the latter is to avoid noise in derived quantities such as PSL) + ! + if (masterproc) then + write(iulog, *) "Reading in PHIS on physgrid" + write(iulog, *) "Recommended to read in PHIS on GLL grid" + end if + call read_phys_field_2d(fieldname, fh_topo, 'ncol', phis_phys_tmp) + call map_phis_from_physgrid_to_gll(dyn_in%fvm, elem, phis_phys_tmp, & + phis_tmp, pmask) + deallocate(phis_phys_tmp) end if else call endrun(subname//': Could not find PHIS field on input datafile') end if - + ! Put the error handling back the way it was call pio_seterrorhandling(fh_topo, pio_errtype) @@ -2018,57 +2157,8 @@ subroutine set_phis(dyn_in) call analytic_ic_set_ic(vcoord, latvals, lonvals, glob_ind, & PHIS_OUT=phis_tmp, mask=pmask(:)) deallocate(glob_ind) + end if - if (fv_nphys > 0) then - - ! initialize PHIS on physgrid - allocate(latvals_phys(fv_nphys*fv_nphys*nelemd), stat=ierr) - call check_allocate(ierr, subname, 'latvals_phys(fv_nphys*fv_nphys*nelemd)', & - file=__FILE__, line=__LINE__) - - allocate(lonvals_phys(fv_nphys*fv_nphys*nelemd), stat=ierr) - call check_allocate(ierr, subname, 'lonvals_phys(fv_nphys*fv_nphys*nelemd)', & - file=__FILE__, line=__LINE__) - - indx = 1 - do ie = 1, nelemd - do j = 1, fv_nphys - do i = 1, fv_nphys - latvals_phys(indx) = dyn_in%fvm(ie)%center_cart_physgrid(i,j)%lat - lonvals_phys(indx) = dyn_in%fvm(ie)%center_cart_physgrid(i,j)%lon - indx = indx + 1 - end do - end do - end do - - allocate(pmask_phys(fv_nphys*fv_nphys*nelemd), stat=ierr) - call check_allocate(ierr, subname, 'pmask_phys(fv_nphys*fv_nphys*nelemd)', & - file=__FILE__, line=__LINE__) - - pmask_phys(:) = .true. - allocate(glob_ind(fv_nphys*fv_nphys*nelemd), stat=ierr) - call check_allocate(ierr, subname, 'glob_ind(fv_nphys*fv_nphys*nelemd)', & - file=__FILE__, line=__LINE__) - - j = 1 - do ie = 1, nelemd - do i = 1, fv_nphys*fv_nphys - ! Create a global(ish) column index - glob_ind(j) = elem(ie)%GlobalId - j = j + 1 - end do - end do - - call analytic_ic_set_ic(vcoord, latvals_phys, lonvals_phys, glob_ind, & - PHIS_OUT=phis_phys_tmp, mask=pmask_phys) - - deallocate(latvals_phys) - deallocate(lonvals_phys) - deallocate(pmask_phys) - deallocate(glob_ind) - end if - - end if deallocate(pmask) @@ -2083,16 +2173,7 @@ subroutine set_phis(dyn_in) end do end do end do - if (fv_nphys > 0) then - do ie = 1, nelemd - dyn_in%fvm(ie)%phis_physgrid = RESHAPE(phis_phys_tmp(:,ie),(/fv_nphys,fv_nphys/)) - end do - end if - deallocate(phis_tmp) - if (fv_nphys > 0) then - deallocate(phis_phys_tmp) - end if ! boundary exchange to update the redundent columns in the element objects do ie = 1, nelemd diff --git a/src/dynamics/se/dyn_grid.F90 b/src/dynamics/se/dyn_grid.F90 index bf61ff37..09b40170 100644 --- a/src/dynamics/se/dyn_grid.F90 +++ b/src/dynamics/se/dyn_grid.F90 @@ -49,7 +49,7 @@ module dyn_grid use prim_init, only: prim_init1 use edge_mod, only: initEdgeBuffer use edgetype_mod, only: EdgeBuffer_t -use time_mod, only: TimeLevel_t +use se_dyn_time_mod, only: TimeLevel_t use dof_mod, only: UniqueCoords, UniquePoints implicit none @@ -60,6 +60,7 @@ module dyn_grid integer, parameter :: fvm_decomp = 102 ! The FVM (CSLAM) grid integer, parameter :: physgrid_d = 103 ! physics grid on dynamics decomp integer, parameter :: ini_decomp = 104 ! alternate dynamics grid for reading initial file +integer, parameter :: ini_decomp_scm = 205 ! alternate dynamics grid for reading initial file character(len=3), protected :: ini_grid_name @@ -135,7 +136,7 @@ subroutine model_grid_init() use hybrid_mod, only: hybrid_t, init_loop_ranges, & get_loop_ranges, config_thread_region use control_mod, only: qsplit, rsplit - use time_mod, only: tstep, nsplit + use se_dyn_time_mod, only: tstep, nsplit use fvm_mod, only: fvm_init2, fvm_init3, fvm_pg_init use dimensions_mod, only: irecons_tracer, dimensions_mod_init, qsize use comp_gll_ctr_vol, only: gll_grid_write @@ -779,7 +780,9 @@ subroutine define_cam_grids() use cam_grid_support, only: horiz_coord_t, horiz_coord_create use cam_grid_support, only: cam_grid_register, cam_grid_attribute_register - +#ifdef SCAM + use scamMod, only: closeioplon,closeioplat,closeioplonidx,single_column +#endif !SE dycore: use dimensions_mod, only: nc @@ -790,6 +793,7 @@ subroutine define_cam_grids() type(horiz_coord_t), pointer :: lat_coord type(horiz_coord_t), pointer :: lon_coord integer(iMap), pointer :: grid_map(:,:) + integer(iMap), pointer :: grid_map_scm(:,:) !grid_map decomp for single column mode real(r8), allocatable :: pelat_deg(:) ! pe-local latitudes (degrees) real(r8), allocatable :: pelon_deg(:) ! pe-local longitudes (degrees) @@ -797,6 +801,7 @@ subroutine define_cam_grids() real(r8) :: areaw(np,np) integer(iMap) :: fdofP_local(npsq,nelemd) ! pe-local map for dynamics decomp integer(iMap), allocatable :: pemap(:) ! pe-local map for PIO decomp + integer(iMap), allocatable :: pemap_scm(:) ! pe-local map for single column PIO decomp integer :: ncols_fvm, ngcols_fvm real(r8), allocatable :: fvm_coord(:) @@ -933,7 +938,43 @@ subroutine define_cam_grids() ! grid_map cannot be deallocated as the cam_filemap_t object just points ! to it. It can be nullified. nullify(grid_map) +#ifdef SCAM + !--------------------------------- + ! Create SCM grid object when running single column mode + !--------------------------------- + if ( single_column) then + allocate(pemap_scm(1)) + pemap_scm = 0_iMap + pemap_scm = closeioplonidx + + ! Map for scm grid + allocate(grid_map_scm(3,npsq)) + grid_map_scm = 0_iMap + mapind = 1 + j = 1 + do i = 1, npsq + grid_map_scm(1, mapind) = i + grid_map_scm(2, mapind) = j + grid_map_scm(3, mapind) = pemap_scm(1) + mapind = mapind + 1 + end do + latval=closeioplat + lonval=closeioplon + + lat_coord => horiz_coord_create('lat', 'ncol', 1, & + 'latitude', 'degrees_north', 1, 1, latval, map=pemap_scm) + lon_coord => horiz_coord_create('lon', 'ncol', 1, & + 'longitude', 'degrees_east', 1, 1, lonval, map=pemap_scm) + + call cam_grid_register('SCM', ini_decomp_scm, lat_coord, lon_coord, & + grid_map_scm, block_indexed=.false., unstruct=.true.) + deallocate(pemap_scm) + ! grid_map cannot be deallocated as the cam_filemap_t object just points + ! to it. It can be nullified. + nullify(grid_map_scm) + end if +#endif !--------------------------------- ! Create FVM grid object for CSLAM !--------------------------------- diff --git a/src/dynamics/se/namelist_definition_se_dycore.xml b/src/dynamics/se/namelist_definition_se_dycore.xml index 580ed330..82cb3597 100644 --- a/src/dynamics/se/namelist_definition_se_dycore.xml +++ b/src/dynamics/se/namelist_definition_se_dycore.xml @@ -259,22 +259,59 @@ 2.0e5 - - logical + + real se dyn_se_nl - Hyperscosity for T and dp is applied to (T-Tref) and (dp-dp_ref) where - Xref are reference states where the effect of topography has been removed - (Simmons and Jiabin, 1991, QJRMS, Section 2a). - If TRUE dp_ref is dynamic smoothed reference state derived by Patrick Callaghan - (Lauritzen et al., 2018, JAMES, Appendix A.2) and temperature reference state - based on Simmons and Jiabin (1991) but using smoothed dp_ref. - If FALSE Tref is static reference state (Simmons and Jiabin) and dp_ref state - derived from hydrostatic balance. + Hyperviscosity coefficient se_nu [m^4/s] for u,v, T is increased to + se_nu_p*se_sponge_del4_nu_fac following a hyperbolic tangent function + centered around pressure at vertical index se_sponge_del4_lev: + + 0.5_r8*(1.0_r8+tanh(2.0_r8*log(pmid(se_sponge_del4_lev)/press))) + + where press is pressure + + If < 0, se_sponge_del4_nu_fac is automatically set based on model top location. + Default: Set by build-namelist. - .false. + -1 + + + + real + se> + dyn_se_nl + + Divergence damping hyperviscosity coefficient se_nu_div [m^4/s] for u,v is increased to + se_nu_p*se_sponge_del4_nu_div_fac following a hyperbolic tangent function + centered around pressure at vertical index se_sponge_del4_lev: + + 0.5_r8*(1.0_r8+tanh(2.0_r8*log(pmid(se_sponge_del4_lev)/press))) + + where press is pressure + + If < 0, se_sponge_del4_nu_div_fac is automatically set based on model top location. + + + -1 + + + + real + se> + dyn_se_nl + + Level index around which increased del4 damping is centered. + + See se_sponge_del4_nu_fac and se_sponge_del4_nu_div_fac + + If < 0, se_sponge_del4_lev is automatically set based on model top location. + Default: Set by build-namelist. + + + -1 @@ -607,4 +644,42 @@ 0 + + integer + se + dyn_se_nl + 1,2,3 + + 1: Exner version of pressure gradient force (PGF) + see Appendix A in https://agupubs.onlinelibrary.wiley.com/doi/epdf/10.1029/2022MS003192 + + 2: Traditional pressure gradient formulation (grad p) + + 3: Hybrid (formulation 1 where hybm>0 else formulation 2) + Use hybrid PGF option for WACCM-x to make WACCM-x consistent with PGF + used in CAM in the troposphere and traditional PGF formulation above + + + 1 + 3 + + + + integer + se + dyn_se_nl + 0,1 + + 0: physics tendencies will be added every vertical remapping time-step (dt_phys/se_nsplit) + for se_ftype=0,2 + + 1: physics tendencies will be added every dynamics time-step (dt_phys/se_nsplit*se_rsplit) + for se_ftype=0,2 + + If se_ftype=1 then se_dribble_in_rsplit_loop has no effect since physics tendencies are added as an adjustment + + + 1 + + diff --git a/src/dynamics/se/stepon.F90 b/src/dynamics/se/stepon.F90 index 138a6125..11118bdb 100644 --- a/src/dynamics/se/stepon.F90 +++ b/src/dynamics/se/stepon.F90 @@ -10,7 +10,11 @@ module stepon !SE dycore: use parallel_mod, only: par use dimensions_mod, only: nelemd - +#ifdef scam +use scamMod, only: use_iop, doiopupdate, single_column, & + setiopupdate, readiopdata +use se_single_column_mod, only: scm_setfield, iop_broadcast +#endif implicit none private save @@ -26,12 +30,52 @@ module stepon !========================================================================================= subroutine stepon_init(cam_runtime_opts, dyn_in, dyn_out) - +#ifdef constituents + use constituents, only: pcnst, cnst_name, cnst_longname + use dimensions_mod, only: fv_nphys, cnst_name_gll, cnst_longname_gll, qsize +#endif ! Dummy arguments type(runtime_options), intent(in) :: cam_runtime_opts ! Runtime settings object type(dyn_import_t), intent(in) :: dyn_in ! Dynamics import container type(dyn_export_t), intent(in) :: dyn_out ! Dynamics export container + ! local variables + integer :: m, m_cnst +#ifdef constituents + !---------------------------------------------------------------------------- + ! These fields on dynamics grid are output before the call to d_p_coupling. + do m_cnst = 1, qsize + call addfld(trim(cnst_name_gll(m_cnst))//'_gll', (/ 'lev' /), 'I', 'kg/kg', & + trim(cnst_longname_gll(m_cnst)), gridname='GLL') + call addfld(trim(cnst_name_gll(m_cnst))//'dp_gll', (/ 'lev' /), 'I', 'kg/kg', & + trim(cnst_longname_gll(m_cnst))//'*dp', gridname='GLL') + end do + call addfld('U_gll' ,(/ 'lev' /), 'I', 'm/s ','U wind on gll grid',gridname='GLL') + call addfld('V_gll' ,(/ 'lev' /), 'I', 'm/s ','V wind on gll grid',gridname='GLL') + call addfld('T_gll' ,(/ 'lev' /), 'I', 'K ' ,'T on gll grid' ,gridname='GLL') + call addfld('dp_ref_gll' ,(/ 'lev' /), 'I', ' ' ,'dp dry / dp_ref on gll grid' ,gridname='GLL') + call addfld('PSDRY_gll' ,horiz_only , 'I', 'Pa ' ,'psdry on gll grid' ,gridname='GLL') + call addfld('PS_gll' ,horiz_only , 'I', 'Pa ' ,'ps on gll grid' ,gridname='GLL') + call addfld('PHIS_gll' ,horiz_only , 'I', 'Pa ' ,'PHIS on gll grid' ,gridname='GLL') + + ! Fields for initial condition files + call addfld('U&IC', (/ 'lev' /), 'I', 'm/s', 'Zonal wind', gridname='GLL' ) + call addfld('V&IC', (/ 'lev' /), 'I', 'm/s', 'Meridional wind',gridname='GLL' ) + ! Don't need to register U&IC V&IC as vector components since we don't interpolate IC files + call add_default('U&IC',0, 'I') + call add_default('V&IC',0, 'I') + + call addfld('PS&IC', horiz_only, 'I', 'Pa', 'Surface pressure', gridname='GLL') + call addfld('T&IC', (/ 'lev' /), 'I', 'K', 'Temperature', gridname='GLL') + call add_default('PS&IC', 0, 'I') + call add_default('T&IC', 0, 'I') + + do m_cnst = 1,pcnst + call addfld(trim(cnst_name(m_cnst))//'&IC', (/ 'lev' /), 'I', 'kg/kg', & + trim(cnst_longname(m_cnst)), gridname='GLL') + call add_default(trim(cnst_name(m_cnst))//'&IC', 0, 'I') + end do +#endif end subroutine stepon_init !========================================================================================= @@ -44,7 +88,7 @@ subroutine stepon_timestep_init(dtime_out, cam_runtime_opts, phys_state, & use dp_coupling, only: d_p_coupling ! dynamics-physics coupling !SE dycore: - use time_mod, only: tstep ! dynamics timestep + use se_dyn_time_mod, only: tstep ! dynamics timestep ! Dummy arguments real(r8), intent(out) :: dtime_out ! Time-step (s) @@ -66,14 +110,39 @@ subroutine stepon_timestep_init(dtime_out, cam_runtime_opts, phys_state, & ! write diagnostic fields on gll grid and initial file call diag_dynvar_ic(dyn_out%elem, dyn_out%fvm) end if +#ifdef scam + + ! Determine whether it is time for an IOP update; + ! doiopupdate set to true if model time step > next available IOP + + + if (use_iop .and. masterproc) then + call setiopupdate + end if + if (single_column) then + + ! If first restart step then ensure that IOP data is read + if (is_first_restart_step()) then + if (masterproc) call readiopdata( hvcoord%hyam, hvcoord%hybm, hvcoord%hyai, hvcoord%hybi, hvcoord%ps0 ) + call iop_broadcast() + endif + + iop_update_phase1 = .true. + if ((is_first_restart_step() .or. doiopupdate) .and. masterproc) then + call readiopdata( hvcoord%hyam, hvcoord%hybm, hvcoord%hyai, hvcoord%hybi, hvcoord%ps0 ) + endif + call iop_broadcast() + + call scm_setfield(dyn_out%elem,iop_update_phase1) + endif +#endif ! Synchronize all PEs and then transfer dynamics variables to physics: call t_barrierf('sync_d_p_coupling', mpicom) call t_startf('d_p_coupling') ! Move data into phys_state structure. call d_p_coupling(cam_runtime_opts, phys_state, phys_tend, dyn_out) call t_stopf('d_p_coupling') - end subroutine stepon_timestep_init !========================================================================================= @@ -85,9 +154,9 @@ subroutine stepon_run2(cam_runtime_opts, phys_state, phys_tend, dyn_in, dyn_out) use dyn_grid, only: TimeLevel !SE dycore: - use time_mod, only: TimeLevel_Qdp + use se_dyn_time_mod, only: TimeLevel_Qdp use control_mod, only: qsplit - use prim_advance_mod, only: calc_tot_energy_dynamics + use prim_advance_mod, only: tot_energy_dyn ! Dummy arguments type(runtime_options), intent(in) :: cam_runtime_opts ! Runtime settings object @@ -98,12 +167,12 @@ subroutine stepon_run2(cam_runtime_opts, phys_state, phys_tend, dyn_in, dyn_out) ! Local variables integer :: tl_f, tl_fQdp + !---------------------------------------------------------------------------- !Determine appropriate time values: tl_f = TimeLevel%n0 ! timelevel which was adjusted by physics call TimeLevel_Qdp(TimeLevel, qsplit, tl_fQdp) - ! Synchronize all PEs and then transfer physics variables to dynamics: call t_barrierf('sync_p_d_coupling', mpicom) call t_startf('p_d_coupling') @@ -112,7 +181,7 @@ subroutine stepon_run2(cam_runtime_opts, phys_state, phys_tend, dyn_in, dyn_out) call t_stopf('p_d_coupling') if (iam < par%nprocs) then - call calc_tot_energy_dynamics(dyn_in%elem,dyn_in%fvm, 1, nelemd, tl_f, tl_fQdp,'dED') + call tot_energy_dyn(dyn_in%elem,dyn_in%fvm, 1, nelemd, tl_f, tl_fQdp,'dED') end if end subroutine stepon_run2 @@ -126,10 +195,12 @@ subroutine stepon_run3(dtime, cam_runtime_opts, cam_out, phys_state, dyn_in, dyn !SE/CAM interface: use dyn_comp, only: dyn_run use dyn_grid, only: TimeLevel +#ifdef scam + use advect_tend, only: compute_write_iop_fields +#endif use advect_tend, only: compute_adv_tends_xyz - !SE dycore: - use time_mod, only: TimeLevel_Qdp + use se_dyn_time_mod,only: TimeLevel_Qdp use control_mod, only: qsplit ! Dummy arguments @@ -143,13 +214,26 @@ subroutine stepon_run3(dtime, cam_runtime_opts, cam_out, phys_state, dyn_in, dyn ! Local variables integer :: tl_f, tl_fQdp !-------------------------------------------------------------------------------------- - +#ifdef scam + if (single_column) then + ! Update IOP properties e.g. omega, divT, divQ + iop_update_phase1 = .false. + if (doiopupdate) then + if (masterproc) call readiopdata( hvcoord%hyam, hvcoord%hybm, hvcoord%hyai, hvcoord%hybi, hvcoord%ps0 ) + call iop_broadcast() + call scm_setfield(dyn_out%elem,iop_update_phase1) + endif + endif +#endif ! Determine appropriate time values and ! initalize advected constituent mixing ratios: call t_startf('comp_adv_tends1') tl_f = TimeLevel%n0 call TimeLevel_Qdp(TimeLevel, qsplit, tl_fQdp) call compute_adv_tends_xyz(dyn_in%elem,dyn_in%fvm,1,nelemd,tl_fQdp,tl_f) +#ifdef scam + if (write_camiop) call compute_write_iop_fields(dyn_in%elem,dyn_in%fvm,1,nelemd,tl_fQdp,tl_f) +#endif call t_stopf('comp_adv_tends1') ! Synchronize all PEs and then run dynamics (dyn_run): @@ -164,6 +248,9 @@ subroutine stepon_run3(dtime, cam_runtime_opts, cam_out, phys_state, dyn_in, dyn tl_f = TimeLevel%n0 call TimeLevel_Qdp(TimeLevel, qsplit, tl_fQdp) call compute_adv_tends_xyz(dyn_in%elem,dyn_in%fvm,1,nelemd,tl_fQdp,tl_f) +#ifdef scam + if (write_camiop) call compute_write_iop_fields(dyn_in%elem,dyn_in%fvm,1,nelemd,tl_fQdp,tl_f) +#endif call t_stopf('comp_adv_tends2') end subroutine stepon_run3 @@ -192,7 +279,7 @@ subroutine diag_dynvar_ic(elem, fvm) use cam_abortutils, only: endrun, check_allocate !SE dycore: - use time_mod, only: TimeLevel_Qdp ! dynamics typestep + use se_dyn_time_mod, only: TimeLevel_Qdp ! dynamics typestep use control_mod, only: qsplit use hybrid_mod, only: config_thread_region, get_loop_ranges use hybrid_mod, only: hybrid_t diff --git a/src/dynamics/utils/dynconst.F90 b/src/dynamics/utils/dynconst.F90 index 78c5b04c..93c2d863 100644 --- a/src/dynamics/utils/dynconst.F90 +++ b/src/dynamics/utils/dynconst.F90 @@ -45,6 +45,8 @@ module dynconst real(kind_dyn), protected, public :: lapse_rate ! R/Cp real(kind_dyn), protected, public :: cappa + ! Standard pressure [Pa] + real(kind_dyn), protected, public :: pstd !Public routines: @@ -72,6 +74,7 @@ subroutine dynconst_init use physconst, only: phys_cappa=>cappa use physconst, only: phys_rair=>rair use physconst, only: phys_rh2o=>rh2o + use physconst, only: phys_pstd=>pstd !Set constants used by the dynamics: @@ -86,7 +89,7 @@ subroutine dynconst_init tref = real(phys_tref, kind_dyn) lapse_rate = real(phys_lapse_rate, kind_dyn) cappa = real(phys_cappa, kind_dyn) - + pstd = real(phys_pstd, kind_dyn) end subroutine dynconst_init end module dynconst From 17eb407b2ed5d07b541bb09eb5a8b50c39acee4c Mon Sep 17 00:00:00 2001 From: Haipeng Lin Date: Thu, 26 Dec 2024 18:55:17 -0500 Subject: [PATCH 10/12] Fix nested timer ESMF error --- src/dynamics/se/dycore/prim_advance_mod.F90 | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index 0700b13f..1ac2e855 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -329,6 +329,7 @@ subroutine applyCAMforcing(elem,fvm,np1,np1_qdp,dt_dribble,dt_phys,nets,nete,nsu character(len=*), parameter :: subname = 'applyCAMforcing (SE)' + call t_startf('applyCAMforc') if (use_cslam) then allocate(ftmp_fvm(nc,nc,nlev,ntrac,nets:nete), stat=iret) call check_allocate(iret, subname, 'ftmp_fvm(nc,nc,nlev,ntrac,nets:nete)', & From 0fdead011909a8a438cda9a7247c3a51e7ad4f88 Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 27 Dec 2024 10:40:40 -0700 Subject: [PATCH 11/12] remove debug statement --- src/dynamics/se/dycore/prim_advance_mod.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dynamics/se/dycore/prim_advance_mod.F90 b/src/dynamics/se/dycore/prim_advance_mod.F90 index 1ac2e855..5389ed04 100644 --- a/src/dynamics/se/dycore/prim_advance_mod.F90 +++ b/src/dynamics/se/dycore/prim_advance_mod.F90 @@ -1231,7 +1231,6 @@ subroutine compute_and_apply_rhs(np1,nm1,n0,dt2,elem,hvcoord,hybrid,& ! vtemp = gradient_sphere(Ephi(:,:),deriv,elem(ie)%Dinv) call gradient_sphere(Ephi(:,:),deriv,elem(ie)%Dinv,vtemp) density_inv(:,:) = R_dry(:,:,k)*T_v(:,:,k)/p_full(:,:,k) - if (ie==1) write(*,*) "xxx pgf_formulation",pgf_formulation if (pgf_formulation==1.or.(pgf_formulation==3.and.hvcoord%hybm(k)>0._r8)) then if (dry_air_species_num==0) then exner(:,:)=(p_full(:,:,k)/hvcoord%ps0)**kappa(:,:,k,ie) From 5dd456687ebe340f41b3daf072b3fe72f15a292f Mon Sep 17 00:00:00 2001 From: PeterHjortLauritzen Date: Fri, 27 Dec 2024 11:27:02 -0700 Subject: [PATCH 12/12] change namelist defaults --- src/dynamics/se/namelist_definition_se_dycore.xml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/dynamics/se/namelist_definition_se_dycore.xml b/src/dynamics/se/namelist_definition_se_dycore.xml index 82cb3597..0283f71a 100644 --- a/src/dynamics/se/namelist_definition_se_dycore.xml +++ b/src/dynamics/se/namelist_definition_se_dycore.xml @@ -252,10 +252,10 @@ Second-order viscosity applied only near the model top [m^2/s]. - 5.0e5 - 1.0e6 - - 0.0 + 1.25e5 + 1.0e6 + 1.0e6 + 1.0e6 2.0e5 @@ -679,7 +679,8 @@ If se_ftype=1 then se_dribble_in_rsplit_loop has no effect since physics tendencies are added as an adjustment - 1 + 0 + 1