diff --git a/Source/Advection/Advection.H b/Source/Advection/Advection.H index be954c3f0..d09dd1537 100644 --- a/Source/Advection/Advection.H +++ b/Source/Advection/Advection.H @@ -62,41 +62,41 @@ void AdvectionSrcForMom (const amrex::Box& bxx, const amrex::Box& bxy, const amr AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE AdvType -EfficientAdvType(int nrk, AdvType adv_type) +EfficientAdvType (int nrk, AdvType adv_type) { - AdvType eff_adv_type; + AdvType eff_adv_type; - if (nrk == 0) { + if (nrk == 0) { - eff_adv_type = AdvType::Centered_2nd; + eff_adv_type = AdvType::Centered_2nd; - } else if (nrk == 1) { + } else if (nrk == 1) { - if ( (adv_type == AdvType::Centered_2nd) || - (adv_type == AdvType::Upwind_3rd) || - (adv_type == AdvType::Centered_4th) || - (adv_type == AdvType::Weno_3) || - (adv_type == AdvType::Weno_3Z) || - (adv_type == AdvType::Weno_3MZQ) ) - { - eff_adv_type = AdvType::Centered_2nd; + if ( (adv_type == AdvType::Centered_2nd) || + (adv_type == AdvType::Upwind_3rd) || + (adv_type == AdvType::Centered_4th) || + (adv_type == AdvType::Weno_3) || + (adv_type == AdvType::Weno_3Z) || + (adv_type == AdvType::Weno_3MZQ) ) + { + eff_adv_type = AdvType::Centered_2nd; - } else if ( (adv_type == AdvType::Upwind_5th) || - (adv_type == AdvType::Weno_5) || - (adv_type == AdvType::Weno_5Z) ) - { - eff_adv_type = AdvType::Upwind_3rd; + } else if ( (adv_type == AdvType::Upwind_5th) || + (adv_type == AdvType::Weno_5) || + (adv_type == AdvType::Weno_5Z) ) + { + eff_adv_type = AdvType::Upwind_3rd; - } else { // (adv_type == AdvType::Centered_6th) + } else { // (adv_type == AdvType::Centered_6th) - eff_adv_type = AdvType::Centered_4th; - } + eff_adv_type = AdvType::Centered_4th; + } - } else { + } else { - eff_adv_type = adv_type; - } + eff_adv_type = adv_type; + } - return(eff_adv_type); + return(eff_adv_type); } #endif diff --git a/Source/Advection/AdvectionSrcForMom_N.H b/Source/Advection/AdvectionSrcForMom_N.H index d20b504b6..53c57242c 100644 --- a/Source/Advection/AdvectionSrcForMom_N.H +++ b/Source/Advection/AdvectionSrcForMom_N.H @@ -272,22 +272,22 @@ AdvectionSrcForZMom_N (int i, int j, int k, */ template void -AdvectionSrcForMomWrapper_N(const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, - const amrex::Array4& rho_u_rhs, - const amrex::Array4& rho_v_rhs, - const amrex::Array4& rho_w_rhs, - const amrex::Array4& rho_u, - const amrex::Array4& rho_v, - const amrex::Array4& rho_w, - const amrex::Array4& u, - const amrex::Array4& v, - const amrex::Array4& w, - const amrex::GpuArray& cellSizeInv, - const amrex::Array4& mf_m, - const amrex::Array4& mf_u_inv, - const amrex::Array4& mf_v_inv, - const AdvType vert_adv_type, - const int domhi_z) +AdvectionSrcForMomWrapper_N (const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, + const amrex::Array4& rho_u_rhs, + const amrex::Array4& rho_v_rhs, + const amrex::Array4& rho_w_rhs, + const amrex::Array4& rho_u, + const amrex::Array4& rho_v, + const amrex::Array4& rho_w, + const amrex::Array4& u, + const amrex::Array4& v, + const amrex::Array4& w, + const amrex::GpuArray& cellSizeInv, + const amrex::Array4& mf_m, + const amrex::Array4& mf_u_inv, + const amrex::Array4& mf_v_inv, + const AdvType vert_adv_type, + const int domhi_z) { // Instantiate the appropriate structs InterpType_H interp_u_h(u); InterpType_V interp_u_v(u); // X-MOM @@ -320,22 +320,22 @@ AdvectionSrcForMomWrapper_N(const amrex::Box& bxx, const amrex::Box& bxy, const */ template void -AdvectionSrcForMomVert_N(const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, - const amrex::Array4& rho_u_rhs, - const amrex::Array4& rho_v_rhs, - const amrex::Array4& rho_w_rhs, - const amrex::Array4& rho_u, - const amrex::Array4& rho_v, - const amrex::Array4& rho_w, - const amrex::Array4& u, - const amrex::Array4& v, - const amrex::Array4& w, - const amrex::GpuArray& cellSizeInv, - const amrex::Array4& mf_m, - const amrex::Array4& mf_u_inv, - const amrex::Array4& mf_v_inv, - const AdvType vert_adv_type, - const int domhi_z) +AdvectionSrcForMomVert_N (const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, + const amrex::Array4& rho_u_rhs, + const amrex::Array4& rho_v_rhs, + const amrex::Array4& rho_w_rhs, + const amrex::Array4& rho_u, + const amrex::Array4& rho_v, + const amrex::Array4& rho_w, + const amrex::Array4& u, + const amrex::Array4& v, + const amrex::Array4& w, + const amrex::GpuArray& cellSizeInv, + const amrex::Array4& mf_m, + const amrex::Array4& mf_u_inv, + const amrex::Array4& mf_v_inv, + const AdvType vert_adv_type, + const int domhi_z) { if (vert_adv_type == AdvType::Centered_2nd) { AdvectionSrcForMomWrapper_N(bxx, bxy, bxz, diff --git a/Source/Advection/AdvectionSrcForMom_T.H b/Source/Advection/AdvectionSrcForMom_T.H index e61d22fce..4cffdb653 100644 --- a/Source/Advection/AdvectionSrcForMom_T.H +++ b/Source/Advection/AdvectionSrcForMom_T.H @@ -324,24 +324,24 @@ AdvectionSrcForZMom_T (int i, int j, int k, */ template void -AdvectionSrcForMomWrapper_T(const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, - const amrex::Array4& rho_u_rhs, - const amrex::Array4& rho_v_rhs, - const amrex::Array4& rho_w_rhs, - const amrex::Array4& rho_u, - const amrex::Array4& rho_v, - const amrex::Array4& Omega, - const amrex::Array4& u, - const amrex::Array4& v, - const amrex::Array4& w, - const amrex::Array4& z_nd, - const amrex::Array4& detJ, - const amrex::GpuArray& cellSizeInv, - const amrex::Array4& mf_m, - const amrex::Array4& mf_u_inv, - const amrex::Array4& mf_v_inv, - const AdvType vert_adv_type, - const int domhi_z) +AdvectionSrcForMomWrapper_T (const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, + const amrex::Array4& rho_u_rhs, + const amrex::Array4& rho_v_rhs, + const amrex::Array4& rho_w_rhs, + const amrex::Array4& rho_u, + const amrex::Array4& rho_v, + const amrex::Array4& Omega, + const amrex::Array4& u, + const amrex::Array4& v, + const amrex::Array4& w, + const amrex::Array4& z_nd, + const amrex::Array4& detJ, + const amrex::GpuArray& cellSizeInv, + const amrex::Array4& mf_m, + const amrex::Array4& mf_u_inv, + const amrex::Array4& mf_v_inv, + const AdvType vert_adv_type, + const int domhi_z) { // Instantiate the appropriate structs InterpType_H interp_u_h(u); InterpType_V interp_u_v(u); // X-MOM @@ -374,23 +374,23 @@ AdvectionSrcForMomWrapper_T(const amrex::Box& bxx, const amrex::Box& bxy, const */ template void -AdvectionSrcForMomVert_T(const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, - const amrex::Array4& rho_u_rhs, - const amrex::Array4& rho_v_rhs, - const amrex::Array4& rho_w_rhs, - const amrex::Array4& rho_u, - const amrex::Array4& rho_v, - const amrex::Array4& Omega, - const amrex::Array4& u, - const amrex::Array4& v, - const amrex::Array4& w, - const amrex::Array4& z_nd, - const amrex::Array4& detJ, - const amrex::GpuArray& cellSizeInv, - const amrex::Array4& mf_m, - const amrex::Array4& mf_u_inv, - const amrex::Array4& mf_v_inv, - const AdvType vert_adv_type, const int domhi_z) +AdvectionSrcForMomVert_T (const amrex::Box& bxx, const amrex::Box& bxy, const amrex::Box& bxz, + const amrex::Array4& rho_u_rhs, + const amrex::Array4& rho_v_rhs, + const amrex::Array4& rho_w_rhs, + const amrex::Array4& rho_u, + const amrex::Array4& rho_v, + const amrex::Array4& Omega, + const amrex::Array4& u, + const amrex::Array4& v, + const amrex::Array4& w, + const amrex::Array4& z_nd, + const amrex::Array4& detJ, + const amrex::GpuArray& cellSizeInv, + const amrex::Array4& mf_m, + const amrex::Array4& mf_u_inv, + const amrex::Array4& mf_v_inv, + const AdvType vert_adv_type, const int domhi_z) { if (vert_adv_type == AdvType::Centered_2nd) { AdvectionSrcForMomWrapper_T(bxx, bxy, bxz, diff --git a/Source/Advection/AdvectionSrcForScalars.H b/Source/Advection/AdvectionSrcForScalars.H index c09f15c81..dd585b794 100644 --- a/Source/Advection/AdvectionSrcForScalars.H +++ b/Source/Advection/AdvectionSrcForScalars.H @@ -6,13 +6,13 @@ */ template void -AdvectionSrcForScalarsWrapper(const amrex::Box& bx, - const int& ncomp, const int& icomp, - const amrex::GpuArray, AMREX_SPACEDIM> flx_arr, - const amrex::Array4& cell_prim, - const amrex::Array4& avg_xmom, - const amrex::Array4& avg_ymom, - const amrex::Array4& avg_zmom) +AdvectionSrcForScalarsWrapper (const amrex::Box& bx, + const int& ncomp, const int& icomp, + const amrex::GpuArray, AMREX_SPACEDIM> flx_arr, + const amrex::Array4& cell_prim, + const amrex::Array4& avg_xmom, + const amrex::Array4& avg_ymom, + const amrex::Array4& avg_zmom) { // Instantiate structs for vert/horiz interp InterpType_H interp_prim_h(cell_prim); @@ -60,14 +60,14 @@ AdvectionSrcForScalarsWrapper(const amrex::Box& bx, */ template void -AdvectionSrcForScalarsVert(const amrex::Box& bx, - const int& ncomp, const int& icomp, - const amrex::GpuArray, AMREX_SPACEDIM> flx_arr, - const amrex::Array4& cell_prim, - const amrex::Array4& avg_xmom, - const amrex::Array4& avg_ymom, - const amrex::Array4& avg_zmom, - const AdvType vert_adv_type) +AdvectionSrcForScalarsVert (const amrex::Box& bx, + const int& ncomp, const int& icomp, + const amrex::GpuArray, AMREX_SPACEDIM> flx_arr, + const amrex::Array4& cell_prim, + const amrex::Array4& avg_xmom, + const amrex::Array4& avg_ymom, + const amrex::Array4& avg_zmom, + const AdvType vert_adv_type) { switch(vert_adv_type) { case AdvType::Centered_2nd: diff --git a/Source/Derive.cpp b/Source/Derive.cpp index dfc232078..ce25c9f7b 100644 --- a/Source/Derive.cpp +++ b/Source/Derive.cpp @@ -13,37 +13,36 @@ namespace derived { * @params[in] datfab array of data used to construct derived quantity * @params[in] scalar_index index of quantity to be divided by density */ -void erf_derrhodivide ( - const amrex::Box& bx, - amrex::FArrayBox& derfab, - const amrex::FArrayBox& datfab, - const int scalar_index) +void erf_derrhodivide (const amrex::Box& bx, + amrex::FArrayBox& derfab, + const amrex::FArrayBox& datfab, + const int scalar_index) { - // This routine divides any cell-centered conserved quantity by density - auto const dat = datfab.array(); - auto primitive = derfab.array(); + // This routine divides any cell-centered conserved quantity by density + auto const dat = datfab.array(); + auto primitive = derfab.array(); - amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real rho = dat(i, j, k, Rho_comp); - const amrex::Real conserved = dat(i, j, k, scalar_index); - primitive(i,j,k) = conserved / rho; - }); + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + const amrex::Real rho = dat(i, j, k, Rho_comp); + const amrex::Real conserved = dat(i, j, k, scalar_index); + primitive(i,j,k) = conserved / rho; + }); } /** * Placeholder function that does nothing */ void -erf_dernull ( - const amrex::Box& /*bx*/, - amrex::FArrayBox& /*derfab*/, - int /*dcomp*/, - int /*ncomp*/, - const amrex::FArrayBox& /*datfab*/, - const amrex::Geometry& /*geomdata*/, - amrex::Real /*time*/, - const int* /*bcrec*/, - const int /*level*/) +erf_dernull (const amrex::Box& /*bx*/, + amrex::FArrayBox& /*derfab*/, + int /*dcomp*/, + int /*ncomp*/, + const amrex::FArrayBox& /*datfab*/, + const amrex::Geometry& /*geomdata*/, + amrex::Real /*time*/, + const int* /*bcrec*/, + const int /*level*/) { } /** @@ -54,29 +53,29 @@ erf_dernull ( * @params[in] datfab array of data used to construct derived quantity */ void -erf_dersoundspeed ( - const amrex::Box& bx, - amrex::FArrayBox& derfab, - int /*dcomp*/, - int /*ncomp*/, - const amrex::FArrayBox& datfab, - const amrex::Geometry& /*geomdata*/, - amrex::Real /*time*/, - const int* /*bcrec*/, - const int /*level*/) +erf_dersoundspeed (const amrex::Box& bx, + amrex::FArrayBox& derfab, + int /*dcomp*/, + int /*ncomp*/, + const amrex::FArrayBox& datfab, + const amrex::Geometry& /*geomdata*/, + amrex::Real /*time*/, + const int* /*bcrec*/, + const int /*level*/) { - auto const dat = datfab.array(); - auto cfab = derfab.array(); + auto const dat = datfab.array(); + auto cfab = derfab.array(); - // NOTE: we compute the soundspeed of dry air -- we do not account for any moisture effects here - amrex::Real qv = 0.; + // NOTE: we compute the soundspeed of dry air -- we do not account for any moisture effects here + amrex::Real qv = 0.; - amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real rhotheta = dat(i, j, k, RhoTheta_comp); - const amrex::Real rho = dat(i, j, k, Rho_comp); - AMREX_ALWAYS_ASSERT(rhotheta > 0.); - cfab(i,j,k) = std::sqrt(Gamma * getPgivenRTh(rhotheta,qv) / rho); - }); + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + const amrex::Real rhotheta = dat(i, j, k, RhoTheta_comp); + const amrex::Real rho = dat(i, j, k, Rho_comp); + AMREX_ALWAYS_ASSERT(rhotheta > 0.); + cfab(i,j,k) = std::sqrt(Gamma * getPgivenRTh(rhotheta,qv) / rho); + }); } /** @@ -87,26 +86,26 @@ erf_dersoundspeed ( * @params[in] datfab array of data used to construct derived quantity */ void -erf_dertemp ( - const amrex::Box& bx, - amrex::FArrayBox& derfab, - int /*dcomp*/, - int /*ncomp*/, - const amrex::FArrayBox& datfab, - const amrex::Geometry& /*geomdata*/, - amrex::Real /*time*/, - const int* /*bcrec*/, - const int /*level*/) +erf_dertemp (const amrex::Box& bx, + amrex::FArrayBox& derfab, + int /*dcomp*/, + int /*ncomp*/, + const amrex::FArrayBox& datfab, + const amrex::Geometry& /*geomdata*/, + amrex::Real /*time*/, + const int* /*bcrec*/, + const int /*level*/) { - auto const dat = datfab.array(); - auto tfab = derfab.array(); + auto const dat = datfab.array(); + auto tfab = derfab.array(); - amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - const amrex::Real rho = dat(i, j, k, Rho_comp); - const amrex::Real rhotheta = dat(i, j, k, RhoTheta_comp); - AMREX_ALWAYS_ASSERT(rhotheta > 0.); - tfab(i,j,k) = getTgivenRandRTh(rho,rhotheta); - }); + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + const amrex::Real rho = dat(i, j, k, Rho_comp); + const amrex::Real rhotheta = dat(i, j, k, RhoTheta_comp); + AMREX_ALWAYS_ASSERT(rhotheta > 0.); + tfab(i,j,k) = getTgivenRandRTh(rho,rhotheta); + }); } /** @@ -117,18 +116,17 @@ erf_dertemp ( * @params[in] datfab array of data used to construct derived quantity */ void -erf_dertheta ( - const amrex::Box& bx, - amrex::FArrayBox& derfab, - int /*dcomp*/, - int /*ncomp*/, - const amrex::FArrayBox& datfab, - const amrex::Geometry& /*geomdata*/, - amrex::Real /*time*/, - const int* /*bcrec*/, - const int /*level*/) +erf_dertheta (const amrex::Box& bx, + amrex::FArrayBox& derfab, + int /*dcomp*/, + int /*ncomp*/, + const amrex::FArrayBox& datfab, + const amrex::Geometry& /*geomdata*/, + amrex::Real /*time*/, + const int* /*bcrec*/, + const int /*level*/) { - erf_derrhodivide(bx, derfab, datfab, RhoTheta_comp); + erf_derrhodivide(bx, derfab, datfab, RhoTheta_comp); } /** @@ -139,18 +137,17 @@ erf_dertheta ( * @params[in] datfab array of data used to construct derived quantity */ void -erf_derscalar ( - const amrex::Box& bx, - amrex::FArrayBox& derfab, - int /*dcomp*/, - int /*ncomp*/, - const amrex::FArrayBox& datfab, - const amrex::Geometry& /*geomdata*/, - amrex::Real /*time*/, - const int* /*bcrec*/, - const int /*level*/) +erf_derscalar (const amrex::Box& bx, + amrex::FArrayBox& derfab, + int /*dcomp*/, + int /*ncomp*/, + const amrex::FArrayBox& datfab, + const amrex::Geometry& /*geomdata*/, + amrex::Real /*time*/, + const int* /*bcrec*/, + const int /*level*/) { - erf_derrhodivide(bx, derfab, datfab, RhoScalar_comp); + erf_derrhodivide(bx, derfab, datfab, RhoScalar_comp); } /** @@ -161,18 +158,17 @@ erf_derscalar ( * @params[in] datfab array of data used to construct derived quantity */ void -erf_derKE ( - const amrex::Box& bx, - amrex::FArrayBox& derfab, - int /*dcomp*/, - int /*ncomp*/, - const amrex::FArrayBox& datfab, - const amrex::Geometry& /*geomdata*/, - amrex::Real /*time*/, - const int* /*bcrec*/, - const int /*level*/) +erf_derKE (const amrex::Box& bx, + amrex::FArrayBox& derfab, + int /*dcomp*/, + int /*ncomp*/, + const amrex::FArrayBox& datfab, + const amrex::Geometry& /*geomdata*/, + amrex::Real /*time*/, + const int* /*bcrec*/, + const int /*level*/) { - erf_derrhodivide(bx, derfab, datfab, RhoKE_comp); + erf_derrhodivide(bx, derfab, datfab, RhoKE_comp); } /** @@ -183,18 +179,17 @@ erf_derKE ( * @params[in] datfab array of data used to construct derived quantity */ void -erf_derQKE ( - const amrex::Box& bx, - amrex::FArrayBox& derfab, - int /*dcomp*/, - int /*ncomp*/, - const amrex::FArrayBox& datfab, - const amrex::Geometry& /*geomdata*/, - amrex::Real /*time*/, - const int* /*bcrec*/, - const int /*level*/) +erf_derQKE (const amrex::Box& bx, + amrex::FArrayBox& derfab, + int /*dcomp*/, + int /*ncomp*/, + const amrex::FArrayBox& datfab, + const amrex::Geometry& /*geomdata*/, + amrex::Real /*time*/, + const int* /*bcrec*/, + const int /*level*/) { - erf_derrhodivide(bx, derfab, datfab, RhoQKE_comp); + erf_derrhodivide(bx, derfab, datfab, RhoQKE_comp); } } // namespace diff --git a/Source/Diffusion/ComputeQKESourceTerm.H b/Source/Diffusion/ComputeQKESourceTerm.H index 1bfa41ac0..3586c1d15 100644 --- a/Source/Diffusion/ComputeQKESourceTerm.H +++ b/Source/Diffusion/ComputeQKESourceTerm.H @@ -34,58 +34,58 @@ ComputeQKESourceTerms (int i, int j, int k, bool v_ext_dir_on_zlo, bool v_ext_dir_on_zhi) { - // Compute some relevant derivatives - amrex::Real dz_inv = cellSizeInv[2]; - int izmin = domain.smallEnd(2); - int izmax = domain.bigEnd(2); - amrex::Real dthetadz, dudz, dvdz; - amrex::Real source_term = 0.0; - if ( k==izmax && c_ext_dir_on_zhi ) { - dthetadz = (1.0/3.0)*(-cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) - - 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) - + 4.0 * cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) )*dz_inv; - } else if ( k==izmin && c_ext_dir_on_zlo ) { - dthetadz = (1.0/3.0)*( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) - + 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) - - 4.0 * cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dz_inv; - } else { - dthetadz = 0.5*( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) - - cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dz_inv; - } + // Compute some relevant derivatives + amrex::Real dz_inv = cellSizeInv[2]; + int izmin = domain.smallEnd(2); + int izmax = domain.bigEnd(2); + amrex::Real dthetadz, dudz, dvdz; + amrex::Real source_term = 0.0; + if ( k==izmax && c_ext_dir_on_zhi ) { + dthetadz = (1.0/3.0)*(-cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) + - 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) + + 4.0 * cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) )*dz_inv; + } else if ( k==izmin && c_ext_dir_on_zlo ) { + dthetadz = (1.0/3.0)*( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) + + 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) + - 4.0 * cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dz_inv; + } else { + dthetadz = 0.5*( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) + - cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dz_inv; + } - if ( k==izmax && u_ext_dir_on_zhi ) { - dudz = (1.0/6.0)*( (-uvel(i ,j,k-1) - 3.0 * uvel(i ,j,k ) + 4.0 * uvel(i ,j,k+1)) - + (-uvel(i+1,j,k-1) - 3.0 * uvel(i+1,j,k ) + 4.0 * uvel(i+1,j,k+1)) )*dz_inv; - } else if ( k==izmin && u_ext_dir_on_zlo ) { - dudz = (1.0/6.0)*( (uvel(i ,j,k+1) + 3.0 * uvel(i ,j,k ) - 4.0 * uvel(i ,j,k-1)) - + (uvel(i+1,j,k+1) + 3.0 * uvel(i+1,j,k ) - 4.0 * uvel(i+1,j,k-1)) )*dz_inv; - } else { - dudz = 0.25*( uvel(i,j,k+1) - uvel(i,j,k-1) + uvel(i+1,j,k+1) - uvel(i+1,j,k-1) )*dz_inv; - } + if ( k==izmax && u_ext_dir_on_zhi ) { + dudz = (1.0/6.0)*( (-uvel(i ,j,k-1) - 3.0 * uvel(i ,j,k ) + 4.0 * uvel(i ,j,k+1)) + + (-uvel(i+1,j,k-1) - 3.0 * uvel(i+1,j,k ) + 4.0 * uvel(i+1,j,k+1)) )*dz_inv; + } else if ( k==izmin && u_ext_dir_on_zlo ) { + dudz = (1.0/6.0)*( (uvel(i ,j,k+1) + 3.0 * uvel(i ,j,k ) - 4.0 * uvel(i ,j,k-1)) + + (uvel(i+1,j,k+1) + 3.0 * uvel(i+1,j,k ) - 4.0 * uvel(i+1,j,k-1)) )*dz_inv; + } else { + dudz = 0.25*( uvel(i,j,k+1) - uvel(i,j,k-1) + uvel(i+1,j,k+1) - uvel(i+1,j,k-1) )*dz_inv; + } - if ( k==izmax && v_ext_dir_on_zhi ) { - dvdz = (1.0/6.0)*( (-vvel(i,j ,k-1) - 3.0 * vvel(i,j ,k ) + 4.0 * vvel(i,j ,k+1)) - + (-vvel(i,j+1,k-1) - 3.0 * vvel(i,j+1,k ) + 4.0 * vvel(i,j+1,k+1)) )*dz_inv; - } else if ( k==izmin && v_ext_dir_on_zlo ) { - dvdz = (1.0/6.0)*( (vvel(i,j ,k+1) + 3.0 * vvel(i,j ,k ) - 4.0 * vvel(i,j ,k-1)) - + (vvel(i,j+1,k+1) + 3.0 * vvel(i,j+1,k ) - 4.0 * vvel(i,j+1,k-1)) )*dz_inv; - } else { - dvdz = 0.25*( vvel(i,j,k+1) - vvel(i,j,k-1) + vvel(i,j+1,k+1) - vvel(i,j+1,k-1) )*dz_inv; - } + if ( k==izmax && v_ext_dir_on_zhi ) { + dvdz = (1.0/6.0)*( (-vvel(i,j ,k-1) - 3.0 * vvel(i,j ,k ) + 4.0 * vvel(i,j ,k+1)) + + (-vvel(i,j+1,k-1) - 3.0 * vvel(i,j+1,k ) + 4.0 * vvel(i,j+1,k+1)) )*dz_inv; + } else if ( k==izmin && v_ext_dir_on_zlo ) { + dvdz = (1.0/6.0)*( (vvel(i,j ,k+1) + 3.0 * vvel(i,j ,k ) - 4.0 * vvel(i,j ,k-1)) + + (vvel(i,j+1,k+1) + 3.0 * vvel(i,j+1,k ) - 4.0 * vvel(i,j+1,k-1)) )*dz_inv; + } else { + dvdz = 0.25*( vvel(i,j,k+1) - vvel(i,j,k-1) + vvel(i,j+1,k+1) - vvel(i,j+1,k-1) )*dz_inv; + } - // Production (We store mu_turb, which is 0.5*K_turb) - source_term += 4.0*K_turb(i,j,k,EddyDiff::Mom_v) * (dudz*dudz + dvdz*dvdz); + // Production (We store mu_turb, which is 0.5*K_turb) + source_term += 4.0*K_turb(i,j,k,EddyDiff::Mom_v) * (dudz*dudz + dvdz*dvdz); - // Bouyancy - source_term -= 2.0*(CONST_GRAV/theta_mean)*K_turb(i,j,k,EddyDiff::Theta_v)*dthetadz; + // Bouyancy + source_term -= 2.0*(CONST_GRAV/theta_mean)*K_turb(i,j,k,EddyDiff::Theta_v)*dthetadz; - // Dissipation - amrex::Real qke = cell_prim(i,j,k,PrimQKE_comp); - if (std::abs(qke) > 0.0) { - source_term -= 2.0 * cell_data(i,j,k,Rho_comp) * std::pow(qke,1.5) / - (pbl_B1_l * K_turb(i,j,k,EddyDiff::PBL_lengthscale)); - } + // Dissipation + amrex::Real qke = cell_prim(i,j,k,PrimQKE_comp); + if (std::abs(qke) > 0.0) { + source_term -= 2.0 * cell_data(i,j,k,Rho_comp) * std::pow(qke,1.5) / + (pbl_B1_l * K_turb(i,j,k,EddyDiff::PBL_lengthscale)); + } - return source_term; + return source_term; } #endif diff --git a/Source/Diffusion/ComputeStrain_N.cpp b/Source/Diffusion/ComputeStrain_N.cpp index f10ac116e..6bf0740d5 100644 --- a/Source/Diffusion/ComputeStrain_N.cpp +++ b/Source/Diffusion/ComputeStrain_N.cpp @@ -26,11 +26,11 @@ using namespace amrex; */ void ComputeStrain_N (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, - const Array4& u, const Array4& v, const Array4& w, - Array4& tau11, Array4& tau22, Array4& tau33, - Array4& tau12, Array4& tau13, Array4& tau23, - const BCRec* bc_ptr, const GpuArray& dxInv, - const Array4& mf_m, const Array4& mf_u, const Array4& mf_v) + const Array4& u, const Array4& v, const Array4& w, + Array4& tau11, Array4& tau22, Array4& tau33, + Array4& tau12, Array4& tau13, Array4& tau23, + const BCRec* bc_ptr, const GpuArray& dxInv, + const Array4& mf_m, const Array4& mf_u, const Array4& mf_v) { // Dirichlet on left or right plane bool xl_v_dir = ( (bc_ptr[BCVars::yvel_bc].lo(0) == ERFBCType::ext_dir) || diff --git a/Source/Diffusion/ComputeStrain_T.cpp b/Source/Diffusion/ComputeStrain_T.cpp index c7fbe7b3b..360e004ee 100644 --- a/Source/Diffusion/ComputeStrain_T.cpp +++ b/Source/Diffusion/ComputeStrain_T.cpp @@ -30,16 +30,16 @@ using namespace amrex; */ void ComputeStrain_T (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, - const Array4& u, const Array4& v, const Array4& w, - Array4& tau11, Array4& tau22, Array4& tau33, - Array4& tau12, Array4& tau13, - Array4& tau21, Array4& tau23, - Array4& tau31, Array4& tau32, - const Array4& z_nd , - const BCRec* bc_ptr, const GpuArray& dxInv, - const Array4& /*mf_m*/, - const Array4& mf_u, - const Array4& mf_v) + const Array4& u, const Array4& v, const Array4& w, + Array4& tau11, Array4& tau22, Array4& tau33, + Array4& tau12, Array4& tau13, + Array4& tau21, Array4& tau23, + Array4& tau31, Array4& tau32, + const Array4& z_nd , + const BCRec* bc_ptr, const GpuArray& dxInv, + const Array4& /*mf_m*/, + const Array4& mf_u, + const Array4& mf_v) { // Dirichlet on left or right plane bool xl_v_dir = ( (bc_ptr[BCVars::yvel_bc].lo(0) == ERFBCType::ext_dir) || diff --git a/Source/Diffusion/ComputeStress_N.cpp b/Source/Diffusion/ComputeStress_N.cpp index a840eb0ef..422f1c33f 100644 --- a/Source/Diffusion/ComputeStress_N.cpp +++ b/Source/Diffusion/ComputeStress_N.cpp @@ -20,9 +20,9 @@ using namespace amrex; */ void ComputeStressConsVisc_N (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Real mu_eff, - Array4& tau11, Array4& tau22, Array4& tau33, - Array4& tau12, Array4& tau13, Array4& tau23, - const Array4& er_arr) + Array4& tau11, Array4& tau22, Array4& tau33, + Array4& tau12, Array4& tau13, Array4& tau23, + const Array4& er_arr) { Real OneThird = (1./3.); @@ -67,10 +67,10 @@ ComputeStressConsVisc_N (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Real mu_eff, */ void ComputeStressVarVisc_N (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Real mu_eff, - const Array4& mu_turb, - Array4& tau11, Array4& tau22, Array4& tau33, - Array4& tau12, Array4& tau13, Array4& tau23, - const Array4& er_arr) + const Array4& mu_turb, + Array4& tau11, Array4& tau22, Array4& tau33, + Array4& tau12, Array4& tau13, Array4& tau23, + const Array4& er_arr) { Real OneThird = (1./3.); diff --git a/Source/Diffusion/ComputeStress_T.cpp b/Source/Diffusion/ComputeStress_T.cpp index ad565e0c2..8db154add 100644 --- a/Source/Diffusion/ComputeStress_T.cpp +++ b/Source/Diffusion/ComputeStress_T.cpp @@ -26,13 +26,13 @@ using namespace amrex; */ void ComputeStressConsVisc_T (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Real mu_eff, - Array4& tau11, Array4& tau22, Array4& tau33, - Array4& tau12, Array4& tau13, - Array4& tau21, Array4& tau23, - Array4& tau31, Array4& tau32, - const Array4& er_arr, - const Array4& z_nd , - const GpuArray& dxInv) + Array4& tau11, Array4& tau22, Array4& tau33, + Array4& tau12, Array4& tau13, + Array4& tau21, Array4& tau23, + Array4& tau31, Array4& tau32, + const Array4& er_arr, + const Array4& z_nd , + const GpuArray& dxInv) { //*********************************************************************************** // NOTE: The first block computes (S-D). @@ -271,14 +271,14 @@ ComputeStressConsVisc_T (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Real mu_eff, */ void ComputeStressVarVisc_T (Box bxcc, Box tbxxy, Box tbxxz, Box tbxyz, Real mu_eff, - const Array4& mu_turb, - Array4& tau11, Array4& tau22, Array4& tau33, - Array4& tau12, Array4& tau13, - Array4& tau21, Array4& tau23, - Array4& tau31, Array4& tau32, - const Array4& er_arr, - const Array4& z_nd , - const GpuArray& dxInv) + const Array4& mu_turb, + Array4& tau11, Array4& tau22, Array4& tau33, + Array4& tau12, Array4& tau13, + Array4& tau21, Array4& tau23, + Array4& tau31, Array4& tau32, + const Array4& er_arr, + const Array4& z_nd , + const GpuArray& dxInv) { //*********************************************************************************** // NOTE: The first block computes (S-D). diff --git a/Source/Diffusion/PBLModels.cpp b/Source/Diffusion/PBLModels.cpp index a9aec0c5b..1c0b21628 100644 --- a/Source/Diffusion/PBLModels.cpp +++ b/Source/Diffusion/PBLModels.cpp @@ -26,218 +26,218 @@ ComputeTurbulentViscosityPBL (const amrex::MultiFab& xvel, const amrex::BCRec* bc_ptr, bool /*vert_only*/) { - // MYNN Level 2.5 PBL Model - if (turbChoice.pbl_type == PBLType::MYNN25) { - - const amrex::Real A1 = turbChoice.pbl_A1; - const amrex::Real A2 = turbChoice.pbl_A2; - const amrex::Real B1 = turbChoice.pbl_B1; - const amrex::Real B2 = turbChoice.pbl_B2; - const amrex::Real C1 = turbChoice.pbl_C1; - const amrex::Real C2 = turbChoice.pbl_C2; - const amrex::Real C3 = turbChoice.pbl_C3; - //const amrex::Real C4 = turbChoice.pbl_C4; - const amrex::Real C5 = turbChoice.pbl_C5; - - // Dirichlet flags to switch derivative stencil - bool c_ext_dir_on_zlo = ( (bc_ptr[BCVars::cons_bc].lo(2) == ERFBCType::ext_dir) ); - bool c_ext_dir_on_zhi = ( (bc_ptr[BCVars::cons_bc].lo(5) == ERFBCType::ext_dir) ); - bool u_ext_dir_on_zlo = ( (bc_ptr[BCVars::xvel_bc].lo(2) == ERFBCType::ext_dir) ); - bool u_ext_dir_on_zhi = ( (bc_ptr[BCVars::xvel_bc].lo(5) == ERFBCType::ext_dir) ); - bool v_ext_dir_on_zlo = ( (bc_ptr[BCVars::yvel_bc].lo(2) == ERFBCType::ext_dir) ); - bool v_ext_dir_on_zhi = ( (bc_ptr[BCVars::yvel_bc].lo(5) == ERFBCType::ext_dir) ); - - // Epsilon - amrex::Real eps = std::numeric_limits::epsilon(); + // MYNN Level 2.5 PBL Model + if (turbChoice.pbl_type == PBLType::MYNN25) { + + const amrex::Real A1 = turbChoice.pbl_A1; + const amrex::Real A2 = turbChoice.pbl_A2; + const amrex::Real B1 = turbChoice.pbl_B1; + const amrex::Real B2 = turbChoice.pbl_B2; + const amrex::Real C1 = turbChoice.pbl_C1; + const amrex::Real C2 = turbChoice.pbl_C2; + const amrex::Real C3 = turbChoice.pbl_C3; + //const amrex::Real C4 = turbChoice.pbl_C4; + const amrex::Real C5 = turbChoice.pbl_C5; + + // Dirichlet flags to switch derivative stencil + bool c_ext_dir_on_zlo = ( (bc_ptr[BCVars::cons_bc].lo(2) == ERFBCType::ext_dir) ); + bool c_ext_dir_on_zhi = ( (bc_ptr[BCVars::cons_bc].lo(5) == ERFBCType::ext_dir) ); + bool u_ext_dir_on_zlo = ( (bc_ptr[BCVars::xvel_bc].lo(2) == ERFBCType::ext_dir) ); + bool u_ext_dir_on_zhi = ( (bc_ptr[BCVars::xvel_bc].lo(5) == ERFBCType::ext_dir) ); + bool v_ext_dir_on_zlo = ( (bc_ptr[BCVars::yvel_bc].lo(2) == ERFBCType::ext_dir) ); + bool v_ext_dir_on_zhi = ( (bc_ptr[BCVars::yvel_bc].lo(5) == ERFBCType::ext_dir) ); + + // Epsilon + amrex::Real eps = std::numeric_limits::epsilon(); #ifdef _OPENMP #pragma omp parallel if (amrex::Gpu::notInLaunchRegion()) #endif - for ( amrex::MFIter mfi(eddyViscosity,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { - - const amrex::Box &bx = mfi.growntilebox(1); - const amrex::Array4 &cell_data = cons_in.array(mfi); - const amrex::Array4 &K_turb = eddyViscosity.array(mfi); - const amrex::Array4 &uvel = xvel.array(mfi); - const amrex::Array4 &vvel = yvel.array(mfi); - - // Compute some quantities that are constant in each column - // Sbox is shrunk to only include the interior of the domain in the vertical direction to compute integrals - // Box includes one ghost cell in each direction - const amrex::Box &dbx = geom.Domain(); - amrex::Box sbx(bx.smallEnd(), bx.bigEnd()); - sbx.grow(2,-1); - AMREX_ALWAYS_ASSERT(sbx.smallEnd(2) == dbx.smallEnd(2) && sbx.bigEnd(2) == dbx.bigEnd(2)); - - const amrex::GeometryData gdata = geom.data(); - - const amrex::Box xybx = PerpendicularBox(bx, amrex::IntVect{0,0,0}); - amrex::FArrayBox qintegral(xybx,2); - qintegral.setVal(0.0); - amrex::FArrayBox qturb(bx,1); amrex::FArrayBox qturb_old(bx,1); - const amrex::Array4 qint = qintegral.array(); - const amrex::Array4 qvel = qturb.array(); - const amrex::Array4 qvel_old = qturb_old.array(); - - amrex::ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), bx, - [=] AMREX_GPU_DEVICE (int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept - { - qvel(i,j,k) = std::sqrt(cell_data(i,j,k,RhoQKE_comp) / cell_data(i,j,k,Rho_comp)); - qvel_old(i,j,k) = std::sqrt(cell_data(i,j,k,RhoQKE_comp) / cell_data(i,j,k,Rho_comp) + eps); - AMREX_ASSERT_WITH_MESSAGE(qvel(i,j,k) > 0.0, "QKE must have a positive value"); - AMREX_ASSERT_WITH_MESSAGE(qvel_old(i,j,k) > 0.0, "Old QKE must have a positive value"); - - const amrex::Real Zval = gdata.ProbLo(2) + (k + 0.5)*gdata.CellSize(2); - if (sbx.contains(i,j,k)) { - amrex::Gpu::deviceReduceSum(&qint(i,j,0,0), Zval*qvel(i,j,k), handler); - amrex::Gpu::deviceReduceSum(&qint(i,j,0,1), qvel(i,j,k), handler); - } - }); - - amrex::Real dz_inv = geom.InvCellSize(2); - int izmin = geom.Domain().smallEnd(2); - int izmax = geom.Domain().bigEnd(2); - - // Spatially varying MOST - amrex::Real d_kappa = KAPPA; - amrex::Real d_gravity = CONST_GRAV; - - const auto& t_mean_mf = most->get_mac_avg(0,2); // TODO: IS THIS ACTUALLY RHOTHETA - const auto& u_star_mf = most->get_u_star(0); // Use coarsest level - const auto& t_star_mf = most->get_t_star(0); // Use coarsest level - - const auto& tm_arr = t_mean_mf->array(mfi); // TODO: IS THIS ACTUALLY RHOTHETA - const auto& u_star_arr = u_star_mf->array(mfi); - const auto& t_star_arr = t_star_mf->array(mfi); - - amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept - { - // Compute some partial derivatives that we will need (second order) - // U and V derivatives are interpolated to account for staggered grid - amrex::Real dthetadz, dudz, dvdz; - if ( k==izmax && c_ext_dir_on_zhi ) { - dthetadz = (1.0/3.0)*(-cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) - - 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) - + 4.0 * cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) )*dz_inv; - } else if ( k==izmin && c_ext_dir_on_zlo ) { - dthetadz = (1.0/3.0)*( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) - + 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) - - 4.0 * cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dz_inv; - } else { - dthetadz = 0.5*(cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) - - cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp))*dz_inv; - } - - if ( k==izmax && u_ext_dir_on_zhi ) { - dudz = (1.0/6.0)*( (-uvel(i ,j,k-1) - 3.0 * uvel(i ,j,k ) + 4.0 * uvel(i ,j,k+1)) - + (-uvel(i+1,j,k-1) - 3.0 * uvel(i+1,j,k ) + 4.0 * uvel(i+1,j,k+1)) )*dz_inv; - } else if ( k==izmin && u_ext_dir_on_zlo ) { - dudz = (1.0/6.0)*( (uvel(i ,j,k+1) + 3.0 * uvel(i ,j,k ) - 4.0 * uvel(i ,j,k-1)) - + (uvel(i+1,j,k+1) + 3.0 * uvel(i+1,j,k ) - 4.0 * uvel(i+1,j,k-1)) )*dz_inv; - } else { - dudz = 0.25*(uvel(i,j,k+1) - uvel(i,j,k-1) + uvel(i+1,j,k+1) - uvel(i+1,j,k-1))*dz_inv; - } - - if ( k==izmax && v_ext_dir_on_zhi ) { - dvdz = (1.0/6.0)*( (-vvel(i,j ,k-1) - 3.0 * vvel(i,j ,k ) + 4.0 * vvel(i,j ,k+1)) - + (-vvel(i,j+1,k-1) - 3.0 * vvel(i,j+1,k ) + 4.0 * vvel(i,j+1,k+1)) )*dz_inv; - } else if ( k==izmin && v_ext_dir_on_zlo ) { - dvdz = (1.0/6.0)*( (vvel(i,j ,k+1) + 3.0 * vvel(i,j ,k ) - 4.0 * vvel(i,j ,k-1)) - + (vvel(i,j+1,k+1) + 3.0 * vvel(i,j+1,k ) - 4.0 * vvel(i,j+1,k-1)) )*dz_inv; - } else { - dvdz = 0.25*(vvel(i,j,k+1) - vvel(i,j,k-1) + vvel(i,j+1,k+1) - vvel(i,j+1,k-1))*dz_inv; - } - - // Spatially varying MOST - amrex::Real surface_heat_flux = -u_star_arr(i,j,0) * t_star_arr(i,j,0); - amrex::Real theta0 = tm_arr(i,j,0); // TODO: IS THIS ACTUALLY RHOTHETA - amrex::Real l_obukhov; - if (std::abs(surface_heat_flux) > eps) { - l_obukhov = ( theta0 * u_star_arr(i,j,0) * u_star_arr(i,j,0) ) / - ( d_kappa * d_gravity * t_star_arr(i,j,0) ); - } else { - l_obukhov = std::numeric_limits::max(); - } - - // First Length Scale - AMREX_ASSERT(l_obukhov != 0); - int lk = amrex::max(k,0); - const amrex::Real zval = gdata.ProbLo(2) + (lk + 0.5)*gdata.CellSize(2); - const amrex::Real zeta = zval/l_obukhov; - amrex::Real l_S; - if (zeta >= 1.0) { - l_S = KAPPA*zval/3.7; - } else if (zeta >= 0) { - l_S = KAPPA*zval/(1+2.7*zeta); - } else { - l_S = KAPPA*zval*std::pow(1.0 - 100.0 * zeta, 0.2); - } - - // Second Length Scale - amrex::Real l_T; - if (qint(i,j,0,1) > 0.0) { - l_T = 0.23*qint(i,j,0,0)/qint(i,j,0,1); - } else { - l_T = std::numeric_limits::max(); - } - - // Third Length Scale - amrex::Real l_B; - if (dthetadz > 0) { - amrex::Real N_brunt_vaisala = std::sqrt(CONST_GRAV/theta0 * dthetadz); - if (zeta < 0) { - amrex::Real qc = CONST_GRAV/theta0 * surface_heat_flux * l_T; - qc = std::pow(qc,1.0/3.0); - l_B = (1.0 + 5.0*std::sqrt(qc/(N_brunt_vaisala * l_T))) * qvel(i,j,k)/N_brunt_vaisala; - } else { - l_B = qvel(i,j,k) / N_brunt_vaisala; - } - } else { - l_B = std::numeric_limits::max(); - } - - // Overall Length Scale - amrex::Real l_comb = 1.0 / (1.0/l_S + 1.0/l_T + 1.0/l_B); - - // NOTE: Level 2 limiting from balance of production and dissipation. - // K_turb has a setval of 0.0 when the MF is created (NOT EACH STEP). - // We do this inline to avoid storing qe^2 at each cell. - amrex::Real l_comb_old = K_turb(i,j,k,EddyDiff::PBL_lengthscale); - amrex::Real shearProd = dudz*dudz + dvdz*dvdz; - amrex::Real buoyProd = -(CONST_GRAV/theta0) * dthetadz; - amrex::Real lSM = K_turb(i,j,k,EddyDiff::Mom_v) / (qvel_old(i,j,k) + eps); - amrex::Real lSH = K_turb(i,j,k,EddyDiff::Theta_v) / (qvel_old(i,j,k) + eps); - amrex::Real qe2 = B1 * l_comb_old * ( lSM * shearProd + lSH * buoyProd ); - amrex::Real qe = (qe2 < 0.0) ? 0.0 : std::sqrt(qe2); - amrex::Real one_m_alpha = (qvel(i,j,k) > qe) ? 1.0 : qvel(i,j,k) / (qe + eps); - amrex::Real one_m_alpha2 = one_m_alpha * one_m_alpha; - - // Compute non-dimensional parameters - amrex::Real l2_over_q2 = l_comb*l_comb/(qvel(i,j,k)*qvel(i,j,k)); - amrex::Real GM = l2_over_q2 * shearProd; - amrex::Real GH = l2_over_q2 * buoyProd; - amrex::Real E1 = 1.0 + one_m_alpha2 * ( 6.0*A1*A1*GM - 9.0*A1*A2*(1.0-C2)*GH ); - amrex::Real E2 = one_m_alpha2 * ( -3.0*A1*(4.0*A1 + 3.0*A2*(1.0-C5))*(1.0-C2)*GH ); - amrex::Real E3 = one_m_alpha2 * ( 6.0*A1*A2*GM ); - amrex::Real E4 = 1.0 + one_m_alpha2 * ( -12.0*A1*A2*(1.0-C2)*GH - 3.0*A2*B2*(1.0-C3)*GH ); - amrex::Real R1 = one_m_alpha * ( A1*(1.0-3.0*C1) ); - amrex::Real R2 = one_m_alpha * A2; - - amrex::Real SM = (R2*E2 - R1*E4)/(E2*E3 - E1*E4); - amrex::Real SH = (R1*E3 - R2*E1)/(E2*E3 - E1*E4); - amrex::Real SQ = 3.0 * SM; // Nakanishi & Niino 2009 - - // Finally, compute the eddy viscosity/diffusivities - const amrex::Real rho = cell_data(i,j,k,Rho_comp); - K_turb(i,j,k,EddyDiff::Mom_v) = rho * l_comb * qvel(i,j,k) * SM * 0.5; // 0.5 for mu_turb - K_turb(i,j,k,EddyDiff::Theta_v) = rho * l_comb * qvel(i,j,k) * SH; - K_turb(i,j,k,EddyDiff::QKE_v) = rho * l_comb * qvel(i,j,k) * SQ; - - K_turb(i,j,k,EddyDiff::PBL_lengthscale) = l_comb; - // TODO: How should this be done for other components (scalars, moisture) - }); + for ( amrex::MFIter mfi(eddyViscosity,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { + + const amrex::Box &bx = mfi.growntilebox(1); + const amrex::Array4 &cell_data = cons_in.array(mfi); + const amrex::Array4 &K_turb = eddyViscosity.array(mfi); + const amrex::Array4 &uvel = xvel.array(mfi); + const amrex::Array4 &vvel = yvel.array(mfi); + + // Compute some quantities that are constant in each column + // Sbox is shrunk to only include the interior of the domain in the vertical direction to compute integrals + // Box includes one ghost cell in each direction + const amrex::Box &dbx = geom.Domain(); + amrex::Box sbx(bx.smallEnd(), bx.bigEnd()); + sbx.grow(2,-1); + AMREX_ALWAYS_ASSERT(sbx.smallEnd(2) == dbx.smallEnd(2) && sbx.bigEnd(2) == dbx.bigEnd(2)); + + const amrex::GeometryData gdata = geom.data(); + + const amrex::Box xybx = PerpendicularBox(bx, amrex::IntVect{0,0,0}); + amrex::FArrayBox qintegral(xybx,2); + qintegral.setVal(0.0); + amrex::FArrayBox qturb(bx,1); amrex::FArrayBox qturb_old(bx,1); + const amrex::Array4 qint = qintegral.array(); + const amrex::Array4 qvel = qturb.array(); + const amrex::Array4 qvel_old = qturb_old.array(); + + amrex::ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), bx, + [=] AMREX_GPU_DEVICE (int i, int j, int k, amrex::Gpu::Handler const& handler) noexcept + { + qvel(i,j,k) = std::sqrt(cell_data(i,j,k,RhoQKE_comp) / cell_data(i,j,k,Rho_comp)); + qvel_old(i,j,k) = std::sqrt(cell_data(i,j,k,RhoQKE_comp) / cell_data(i,j,k,Rho_comp) + eps); + AMREX_ASSERT_WITH_MESSAGE(qvel(i,j,k) > 0.0, "QKE must have a positive value"); + AMREX_ASSERT_WITH_MESSAGE(qvel_old(i,j,k) > 0.0, "Old QKE must have a positive value"); + + const amrex::Real Zval = gdata.ProbLo(2) + (k + 0.5)*gdata.CellSize(2); + if (sbx.contains(i,j,k)) { + amrex::Gpu::deviceReduceSum(&qint(i,j,0,0), Zval*qvel(i,j,k), handler); + amrex::Gpu::deviceReduceSum(&qint(i,j,0,1), qvel(i,j,k), handler); + } + }); + + amrex::Real dz_inv = geom.InvCellSize(2); + int izmin = geom.Domain().smallEnd(2); + int izmax = geom.Domain().bigEnd(2); + + // Spatially varying MOST + amrex::Real d_kappa = KAPPA; + amrex::Real d_gravity = CONST_GRAV; + + const auto& t_mean_mf = most->get_mac_avg(0,2); // TODO: IS THIS ACTUALLY RHOTHETA + const auto& u_star_mf = most->get_u_star(0); // Use coarsest level + const auto& t_star_mf = most->get_t_star(0); // Use coarsest level + + const auto& tm_arr = t_mean_mf->array(mfi); // TODO: IS THIS ACTUALLY RHOTHETA + const auto& u_star_arr = u_star_mf->array(mfi); + const auto& t_star_arr = t_star_mf->array(mfi); + + amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + // Compute some partial derivatives that we will need (second order) + // U and V derivatives are interpolated to account for staggered grid + amrex::Real dthetadz, dudz, dvdz; + if ( k==izmax && c_ext_dir_on_zhi ) { + dthetadz = (1.0/3.0)*(-cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) + - 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) + + 4.0 * cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) )*dz_inv; + } else if ( k==izmin && c_ext_dir_on_zlo ) { + dthetadz = (1.0/3.0)*( cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) + + 3.0 * cell_data(i,j,k ,RhoTheta_comp)/cell_data(i,j,k ,Rho_comp) + - 4.0 * cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp) )*dz_inv; + } else { + dthetadz = 0.5*(cell_data(i,j,k+1,RhoTheta_comp)/cell_data(i,j,k+1,Rho_comp) + - cell_data(i,j,k-1,RhoTheta_comp)/cell_data(i,j,k-1,Rho_comp))*dz_inv; + } + + if ( k==izmax && u_ext_dir_on_zhi ) { + dudz = (1.0/6.0)*( (-uvel(i ,j,k-1) - 3.0 * uvel(i ,j,k ) + 4.0 * uvel(i ,j,k+1)) + + (-uvel(i+1,j,k-1) - 3.0 * uvel(i+1,j,k ) + 4.0 * uvel(i+1,j,k+1)) )*dz_inv; + } else if ( k==izmin && u_ext_dir_on_zlo ) { + dudz = (1.0/6.0)*( (uvel(i ,j,k+1) + 3.0 * uvel(i ,j,k ) - 4.0 * uvel(i ,j,k-1)) + + (uvel(i+1,j,k+1) + 3.0 * uvel(i+1,j,k ) - 4.0 * uvel(i+1,j,k-1)) )*dz_inv; + } else { + dudz = 0.25*(uvel(i,j,k+1) - uvel(i,j,k-1) + uvel(i+1,j,k+1) - uvel(i+1,j,k-1))*dz_inv; + } + + if ( k==izmax && v_ext_dir_on_zhi ) { + dvdz = (1.0/6.0)*( (-vvel(i,j ,k-1) - 3.0 * vvel(i,j ,k ) + 4.0 * vvel(i,j ,k+1)) + + (-vvel(i,j+1,k-1) - 3.0 * vvel(i,j+1,k ) + 4.0 * vvel(i,j+1,k+1)) )*dz_inv; + } else if ( k==izmin && v_ext_dir_on_zlo ) { + dvdz = (1.0/6.0)*( (vvel(i,j ,k+1) + 3.0 * vvel(i,j ,k ) - 4.0 * vvel(i,j ,k-1)) + + (vvel(i,j+1,k+1) + 3.0 * vvel(i,j+1,k ) - 4.0 * vvel(i,j+1,k-1)) )*dz_inv; + } else { + dvdz = 0.25*(vvel(i,j,k+1) - vvel(i,j,k-1) + vvel(i,j+1,k+1) - vvel(i,j+1,k-1))*dz_inv; + } + + // Spatially varying MOST + amrex::Real surface_heat_flux = -u_star_arr(i,j,0) * t_star_arr(i,j,0); + amrex::Real theta0 = tm_arr(i,j,0); // TODO: IS THIS ACTUALLY RHOTHETA + amrex::Real l_obukhov; + if (std::abs(surface_heat_flux) > eps) { + l_obukhov = ( theta0 * u_star_arr(i,j,0) * u_star_arr(i,j,0) ) / + ( d_kappa * d_gravity * t_star_arr(i,j,0) ); + } else { + l_obukhov = std::numeric_limits::max(); + } + + // First Length Scale + AMREX_ASSERT(l_obukhov != 0); + int lk = amrex::max(k,0); + const amrex::Real zval = gdata.ProbLo(2) + (lk + 0.5)*gdata.CellSize(2); + const amrex::Real zeta = zval/l_obukhov; + amrex::Real l_S; + if (zeta >= 1.0) { + l_S = KAPPA*zval/3.7; + } else if (zeta >= 0) { + l_S = KAPPA*zval/(1+2.7*zeta); + } else { + l_S = KAPPA*zval*std::pow(1.0 - 100.0 * zeta, 0.2); + } + + // Second Length Scale + amrex::Real l_T; + if (qint(i,j,0,1) > 0.0) { + l_T = 0.23*qint(i,j,0,0)/qint(i,j,0,1); + } else { + l_T = std::numeric_limits::max(); + } + + // Third Length Scale + amrex::Real l_B; + if (dthetadz > 0) { + amrex::Real N_brunt_vaisala = std::sqrt(CONST_GRAV/theta0 * dthetadz); + if (zeta < 0) { + amrex::Real qc = CONST_GRAV/theta0 * surface_heat_flux * l_T; + qc = std::pow(qc,1.0/3.0); + l_B = (1.0 + 5.0*std::sqrt(qc/(N_brunt_vaisala * l_T))) * qvel(i,j,k)/N_brunt_vaisala; + } else { + l_B = qvel(i,j,k) / N_brunt_vaisala; + } + } else { + l_B = std::numeric_limits::max(); + } + + // Overall Length Scale + amrex::Real l_comb = 1.0 / (1.0/l_S + 1.0/l_T + 1.0/l_B); + + // NOTE: Level 2 limiting from balance of production and dissipation. + // K_turb has a setval of 0.0 when the MF is created (NOT EACH STEP). + // We do this inline to avoid storing qe^2 at each cell. + amrex::Real l_comb_old = K_turb(i,j,k,EddyDiff::PBL_lengthscale); + amrex::Real shearProd = dudz*dudz + dvdz*dvdz; + amrex::Real buoyProd = -(CONST_GRAV/theta0) * dthetadz; + amrex::Real lSM = K_turb(i,j,k,EddyDiff::Mom_v) / (qvel_old(i,j,k) + eps); + amrex::Real lSH = K_turb(i,j,k,EddyDiff::Theta_v) / (qvel_old(i,j,k) + eps); + amrex::Real qe2 = B1 * l_comb_old * ( lSM * shearProd + lSH * buoyProd ); + amrex::Real qe = (qe2 < 0.0) ? 0.0 : std::sqrt(qe2); + amrex::Real one_m_alpha = (qvel(i,j,k) > qe) ? 1.0 : qvel(i,j,k) / (qe + eps); + amrex::Real one_m_alpha2 = one_m_alpha * one_m_alpha; + + // Compute non-dimensional parameters + amrex::Real l2_over_q2 = l_comb*l_comb/(qvel(i,j,k)*qvel(i,j,k)); + amrex::Real GM = l2_over_q2 * shearProd; + amrex::Real GH = l2_over_q2 * buoyProd; + amrex::Real E1 = 1.0 + one_m_alpha2 * ( 6.0*A1*A1*GM - 9.0*A1*A2*(1.0-C2)*GH ); + amrex::Real E2 = one_m_alpha2 * ( -3.0*A1*(4.0*A1 + 3.0*A2*(1.0-C5))*(1.0-C2)*GH ); + amrex::Real E3 = one_m_alpha2 * ( 6.0*A1*A2*GM ); + amrex::Real E4 = 1.0 + one_m_alpha2 * ( -12.0*A1*A2*(1.0-C2)*GH - 3.0*A2*B2*(1.0-C3)*GH ); + amrex::Real R1 = one_m_alpha * ( A1*(1.0-3.0*C1) ); + amrex::Real R2 = one_m_alpha * A2; + + amrex::Real SM = (R2*E2 - R1*E4)/(E2*E3 - E1*E4); + amrex::Real SH = (R1*E3 - R2*E1)/(E2*E3 - E1*E4); + amrex::Real SQ = 3.0 * SM; // Nakanishi & Niino 2009 + + // Finally, compute the eddy viscosity/diffusivities + const amrex::Real rho = cell_data(i,j,k,Rho_comp); + K_turb(i,j,k,EddyDiff::Mom_v) = rho * l_comb * qvel(i,j,k) * SM * 0.5; // 0.5 for mu_turb + K_turb(i,j,k,EddyDiff::Theta_v) = rho * l_comb * qvel(i,j,k) * SH; + K_turb(i,j,k,EddyDiff::QKE_v) = rho * l_comb * qvel(i,j,k) * SQ; + + K_turb(i,j,k,EddyDiff::PBL_lengthscale) = l_comb; + // TODO: How should this be done for other components (scalars, moisture) + }); + } + } else if (turbChoice.pbl_type == PBLType::YSU) { + amrex::Error("YSU Model not implemented yet"); } - } else if (turbChoice.pbl_type == PBLType::YSU) { - amrex::Error("YSU Model not implemented yet"); - } } diff --git a/Source/Initialization/ERF_init_from_metgrid.cpp b/Source/Initialization/ERF_init_from_metgrid.cpp index 10be9dc82..56a4e6cb7 100644 --- a/Source/Initialization/ERF_init_from_metgrid.cpp +++ b/Source/Initialization/ERF_init_from_metgrid.cpp @@ -15,15 +15,12 @@ using namespace amrex; void ERF::init_from_metgrid (int lev) { -#ifndef AMREX_USE_GPU -#if defined(ERF_USE_MOISTURE) - amrex::Print() << "Init with met_em with ERF_USE_MOISTURE" << std::endl; -#elif defined(ERF_USE_WARM_NO_PRECIP) - amrex::Print() << "Init with met_em with ERF_USE_WARM_NO_PRECIP" << std::endl; -#else - amrex::Print() << "Init with met_em without moisture" << std::endl; -#endif -#endif + bool use_moisture = (solverChoice.moisture_type == MoistureType::None); + if (use_moisture) { + amrex::Print() << "Init with met_em with valid moisture model." << std::endl; + } else { + amrex::Print() << "Init with met_em without moisture model." << std::endl; + } int nboxes = num_boxes_at_level[lev]; int ntimes = num_files_at_level[lev]; @@ -230,11 +227,9 @@ ERF::init_from_metgrid (int lev) make_zcc(geom[lev],*z_phys,*z_phys_cc[lev]); // Set up FABs to hold data that will be used to set lateral boundary conditions. -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) - int MetGridBdyEnd = MetGridBdyVars::NumTypes; -#else int MetGridBdyEnd = MetGridBdyVars::NumTypes-1; -#endif + if (use_moisture) MetGridBdyEnd = MetGridBdyVars::NumTypes; + //amrex::Vector > fabs_for_bcs; amrex::Vector> fabs_for_bcs; fabs_for_bcs.resize(ntimes); @@ -280,7 +275,6 @@ ERF::init_from_metgrid (int lev) Box tbxc = mfi.tilebox(); Box tbxu = mfi.tilebox(IntVect(1,0,0)); Box tbxv = mfi.tilebox(IntVect(0,1,0)); - Box tbxw = mfi.tilebox(IntVect(0,0,1)); // Define FABs for hlding some of the initial data FArrayBox &cons_fab = lev_new[Vars::cons][mfi]; @@ -299,7 +293,7 @@ ERF::init_from_metgrid (int lev) // z_vel set to 0.0 // theta calculate on origin levels then interpolate // mxrat convert RH -> Q on origin levels then interpolate - init_state_from_metgrid(l_rdOcp, + init_state_from_metgrid(use_moisture, l_rdOcp, tbxc, tbxu, tbxv, cons_fab, xvel_fab, yvel_fab, zvel_fab, z_phys_nd_fab, @@ -343,7 +337,7 @@ ERF::init_from_metgrid (int lev) // r_hse calculate dry density // pi_hse calculate Exner term given pressure const Box valid_bx = mfi.validbox(); - init_base_state_from_metgrid(l_rdOcp, + init_base_state_from_metgrid(use_moisture, l_rdOcp, valid_bx, flag_psfc, cons_fab, r_hse_fab, p_hse_fab, pi_hse_fab, @@ -608,7 +602,8 @@ init_terrain_from_metgrid (FArrayBox& z_phys_nd_fab, * @param fabs_for_bcs Vector of Vector of FArrayBox objects holding MetGridBdyVars at each met_em time. */ void -init_state_from_metgrid (const Real l_rdOcp, +init_state_from_metgrid (const bool use_moisture, + const Real l_rdOcp, Box& tbxc, Box& tbxu, Box& tbxv, @@ -737,55 +732,51 @@ init_state_from_metgrid (const Real l_rdOcp, }); } -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) - // ******************************************************** - // specific humidity / relative humidity / mixing ratio - // ******************************************************** - // TODO: we will need to check what input data we have for moisture - // and then, if necessary, compute mixing ratio. For now, we will - // focus on the case where we have relative humidity. Alternate cases - // could be specific humidity or a mixing ratio. - // - { // calculate vapor mixing ratio from relative humidity. - Box bx = NC_temp_fab[it].box() & tbxc; - auto const rhum = NC_rhum_fab[it].const_array(); - auto const temp = NC_temp_fab[it].const_array(); - auto const pres = NC_pres_fab[it].const_array(); - auto mxrat = mxrat_fab[it].array(); + if (use_moisture) { + // ******************************************************** + // specific humidity / relative humidity / mixing ratio + // ******************************************************** + // TODO: we will need to check what input data we have for moisture + // and then, if necessary, compute mixing ratio. For now, we will + // focus on the case where we have relative humidity. Alternate cases + // could be specific humidity or a mixing ratio. + // + { // calculate vapor mixing ratio from relative humidity. + Box bx = NC_temp_fab[it].box() & tbxc; + auto const rhum = NC_rhum_fab[it].const_array(); + auto const temp = NC_temp_fab[it].const_array(); + auto const pres = NC_pres_fab[it].const_array(); + auto mxrat = mxrat_fab[it].array(); + + ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + { + rh_to_mxrat(i,j,k,rhum,temp,pres,mxrat); + }); + } - ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept + // vertical interpolation of vapor mixing ratio. { - rh_to_mxrat(i,j,k,rhum,temp,pres,mxrat); - }); - } - - // vertical interpolation of vapor mixing ratio. - { - Box bx2d = NC_temp_fab[it].box() & tbxc; - bx2d.setRange(2,0); - auto const orig_data = mxrat_fab[it].const_array(); - auto const orig_z = NC_ght_fab[it].const_array(); - auto new_data = state_fab.array(); - auto bc_data = fabs_for_bcs[it][MetGridBdyVars::QV].array(); - auto const new_z = z_phys_nd_fab.const_array(); - - int kmax = amrex::ubound(tbxc).z; - -#if defined(ERF_USE_MOISTURE) - int state_indx = RhoQ1_comp; -#elif defined(ERF_USE_WARM_NO_PRECIP) - int state_indx = RhoQv_comp; -#endif - ParallelFor(bx2d, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept - { - for (int k = 0; k<=kmax; k++) { - Real Interp_Val = interpolate_column_metgrid(i,j,k,'M',0,orig_z,orig_data,new_z); - if (mask_c_arr(i,j,k)) bc_data(i,j,k,0) = Interp_Val; - if (it==0) new_data(i,j,k,state_indx) = Interp_Val; + Box bx2d = NC_temp_fab[it].box() & tbxc; + bx2d.setRange(2,0); + auto const orig_data = mxrat_fab[it].const_array(); + auto const orig_z = NC_ght_fab[it].const_array(); + auto new_data = state_fab.array(); + auto bc_data = fabs_for_bcs[it][MetGridBdyVars::QV].array(); + auto const new_z = z_phys_nd_fab.const_array(); + + int kmax = amrex::ubound(tbxc).z; + + int state_indx = RhoQ1_comp; + ParallelFor(bx2d, [=] AMREX_GPU_DEVICE (int i, int j, int) noexcept + { + for (int k = 0; k<=kmax; k++) { + Real Interp_Val = interpolate_column_metgrid(i,j,k,'M',0,orig_z,orig_data,new_z); + if (mask_c_arr(i,j,k)) bc_data(i,j,k,0) = Interp_Val; + if (it==0) new_data(i,j,k,state_indx) = Interp_Val; + } + }); } - }); } -#endif // TODO: TEMPORARY CODE TO RUN QUIESCENT, REMOVE WHEN NOT NEEDED. // if (it == 0) { @@ -815,7 +806,8 @@ init_state_from_metgrid (const Real l_rdOcp, * @param fabs_for_bcs Vector of Vector of FArrayBox objects holding MetGridBdyVars at each met_em time. */ void -init_base_state_from_metgrid (const Real l_rdOcp, +init_base_state_from_metgrid (const bool use_moisture, + const Real l_rdOcp, const Box& valid_bx, const Vector& flag_psfc, FArrayBox& state_fab, @@ -828,11 +820,7 @@ init_base_state_from_metgrid (const Real l_rdOcp, Vector>& fabs_for_bcs, const amrex::Array4& mask_c_arr) { -#if defined(ERF_USE_MOISTURE) int RhoQ_comp = RhoQ1_comp; -#elif defined(ERF_USE_WARM_NO_PRECIP) - int RhoQ_comp = RhoQv_comp; -#endif int kmax = amrex::ubound(valid_bx).z; // Device vectors for columnwise operations @@ -843,9 +831,7 @@ init_base_state_from_metgrid (const Real l_rdOcp, Gpu::DeviceVector Rhom_vec_d(kmax+1,0); Real* Rhom_vec = Rhom_vec_d.data(); Gpu::DeviceVector Pd_vec_d(kmax+1,0); Real* Pd_vec = Pd_vec_d.data(); Gpu::DeviceVector Pm_vec_d(kmax+1,0); Real* Pm_vec = Pm_vec_d.data(); -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) Gpu::DeviceVector Q_vec_d(kmax+1,0); Real* Q_vec = Q_vec_d.data(); -#endif // Device vectors for psfc flags Gpu::DeviceVectorflag_psfc_d(flag_psfc.size()); @@ -872,16 +858,12 @@ init_base_state_from_metgrid (const Real l_rdOcp, for (int k=0; k<=kmax; k++) { z_vec[k] = new_z(i,j,k); Thetad_vec[k] = new_data(i,j,k,RhoTheta_comp); -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) - Q_vec[k] = new_data(i,j,k,RhoQ_comp); -#endif + Q_vec[k] = (use_moisture) ? new_data(i,j,k,RhoQ_comp) : 0.0; } z_vec[kmax+1] = new_z(i,j,kmax+1); calc_rho_p(kmax,flag_psfc_vec[0],orig_psfc(i,j,0),Thetad_vec,Thetam_vec, -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) Q_vec, -#endif z_vec,Rhod_vec,Rhom_vec,Pd_vec,Pm_vec); for (int k=0; k<=kmax; k++) { @@ -897,10 +879,10 @@ init_base_state_from_metgrid (const Real l_rdOcp, // RhoTheta and RhoQ1 or RhoQv currently hold Theta and Q1 or Qv. Multiply by Rho. Real RhoTheta = r_hse_arr(i,j,k)*new_data(i,j,k,RhoTheta_comp); new_data(i,j,k,RhoTheta_comp) = RhoTheta; -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) - Real RhoQ = r_hse_arr(i,j,k)*new_data(i,j,k,RhoQ_comp); - new_data(i,j,k,RhoQ_comp) = RhoQ; -#endif + if (use_moisture){ + Real RhoQ = r_hse_arr(i,j,k)*new_data(i,j,k,RhoQ_comp); + new_data(i,j,k,RhoQ_comp) = RhoQ; + } pi_hse_arr(i,j,k) = getExnergivenP(p_hse_arr(i,j,k), l_rdOcp); //pi_hse_arr(i,j,k) = getExnergivenRTh(RhoTheta, l_rdOcp); }); @@ -925,9 +907,7 @@ init_base_state_from_metgrid (const Real l_rdOcp, auto const orig_psfc = NC_psfc_fab[it].const_array(); auto const new_z = z_phys_nd_fab.const_array(); auto Theta_arr = fabs_for_bcs[it][MetGridBdyVars::T].array(); -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) auto Q_arr = fabs_for_bcs[it][MetGridBdyVars::QV].array(); -#endif auto r_hse_arr = fabs_for_bcs[it][MetGridBdyVars::R].array(); auto p_hse_arr = p_hse_bcs_fab.array(); @@ -936,25 +916,19 @@ init_base_state_from_metgrid (const Real l_rdOcp, for (int k=0; k<=kmax; k++) { z_vec[k] = new_z(i,j,k); Thetad_vec[k] = Theta_arr(i,j,k); -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) - Q_vec[k] = Q_arr(i,j,k); -#endif + Q_vec[k] = (use_moisture) ? Q_arr(i,j,k) : 0.0; } z_vec[kmax+1] = new_z(i,j,kmax+1); calc_rho_p(kmax,flag_psfc_vec[it],orig_psfc(i,j,0),Thetad_vec,Thetam_vec, -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) Q_vec, -#endif z_vec,Rhod_vec,Rhom_vec,Pd_vec,Pm_vec); for (int k=0; k<=kmax; k++) { p_hse_arr(i,j,k) = Pd_vec[k]; if (mask_c_arr(i,j,k)) { r_hse_arr(i,j,k) = Rhod_vec[k]; -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) - Q_arr(i,j,k) = Rhod_vec[k]*Q_vec[k]; -#endif + Q_arr(i,j,k) = (use_moisture) ? Rhod_vec[k]*Q_vec[k] : 0.0; Theta_arr(i,j,k) = Rhod_vec[k]*Thetad_vec[k]; } } // k diff --git a/Source/Initialization/Metgrid_utils.H b/Source/Initialization/Metgrid_utils.H index af06ecd5d..ad96e9b09 100644 --- a/Source/Initialization/Metgrid_utils.H +++ b/Source/Initialization/Metgrid_utils.H @@ -45,7 +45,8 @@ init_terrain_from_metgrid (amrex::FArrayBox& z_phys_nd_fab, const amrex::Vector& NC_hgt_fab); void -init_state_from_metgrid (const amrex::Real l_rdOcp, +init_state_from_metgrid (const bool use_moisture, + const amrex::Real l_rdOcp, amrex::Box& tbxc, amrex::Box& tbxu, amrex::Box& tbxv, @@ -80,7 +81,8 @@ init_msfs_from_metgrid (amrex::FArrayBox& msfu_fab, const amrex::Vector& NC_MSFM_fab); void -init_base_state_from_metgrid (const amrex::Real l_rdOcp, +init_base_state_from_metgrid (const bool use_moisture, + const amrex::Real l_rdOcp, const amrex::Box& valid_bx, const amrex::Vector& flag_psfc, amrex::FArrayBox& state, @@ -101,9 +103,7 @@ calc_rho_p (const int& kmax, const amrex::Real& psfc, amrex::Real* Thetad_vec, amrex::Real* Thetam_vec, -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) amrex::Real* Q_vec, -#endif amrex::Real* z_vec, amrex::Real* Rhod_vec, amrex::Real* Rhom_vec, @@ -123,11 +123,7 @@ calc_rho_p (const int& kmax, // calculate virtual potential temperature at the surface. { -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) amrex::Real qvf = 1.0+(R_v/R_d+1.0)*Q_vec[0]; -#else - amrex::Real qvf = 1.0; -#endif Thetam_vec[0] = Thetad_vec[0]*qvf; } @@ -137,11 +133,7 @@ calc_rho_p (const int& kmax, // integrate from the surface to the top boundary. for (int k=1; k<=kmax; k++) { amrex::Real dz = z_vec[k]-z_vec[k-1]; -#if defined(ERF_USE_MOISTURE) || defined(ERF_USE_WARM_NO_PRECIP) amrex::Real qvf = 1.0+(R_v/R_d+1.0)*Q_vec[k]; -#else - amrex::Real qvf = 1.0; -#endif Thetam_vec[k] = Thetad_vec[k]*qvf; Rhom_vec[k] = Rhom_vec[k-1]; // an initial guess. for (int it=0; it accrrc; - amrex::TableData accrsi; - amrex::TableData accrsc; - amrex::TableData coefice; - amrex::TableData evaps1; - amrex::TableData evaps2; - amrex::TableData accrgi; - amrex::TableData accrgc; - amrex::TableData evapg1; - amrex::TableData evapg2; - amrex::TableData evapr1; - amrex::TableData evapr2; - - // vertical plane average data - amrex::TableData rho1d; - amrex::TableData pres1d; - amrex::TableData tabs1d; - amrex::TableData qt1d; - amrex::TableData qv1d; - amrex::TableData qn1d; - // independent variables amrex::Array mic_fab_vars; - - amrex::TableData gamaz; - amrex::TableData zmid; // mid value of vertical coordinate in physical domain - - // data (output) - amrex::TableData qifall; - amrex::TableData tlatqi; }; #endif diff --git a/Source/Microphysics/FastEddy/FastEddy.cpp b/Source/Microphysics/FastEddy/FastEddy.cpp index 0eb69f9b1..521c55a88 100644 --- a/Source/Microphysics/FastEddy/FastEddy.cpp +++ b/Source/Microphysics/FastEddy/FastEddy.cpp @@ -11,8 +11,8 @@ using namespace amrex; /** * Compute Precipitation-related Microphysics quantities. */ -void FastEddy::AdvanceFE () { - +void FastEddy::AdvanceFE () +{ auto tabs = mic_fab_vars[MicVar_FE::tabs]; // get the temperature, dentisy, theta, qt and qc from input diff --git a/Source/Microphysics/FastEddy/Update_FE.cpp b/Source/Microphysics/FastEddy/Update_FE.cpp index d6155ece7..ba3d30055 100644 --- a/Source/Microphysics/FastEddy/Update_FE.cpp +++ b/Source/Microphysics/FastEddy/Update_FE.cpp @@ -13,7 +13,6 @@ void FastEddy::Update (amrex::MultiFab& cons, amrex::MultiFab& qmoist) { - // Get the temperature, density, theta, qt and qp from input for ( amrex::MFIter mfi(cons,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { auto states_arr = cons.array(mfi); @@ -47,7 +46,6 @@ void FastEddy::Update (amrex::MultiFab& cons, */ void FastEddy::Copy_Micro_to_State (amrex::MultiFab& cons) { - // Get the temperature, density, theta, qt and qp from input for (amrex::MFIter mfi(cons,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { const auto& box3d = mfi.tilebox(); diff --git a/Source/Microphysics/Kessler/Kessler.cpp b/Source/Microphysics/Kessler/Kessler.cpp index cb5ca7dfe..4daee2c60 100644 --- a/Source/Microphysics/Kessler/Kessler.cpp +++ b/Source/Microphysics/Kessler/Kessler.cpp @@ -90,7 +90,6 @@ void Kessler::AdvanceKessler () ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - qt_array(i,j,k) = std::max(0.0, qt_array(i,j,k)); qp_array(i,j,k) = std::max(0.0, qp_array(i,j,k)); qn_array(i,j,k) = std::max(0.0, qn_array(i,j,k)); @@ -160,7 +159,6 @@ void Kessler::AdvanceKessler () dq_clwater_to_rain = std::min(dq_clwater_to_rain, qn_array(i,j,k)); } - if(std::fabs(fz_array(i,j,k+1)) < 1e-14) fz_array(i,j,k+1) = 0.0; if(std::fabs(fz_array(i,j,k)) < 1e-14) fz_array(i,j,k) = 0.0; Real dq_sed = 1.0/rho_array(i,j,k)*(fz_array(i,j,k+1) - fz_array(i,j,k))/dz*dtn; @@ -176,7 +174,6 @@ void Kessler::AdvanceKessler () qt_array(i,j,k) = std::max(0.0, qt_array(i,j,k)); qp_array(i,j,k) = std::max(0.0, qp_array(i,j,k)); qn_array(i,j,k) = std::max(0.0, qn_array(i,j,k)); - }); } } diff --git a/Source/Microphysics/SAM/Cloud_SAM.cpp b/Source/Microphysics/SAM/Cloud_SAM.cpp index 9001a62b8..8098a8d05 100644 --- a/Source/Microphysics/SAM/Cloud_SAM.cpp +++ b/Source/Microphysics/SAM/Cloud_SAM.cpp @@ -10,122 +10,123 @@ using namespace amrex; */ void SAM::Cloud () { - constexpr Real an = 1.0/(tbgmax-tbgmin); - constexpr Real bn = tbgmin*an; - constexpr Real ap = 1.0/(tprmax-tprmin); - constexpr Real bp = tprmin*ap; + constexpr Real an = 1.0/(tbgmax-tbgmin); + constexpr Real bn = tbgmin*an; + constexpr Real ap = 1.0/(tprmax-tprmin); + constexpr Real bp = tprmin*ap; - auto pres1d_t = pres1d.table(); + auto pres1d_t = pres1d.table(); - auto qt = mic_fab_vars[MicVar::qt]; - auto qp = mic_fab_vars[MicVar::qp]; - auto qn = mic_fab_vars[MicVar::qn]; - auto rho = mic_fab_vars[MicVar::rho]; - auto tabs = mic_fab_vars[MicVar::tabs]; + auto qt = mic_fab_vars[MicVar::qt]; + auto qp = mic_fab_vars[MicVar::qp]; + auto qn = mic_fab_vars[MicVar::qn]; + auto rho = mic_fab_vars[MicVar::rho]; + auto tabs = mic_fab_vars[MicVar::tabs]; - Real fac_cond = m_fac_cond; - Real fac_sub = m_fac_sub; - Real fac_fus = m_fac_fus; + Real fac_cond = m_fac_cond; + Real fac_sub = m_fac_sub; + Real fac_fus = m_fac_fus; - for ( MFIter mfi(*tabs, TilingIfNotGPU()); mfi.isValid(); ++mfi) { - auto qt_array = qt->array(mfi); - auto qp_array = qp->array(mfi); - auto qn_array = qn->array(mfi); - auto tabs_array = tabs->array(mfi); + for ( MFIter mfi(*tabs, TilingIfNotGPU()); mfi.isValid(); ++mfi) { + auto qt_array = qt->array(mfi); + auto qp_array = qp->array(mfi); + auto qn_array = qn->array(mfi); + auto tabs_array = tabs->array(mfi); - const auto& box3d = mfi.tilebox() & m_gtoe[mfi.index()]; + const auto& box3d = mfi.tilebox() & m_gtoe[mfi.index()]; - ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k) { - qt_array(i,j,k) = std::max(0.0,qt_array(i,j,k)); - // Initial guess for temperature assuming no cloud water/ice: - Real tabs1 = tabs_array(i,j,k); + ParallelFor(box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k) + { + qt_array(i,j,k) = std::max(0.0,qt_array(i,j,k)); + // Initial guess for temperature assuming no cloud water/ice: + Real tabs1 = tabs_array(i,j,k); - Real qsatt; - Real om; - Real qsatt1; - Real qsatt2; + Real qsatt; + Real om; + Real qsatt1; + Real qsatt2; - // Warm cloud: - if(tabs1 > tbgmax) { - tabs1 = tabs_array(i,j,k)+fac_cond*qp_array(i,j,k); - erf_qsatw(tabs1, pres1d_t(k), qsatt); - } - // Ice cloud: - else if(tabs1 <= tbgmin) { - tabs1 = tabs_array(i,j,k)+fac_sub*qp_array(i,j,k); - erf_qsati(tabs1, pres1d_t(k), qsatt); - } - // Mixed-phase cloud: - else { - om = an*tabs1-bn; - erf_qsatw(tabs1, pres1d_t(k), qsatt1); - erf_qsati(tabs1, pres1d_t(k), qsatt2); - qsatt = om*qsatt1 + (1.-om)*qsatt2; - } - - int niter; - Real dtabs, lstarn, dlstarn, omp, lstarp, dlstarp, fff, dfff, dqsat; - // Test if condensation is possible: - if(qt_array(i,j,k) > qsatt) { - niter = 0; - dtabs = 1; - do { - if(tabs1 >= tbgmax) { - om=1.0; - lstarn = fac_cond; - dlstarn = 0.0; - erf_qsatw(tabs1, pres1d_t(k), qsatt); - erf_dtqsatw(tabs1, pres1d_t(k), dqsat); + // Warm cloud: + if(tabs1 > tbgmax) { + tabs1 = tabs_array(i,j,k)+fac_cond*qp_array(i,j,k); + erf_qsatw(tabs1, pres1d_t(k), qsatt); } + // Ice cloud: else if(tabs1 <= tbgmin) { - om = 0.0; - lstarn = fac_sub; - dlstarn = 0.0; - erf_qsati(tabs1, pres1d_t(k), qsatt); - erf_dtqsati(tabs1, pres1d_t(k), dqsat); - } - else { - om=an*tabs1-bn; - lstarn = fac_cond+(1.0-om)*fac_fus; - dlstarn = an*fac_fus; - erf_qsatw(tabs1, pres1d_t(k), qsatt1); - erf_qsati(tabs1, pres1d_t(k), qsatt2); + tabs1 = tabs_array(i,j,k)+fac_sub*qp_array(i,j,k); + erf_qsati(tabs1, pres1d_t(k), qsatt); + } + // Mixed-phase cloud: + else { + om = an*tabs1-bn; + erf_qsatw(tabs1, pres1d_t(k), qsatt1); + erf_qsati(tabs1, pres1d_t(k), qsatt2); + qsatt = om*qsatt1 + (1.-om)*qsatt2; + } - qsatt = om*qsatt1+(1.-om)*qsatt2; - erf_dtqsatw(tabs1, pres1d_t(k), qsatt1); - erf_dtqsati(tabs1, pres1d_t(k), qsatt2); - dqsat = om*qsatt1+(1.-om)*qsatt2; - } + int niter; + Real dtabs, lstarn, dlstarn, omp, lstarp, dlstarp, fff, dfff, dqsat; + // Test if condensation is possible: + if(qt_array(i,j,k) > qsatt) { + niter = 0; + dtabs = 1; + do { + if(tabs1 >= tbgmax) { + om=1.0; + lstarn = fac_cond; + dlstarn = 0.0; + erf_qsatw(tabs1, pres1d_t(k), qsatt); + erf_dtqsatw(tabs1, pres1d_t(k), dqsat); + } + else if(tabs1 <= tbgmin) { + om = 0.0; + lstarn = fac_sub; + dlstarn = 0.0; + erf_qsati(tabs1, pres1d_t(k), qsatt); + erf_dtqsati(tabs1, pres1d_t(k), dqsat); + } + else { + om=an*tabs1-bn; + lstarn = fac_cond+(1.0-om)*fac_fus; + dlstarn = an*fac_fus; + erf_qsatw(tabs1, pres1d_t(k), qsatt1); + erf_qsati(tabs1, pres1d_t(k), qsatt2); - if(tabs1 >= tprmax) { - omp = 1.0; - lstarp = fac_cond; - dlstarp = 0.0; - } - else if(tabs1 <= tprmin) { - omp = 0.0; - lstarp = fac_sub; - dlstarp = 0.0; - } - else { - omp=ap*tabs1-bp; - lstarp = fac_cond+(1.0-omp)*fac_fus; - dlstarp = ap*fac_fus; - } - fff = tabs_array(i,j,k)-tabs1+lstarn*(qt_array(i,j,k)-qsatt)+lstarp*qp_array(i,j,k); - dfff = dlstarn*(qt_array(i,j,k)-qsatt)+dlstarp*qp_array(i,j,k)-lstarn*dqsat-1.0; - dtabs = -fff/dfff; - niter = niter+1; - tabs1 = tabs1+dtabs; - } while(std::abs(dtabs) > 0.01 && niter < 10); - qsatt = qsatt + dqsat*dtabs; - qn_array(i,j,k) = std::max(0.0, qt_array(i,j,k)-qsatt); - } - else { - qn_array(i,j,k) = 0.0; - } - tabs_array(i,j,k) = tabs1; - qp_array(i,j,k) = std::max(0.0, qp_array(i,j,k)); // just in case - }); - } + qsatt = om*qsatt1+(1.-om)*qsatt2; + erf_dtqsatw(tabs1, pres1d_t(k), qsatt1); + erf_dtqsati(tabs1, pres1d_t(k), qsatt2); + dqsat = om*qsatt1+(1.-om)*qsatt2; + } + + if(tabs1 >= tprmax) { + omp = 1.0; + lstarp = fac_cond; + dlstarp = 0.0; + } + else if(tabs1 <= tprmin) { + omp = 0.0; + lstarp = fac_sub; + dlstarp = 0.0; + } + else { + omp=ap*tabs1-bp; + lstarp = fac_cond+(1.0-omp)*fac_fus; + dlstarp = ap*fac_fus; + } + fff = tabs_array(i,j,k)-tabs1+lstarn*(qt_array(i,j,k)-qsatt)+lstarp*qp_array(i,j,k); + dfff = dlstarn*(qt_array(i,j,k)-qsatt)+dlstarp*qp_array(i,j,k)-lstarn*dqsat-1.0; + dtabs = -fff/dfff; + niter = niter+1; + tabs1 = tabs1+dtabs; + } while(std::abs(dtabs) > 0.01 && niter < 10); + qsatt = qsatt + dqsat*dtabs; + qn_array(i,j,k) = std::max(0.0, qt_array(i,j,k)-qsatt); + } + else { + qn_array(i,j,k) = 0.0; + } + tabs_array(i,j,k) = tabs1; + qp_array(i,j,k) = std::max(0.0, qp_array(i,j,k)); // just in case + }); + } } diff --git a/Source/Microphysics/SAM/Diagnose_SAM.cpp b/Source/Microphysics/SAM/Diagnose_SAM.cpp index 544a202f6..b671aabcc 100644 --- a/Source/Microphysics/SAM/Diagnose_SAM.cpp +++ b/Source/Microphysics/SAM/Diagnose_SAM.cpp @@ -7,46 +7,46 @@ */ void SAM::Diagnose () { - auto qt = mic_fab_vars[MicVar::qt]; - auto qp = mic_fab_vars[MicVar::qp]; - auto qv = mic_fab_vars[MicVar::qv]; - auto qn = mic_fab_vars[MicVar::qn]; - auto qcl = mic_fab_vars[MicVar::qcl]; - auto qci = mic_fab_vars[MicVar::qci]; - auto qpl = mic_fab_vars[MicVar::qpl]; - auto qpi = mic_fab_vars[MicVar::qpi]; - auto qg = mic_fab_vars[MicVar::qg]; - auto tabs = mic_fab_vars[MicVar::tabs]; + auto qt = mic_fab_vars[MicVar::qt]; + auto qp = mic_fab_vars[MicVar::qp]; + auto qv = mic_fab_vars[MicVar::qv]; + auto qn = mic_fab_vars[MicVar::qn]; + auto qcl = mic_fab_vars[MicVar::qcl]; + auto qci = mic_fab_vars[MicVar::qci]; + auto qpl = mic_fab_vars[MicVar::qpl]; + auto qpi = mic_fab_vars[MicVar::qpi]; + auto qg = mic_fab_vars[MicVar::qg]; + auto tabs = mic_fab_vars[MicVar::tabs]; - for ( amrex::MFIter mfi(*tabs, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { - auto qt_array = qt->array(mfi); - auto qp_array = qp->array(mfi); - auto qv_array = qv->array(mfi); - auto qn_array = qn->array(mfi); - auto qcl_array = qcl->array(mfi); - auto qci_array = qci->array(mfi); - auto qpl_array = qpl->array(mfi); - auto qpi_array = qpi->array(mfi); - auto qg_array = qg->array(mfi); - auto tabs_array = tabs->array(mfi); + for ( amrex::MFIter mfi(*tabs, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { + auto qt_array = qt->array(mfi); + auto qp_array = qp->array(mfi); + auto qv_array = qv->array(mfi); + auto qn_array = qn->array(mfi); + auto qcl_array = qcl->array(mfi); + auto qci_array = qci->array(mfi); + auto qpl_array = qpl->array(mfi); + auto qpi_array = qpi->array(mfi); + auto qg_array = qg->array(mfi); + auto tabs_array = tabs->array(mfi); - const auto& box3d = mfi.tilebox(); + const auto& box3d = mfi.tilebox(); - amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept - { - qv_array(i,j,k) = qt_array(i,j,k) - qn_array(i,j,k); - amrex::Real omn = std::max(0.0, std::min(1.0,(tabs_array(i,j,k)-tbgmin)*a_bg)); - qcl_array(i,j,k) = qn_array(i,j,k)*omn; - qci_array(i,j,k) = qn_array(i,j,k)*(1.0-omn); - amrex::Real omp = std::max(0.0, std::min(1.0,(tabs_array(i,j,k)-tprmin)*a_pr)); - qpl_array(i,j,k) = qp_array(i,j,k)*omp; - qpi_array(i,j,k) = qp_array(i,j,k)*(1.0-omp); + amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + qv_array(i,j,k) = qt_array(i,j,k) - qn_array(i,j,k); + amrex::Real omn = std::max(0.0, std::min(1.0,(tabs_array(i,j,k)-tbgmin)*a_bg)); + qcl_array(i,j,k) = qn_array(i,j,k)*omn; + qci_array(i,j,k) = qn_array(i,j,k)*(1.0-omn); + amrex::Real omp = std::max(0.0, std::min(1.0,(tabs_array(i,j,k)-tprmin)*a_pr)); + qpl_array(i,j,k) = qp_array(i,j,k)*omp; + qpi_array(i,j,k) = qp_array(i,j,k)*(1.0-omp); - // TODO: If omp above is bound by [0, 1], shouldn't this always be 0? - // Graupel == precip total - rain - snow (but must be >= 0) - qg_array(i,j,k) = std::max(0.0, qp_array(i,j,k)-qpl_array(i,j,k)-qpi_array(i,j,k)); - }); - } + // TODO: If omp above is bound by [0, 1], shouldn't this always be 0? + // Graupel == precip total - rain - snow (but must be >= 0) + qg_array(i,j,k) = std::max(0.0, qp_array(i,j,k)-qpl_array(i,j,k)-qpi_array(i,j,k)); + }); + } } diff --git a/Source/Microphysics/SAM/IceFall.cpp b/Source/Microphysics/SAM/IceFall.cpp index e3635e284..07797d05c 100644 --- a/Source/Microphysics/SAM/IceFall.cpp +++ b/Source/Microphysics/SAM/IceFall.cpp @@ -10,162 +10,166 @@ using namespace amrex; */ void SAM::IceFall () { - Real dz = m_geom.CellSize(2); - Real dtn = dt; - int nz = nlev; - - int kmax, kmin; - auto qcl = mic_fab_vars[MicVar::qcl]; - auto qci = mic_fab_vars[MicVar::qci]; - auto qt = mic_fab_vars[MicVar::qt]; - auto tabs = mic_fab_vars[MicVar::tabs]; - auto theta = mic_fab_vars[MicVar::theta]; - - MultiFab fz; - fz.define(qcl->boxArray(),qcl->DistributionMap(), 1, qcl->nGrowVect()); - fz.setVal(0.); - - auto qifall_t = qifall.table(); - auto tlatqi_t = tlatqi.table(); - auto rho1d_t = rho1d.table(); - - kmin = nz; - kmax = -1; - - { // calculate maximum and minium ice fall vertical region - auto const& qcl_arrays = qcl->const_arrays(); - auto const& qci_arrays = qci->const_arrays(); - auto const& tabs_arrays = tabs->const_arrays(); - - GpuTuple k_max_min = ParReduce(TypeList{}, - TypeList{}, - *qcl, IntVect::TheZeroVector(), - [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept - -> GpuTuple - { - bool is_positive = qcl_arrays[box_no](i,j,k)+qci_arrays[box_no](i,j,k) > 0.0; - bool smaller_than_zero = tabs_arrays[box_no](i,j,k) < 273.15; - int mkmin = is_positive && smaller_than_zero ? k : nz-1; - int mkmax = is_positive && smaller_than_zero ? k : 0; - return {mkmax, mkmin}; - }); - kmax = amrex::get<0>(k_max_min); - kmin = amrex::get<1>(k_max_min); - } + Real dz = m_geom.CellSize(2); + Real dtn = dt; + int nz = nlev; + + int kmax, kmin; + auto qcl = mic_fab_vars[MicVar::qcl]; + auto qci = mic_fab_vars[MicVar::qci]; + auto qt = mic_fab_vars[MicVar::qt]; + auto tabs = mic_fab_vars[MicVar::tabs]; + auto theta = mic_fab_vars[MicVar::theta]; + + MultiFab fz; + fz.define(qcl->boxArray(),qcl->DistributionMap(), 1, qcl->nGrowVect()); + fz.setVal(0.); + + auto qifall_t = qifall.table(); + auto tlatqi_t = tlatqi.table(); + auto rho1d_t = rho1d.table(); + + kmin = nz; + kmax = -1; + + { // calculate maximum and minium ice fall vertical region + auto const& qcl_arrays = qcl->const_arrays(); + auto const& qci_arrays = qci->const_arrays(); + auto const& tabs_arrays = tabs->const_arrays(); + + GpuTuple k_max_min = ParReduce(TypeList{}, + TypeList{}, + *qcl, IntVect::TheZeroVector(), + [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) noexcept + -> GpuTuple + { + bool is_positive = qcl_arrays[box_no](i,j,k)+qci_arrays[box_no](i,j,k) > 0.0; + bool smaller_than_zero = tabs_arrays[box_no](i,j,k) < 273.15; + int mkmin = is_positive && smaller_than_zero ? k : nz-1; + int mkmax = is_positive && smaller_than_zero ? k : 0; + return {mkmax, mkmin}; + }); + kmax = amrex::get<0>(k_max_min); + kmin = amrex::get<1>(k_max_min); + } //std::cout << "ice_fall: " << kmin << "; " << kmax << std::endl; - // for (int k=0; karray(mfi); - auto qci_array = qci->array(mfi); - auto qt_array = qt->array(mfi); - //auto tabs_array = tabs->array(mfi); - auto theta_array = theta->array(mfi); - auto fz_array = fz.array(mfi); - - const auto& box3d = mfi.tilebox(); - - amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - if (k >= std::max(0,kmin-1) && k <= kmax ) { - // Set up indices for x-y planes above and below current plane. - int kc = std::min(k+1, nz-1); - int kb = std::max(k-1, 0); - - // CFL number based on grid spacing interpolated to interface i,j,k-1/2 - Real coef = dtn/dz; //dtn/(0.5*(adz(kb)+adz(k))*dz); - - // Compute cloud ice density in this cell and the ones above/below. - // Since cloud ice is falling, the above cell is u(icrm,upwind), - // this cell is c (center) and the one below is d (downwind). - Real qiu = rho1d_t(kc)*qci_array(i,j,kc); - Real qic = rho1d_t(k )*qci_array(i,j,k ); - Real qid = rho1d_t(kb)*qci_array(i,j,kb); - - // Ice sedimentation velocity depends on ice content. The fiting is - // based on the data by Heymsfield (JAS,2003). -Marat - Real vt_ice = min( 0.4 , 8.66 * pow( (max(0.,qic)+1.e-10) , 0.24) ); // Heymsfield (JAS, 2003, p.2607) - - // Use MC flux limiter in computation of flux correction. - // (MC = monotonized centered difference). - // if (qic.eq.qid) then - Real tmp_phi; - if ( std::abs(qic-qid) < 1.0e-25 ) { // when qic, and qid is very small, qic_qid can still be zero - // even if qic is not equal to qid. so add a fix here +++mhwang - tmp_phi = 0.; - } else { - Real tmp_theta = (qiu-qic)/(qic-qid+1.0e-20); - tmp_phi = max(0., min(0.5*(1.+tmp_theta), min(2., 2.*tmp_theta))); - } - - // Compute limited flux. - // Since falling cloud ice is a 1D advection problem, this - // flux-limited advection scheme is monotonic. - fz_array(i,j,k) = -vt_ice*(qic - 0.5*(1.-coef*vt_ice)*tmp_phi*(qic-qid)); - } - }); - - // for (int j=0; j= std::max(0,kmin-1) && k <= kmax ) { - Real coef = dtn/dz; - // The cloud ice increment is the difference of the fluxes. - Real dqi = coef*(fz_array(i,j,k)-fz_array(i,j,k+1)); - // Add this increment to both non-precipitating and total water. - amrex::Gpu::Atomic::Add(&qt_array(i,j,k), dqi); - // Include this effect in the total moisture budget. - amrex::Gpu::Atomic::Add(&qifall_t(k), dqi); - - // The latent heat flux induced by the falling cloud ice enters - // the liquid-ice static energy budget in the same way as the - // precipitation. Note: use latent heat of sublimation. - Real lat_heat = (fac_cond+fac_fus)*dqi; - - // Add divergence of latent heat flux contribution to liquid-ice static potential temperature. - amrex::Gpu::Atomic::Add(&theta_array(i,j,k), -lat_heat); - // Add divergence to liquid-ice static energy budget. - amrex::Gpu::Atomic::Add(&tlatqi_t(k), -lat_heat); - } - }); + // for (int k=0; karray(mfi); + auto qci_array = qci->array(mfi); + auto qt_array = qt->array(mfi); + //auto tabs_array = tabs->array(mfi); + auto theta_array = theta->array(mfi); + auto fz_array = fz.array(mfi); + + const auto& box3d = mfi.tilebox(); + + amrex::ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + if (k >= std::max(0,kmin-1) && k <= kmax ) { + // Set up indices for x-y planes above and below current plane. + int kc = std::min(k+1, nz-1); + int kb = std::max(k-1, 0); + + // CFL number based on grid spacing interpolated to interface i,j,k-1/2 + Real coef = dtn/dz; //dtn/(0.5*(adz(kb)+adz(k))*dz); + + // Compute cloud ice density in this cell and the ones above/below. + // Since cloud ice is falling, the above cell is u(icrm,upwind), + // this cell is c (center) and the one below is d (downwind). + Real qiu = rho1d_t(kc)*qci_array(i,j,kc); + Real qic = rho1d_t(k )*qci_array(i,j,k ); + Real qid = rho1d_t(kb)*qci_array(i,j,kb); + + // Ice sedimentation velocity depends on ice content. The fiting is + // based on the data by Heymsfield (JAS,2003). -Marat + Real vt_ice = min( 0.4 , 8.66 * pow( (max(0.,qic)+1.e-10) , 0.24) ); // Heymsfield (JAS, 2003, p.2607) + + // Use MC flux limiter in computation of flux correction. + // (MC = monotonized centered difference). + // if (qic.eq.qid) then + Real tmp_phi; + if ( std::abs(qic-qid) < 1.0e-25 ) { // when qic, and qid is very small, qic_qid can still be zero + // even if qic is not equal to qid. so add a fix here +++mhwang + tmp_phi = 0.; + } else { + Real tmp_theta = (qiu-qic)/(qic-qid+1.0e-20); + tmp_phi = max(0., min(0.5*(1.+tmp_theta), min(2., 2.*tmp_theta))); + } + + // Compute limited flux. + // Since falling cloud ice is a 1D advection problem, this + // flux-limited advection scheme is monotonic. + fz_array(i,j,k) = -vt_ice*(qic - 0.5*(1.-coef*vt_ice)*tmp_phi*(qic-qid)); + } + }); + + // for (int j=0; j= std::max(0,kmin-1) && k <= kmax ) { + Real coef = dtn/dz; + // The cloud ice increment is the difference of the fluxes. + Real dqi = coef*(fz_array(i,j,k)-fz_array(i,j,k+1)); + // Add this increment to both non-precipitating and total water. + amrex::Gpu::Atomic::Add(&qt_array(i,j,k), dqi); + // Include this effect in the total moisture budget. + amrex::Gpu::Atomic::Add(&qifall_t(k), dqi); + + // The latent heat flux induced by the falling cloud ice enters + // the liquid-ice static energy budget in the same way as the + // precipitation. Note: use latent heat of sublimation. + Real lat_heat = (fac_cond+fac_fus)*dqi; + + // Add divergence of latent heat flux contribution to liquid-ice static potential temperature. + amrex::Gpu::Atomic::Add(&theta_array(i,j,k), -lat_heat); + // Add divergence to liquid-ice static energy budget. + amrex::Gpu::Atomic::Add(&tlatqi_t(k), -lat_heat); + } + }); #if 0 - // for (int j=0; j(ny,nx,ncrms) , YAKL_LAMBDA (int j, int i, int icrm) { - amrex::ParallelFor(box2d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - Real coef = dtn/dz; - Real dqi = -coef*fz(i,j,0); - precsfc (i,j) = precsfc (i,j)+dqi; - precssfc(i,j) = precssfc(i,j)+dqi; - }); + // for (int j=0; j(ny,nx,ncrms) , YAKL_LAMBDA (int j, int i, int icrm) { + amrex::ParallelFor(box2d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + Real coef = dtn/dz; + Real dqi = -coef*fz(i,j,0); + precsfc (i,j) = precsfc (i,j)+dqi; + precssfc(i,j) = precssfc(i,j)+dqi; + }); #endif - } + } } diff --git a/Source/Microphysics/SAM/Precip.cpp b/Source/Microphysics/SAM/Precip.cpp index aa58a6ee4..e4861a610 100644 --- a/Source/Microphysics/SAM/Precip.cpp +++ b/Source/Microphysics/SAM/Precip.cpp @@ -10,139 +10,140 @@ using namespace amrex; */ void SAM::Precip () { - Real powr1 = (3.0 + b_rain) / 4.0; - Real powr2 = (5.0 + b_rain) / 8.0; - Real pows1 = (3.0 + b_snow) / 4.0; - Real pows2 = (5.0 + b_snow) / 8.0; - Real powg1 = (3.0 + b_grau) / 4.0; - Real powg2 = (5.0 + b_grau) / 8.0; - - auto accrrc_t = accrrc.table(); - auto accrsc_t = accrsc.table(); - auto accrsi_t = accrsi.table(); - auto accrgc_t = accrgc.table(); - auto accrgi_t = accrgi.table(); - auto coefice_t = coefice.table(); - auto evapr1_t = evapr1.table(); - auto evapr2_t = evapr2.table(); - auto evaps1_t = evaps1.table(); - auto evaps2_t = evaps2.table(); - auto evapg1_t = evapg1.table(); - auto evapg2_t = evapg2.table(); - auto pres1d_t = pres1d.table(); - - auto qt = mic_fab_vars[MicVar::qt]; - auto qp = mic_fab_vars[MicVar::qp]; - auto qn = mic_fab_vars[MicVar::qn]; - auto tabs = mic_fab_vars[MicVar::tabs]; - - Real dtn = dt; - - // get the temperature, dentisy, theta, qt and qp from input - for ( MFIter mfi(*tabs,TilingIfNotGPU()); mfi.isValid(); ++mfi) { - auto tabs_array = mic_fab_vars[MicVar::tabs]->array(mfi); - auto qn_array = mic_fab_vars[MicVar::qn]->array(mfi); - auto qt_array = mic_fab_vars[MicVar::qt]->array(mfi); - auto qp_array = mic_fab_vars[MicVar::qp]->array(mfi); - - const auto& box3d = mfi.tilebox(); - - ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - //------- Autoconversion/accretion - Real omn, omp, omg, qcc, qii, autor, autos, accrr, qrr, accrcs, accris, - qss, accrcg, accrig, tmp, qgg, dq, qsatt, qsat; - - if (qn_array(i,j,k)+qp_array(i,j,k) > 0.0) { - omn = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tbgmin)*a_bg)); - omp = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tprmin)*a_pr)); - omg = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tgrmin)*a_gr)); - - if (qn_array(i,j,k) > 0.0) { - qcc = qn_array(i,j,k) * omn; - qii = qn_array(i,j,k) * (1.0-omn); - - if (qcc > qcw0) { - autor = alphaelq; - } else { - autor = 0.0; - } - - if (qii > qci0) { - autos = betaelq*coefice_t(k); - } else { - autos = 0.0; - } - - accrr = 0.0; - if (omp > 0.001) { - qrr = qp_array(i,j,k) * omp; - accrr = accrrc_t(k) * std::pow(qrr, powr1); + Real powr1 = (3.0 + b_rain) / 4.0; + Real powr2 = (5.0 + b_rain) / 8.0; + Real pows1 = (3.0 + b_snow) / 4.0; + Real pows2 = (5.0 + b_snow) / 8.0; + Real powg1 = (3.0 + b_grau) / 4.0; + Real powg2 = (5.0 + b_grau) / 8.0; + + auto accrrc_t = accrrc.table(); + auto accrsc_t = accrsc.table(); + auto accrsi_t = accrsi.table(); + auto accrgc_t = accrgc.table(); + auto accrgi_t = accrgi.table(); + auto coefice_t = coefice.table(); + auto evapr1_t = evapr1.table(); + auto evapr2_t = evapr2.table(); + auto evaps1_t = evaps1.table(); + auto evaps2_t = evaps2.table(); + auto evapg1_t = evapg1.table(); + auto evapg2_t = evapg2.table(); + auto pres1d_t = pres1d.table(); + + auto qt = mic_fab_vars[MicVar::qt]; + auto qp = mic_fab_vars[MicVar::qp]; + auto qn = mic_fab_vars[MicVar::qn]; + auto tabs = mic_fab_vars[MicVar::tabs]; + + Real dtn = dt; + + // get the temperature, dentisy, theta, qt and qp from input + for ( MFIter mfi(*tabs,TilingIfNotGPU()); mfi.isValid(); ++mfi) { + auto tabs_array = mic_fab_vars[MicVar::tabs]->array(mfi); + auto qn_array = mic_fab_vars[MicVar::qn]->array(mfi); + auto qt_array = mic_fab_vars[MicVar::qt]->array(mfi); + auto qp_array = mic_fab_vars[MicVar::qp]->array(mfi); + + const auto& box3d = mfi.tilebox(); + + ParallelFor(box3d, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + //------- Autoconversion/accretion + Real omn, omp, omg, qcc, qii, autor, autos, accrr, qrr, accrcs, accris, + qss, accrcg, accrig, tmp, qgg, dq, qsatt, qsat; + + if (qn_array(i,j,k)+qp_array(i,j,k) > 0.0) { + omn = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tbgmin)*a_bg)); + omp = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tprmin)*a_pr)); + omg = std::max(0.0,std::min(1.0,(tabs_array(i,j,k)-tgrmin)*a_gr)); + + if (qn_array(i,j,k) > 0.0) { + qcc = qn_array(i,j,k) * omn; + qii = qn_array(i,j,k) * (1.0-omn); + + if (qcc > qcw0) { + autor = alphaelq; + } else { + autor = 0.0; + } + + if (qii > qci0) { + autos = betaelq*coefice_t(k); + } else { + autos = 0.0; + } + + accrr = 0.0; + if (omp > 0.001) { + qrr = qp_array(i,j,k) * omp; + accrr = accrrc_t(k) * std::pow(qrr, powr1); + } + + accrcs = 0.0; + accris = 0.0; + + if (omp < 0.999 && omg < 0.999) { + qss = qp_array(i,j,k) * (1.0-omp)*(1.0-omg); + tmp = pow(qss, pows1); + accrcs = accrsc_t(k) * tmp; + accris = accrsi_t(k) * tmp; + } + accrcg = 0.0; + accrig = 0.0; + if (omp < 0.999 && omg > 0.001) { + qgg = qp_array(i,j,k) * (1.0-omp)*omg; + tmp = pow(qgg, powg1); + accrcg = accrgc_t(k) * tmp; + accrig = accrgi_t(k) * tmp; + } + qcc = (qcc+dtn*autor*qcw0)/(1.0+dtn*(accrr+accrcs+accrcg+autor)); + qii = (qii+dtn*autos*qci0)/(1.0+dtn*(accris+accrig+autos)); + dq = dtn *(accrr*qcc + autor*(qcc-qcw0)+(accris+accrig)*qii + (accrcs+accrcg)*qcc + autos*(qii-qci0)); + dq = std::min(dq,qn_array(i,j,k)); + qt_array(i,j,k) = qt_array(i,j,k) - dq; + qp_array(i,j,k) = qp_array(i,j,k) + dq; + qn_array(i,j,k) = qn_array(i,j,k) - dq; + + } else if(qp_array(i,j,k) > qp_threshold && qn_array(i,j,k) == 0.0) { + + qsatt = 0.0; + if(omn > 0.001) { + erf_qsatw(tabs_array(i,j,k),pres1d_t(k),qsat); + qsatt = qsatt + omn*qsat; + } + if(omn < 0.999) { + erf_qsati(tabs_array(i,j,k),pres1d_t(k),qsat); + qsatt = qsatt + (1.-omn)*qsat; + } + dq = 0.0; + if(omp > 0.001) { + qrr = qp_array(i,j,k) * omp; + dq = dq + evapr1_t(k)*sqrt(qrr) + evapr2_t(k)*pow(qrr,powr2); + } + if(omp < 0.999 && omg < 0.999) { + qss = qp_array(i,j,k) * (1.0-omp)*(1.0-omg); + dq = dq + evaps1_t(k)*sqrt(qss) + evaps2_t(k)*pow(qss,pows2); + } + if(omp < 0.999 && omg > 0.001) { + qgg = qp_array(i,j,k) * (1.0-omp)*omg; + dq = dq + evapg1_t(k)*sqrt(qgg) + evapg2_t(k)*pow(qgg,powg2); + } + dq = dq * dtn * (qt_array(i,j,k) / qsatt-1.0); + dq = std::max(-0.5*qp_array(i,j,k),dq); + qt_array(i,j,k) = qt_array(i,j,k) - dq; + qp_array(i,j,k) = qp_array(i,j,k) + dq; + + } else { + qt_array(i,j,k) = qt_array(i,j,k) + qp_array(i,j,k); + qp_array(i,j,k) = 0.0; + } } - - accrcs = 0.0; - accris = 0.0; - - if (omp < 0.999 && omg < 0.999) { - qss = qp_array(i,j,k) * (1.0-omp)*(1.0-omg); - tmp = pow(qss, pows1); - accrcs = accrsc_t(k) * tmp; - accris = accrsi_t(k) * tmp; - } - accrcg = 0.0; - accrig = 0.0; - if (omp < 0.999 && omg > 0.001) { - qgg = qp_array(i,j,k) * (1.0-omp)*omg; - tmp = pow(qgg, powg1); - accrcg = accrgc_t(k) * tmp; - accrig = accrgi_t(k) * tmp; - } - qcc = (qcc+dtn*autor*qcw0)/(1.0+dtn*(accrr+accrcs+accrcg+autor)); - qii = (qii+dtn*autos*qci0)/(1.0+dtn*(accris+accrig+autos)); - dq = dtn *(accrr*qcc + autor*(qcc-qcw0)+(accris+accrig)*qii + (accrcs+accrcg)*qcc + autos*(qii-qci0)); - dq = std::min(dq,qn_array(i,j,k)); - qt_array(i,j,k) = qt_array(i,j,k) - dq; - qp_array(i,j,k) = qp_array(i,j,k) + dq; - qn_array(i,j,k) = qn_array(i,j,k) - dq; - - } else if(qp_array(i,j,k) > qp_threshold && qn_array(i,j,k) == 0.0) { - - qsatt = 0.0; - if(omn > 0.001) { - erf_qsatw(tabs_array(i,j,k),pres1d_t(k),qsat); - qsatt = qsatt + omn*qsat; - } - if(omn < 0.999) { - erf_qsati(tabs_array(i,j,k),pres1d_t(k),qsat); - qsatt = qsatt + (1.-omn)*qsat; - } - dq = 0.0; - if(omp > 0.001) { - qrr = qp_array(i,j,k) * omp; - dq = dq + evapr1_t(k)*sqrt(qrr) + evapr2_t(k)*pow(qrr,powr2); - } - if(omp < 0.999 && omg < 0.999) { - qss = qp_array(i,j,k) * (1.0-omp)*(1.0-omg); - dq = dq + evaps1_t(k)*sqrt(qss) + evaps2_t(k)*pow(qss,pows2); - } - if(omp < 0.999 && omg > 0.001) { - qgg = qp_array(i,j,k) * (1.0-omp)*omg; - dq = dq + evapg1_t(k)*sqrt(qgg) + evapg2_t(k)*pow(qgg,powg2); - } - dq = dq * dtn * (qt_array(i,j,k) / qsatt-1.0); - dq = std::max(-0.5*qp_array(i,j,k),dq); - qt_array(i,j,k) = qt_array(i,j,k) - dq; - qp_array(i,j,k) = qp_array(i,j,k) + dq; - - } else { - qt_array(i,j,k) = qt_array(i,j,k) + qp_array(i,j,k); - qp_array(i,j,k) = 0.0; - } - } - dq = qp_array(i,j,k); - qp_array(i,j,k) = max(0.0,qp_array(i,j,k)); - qt_array(i,j,k) = qt_array(i,j,k) + (dq-qp_array(i,j,k)); - }); - } + dq = qp_array(i,j,k); + qp_array(i,j,k) = max(0.0,qp_array(i,j,k)); + qt_array(i,j,k) = qt_array(i,j,k) + (dq-qp_array(i,j,k)); + }); + } } diff --git a/Source/Microphysics/SAM/Update_SAM.cpp b/Source/Microphysics/SAM/Update_SAM.cpp index bd7531d7f..08b7d33e6 100644 --- a/Source/Microphysics/SAM/Update_SAM.cpp +++ b/Source/Microphysics/SAM/Update_SAM.cpp @@ -13,48 +13,49 @@ void SAM::Update (amrex::MultiFab& cons, amrex::MultiFab& qmoist) { - // copy multifab data to qc, qv, and qi - amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qv], 0, 0, 1, mic_fab_vars[MicVar::qv]->nGrowVect()); // vapor - amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qcl], 0, 1, 1, mic_fab_vars[MicVar::qcl]->nGrowVect()); // cloud water - amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qci], 0, 2, 1, mic_fab_vars[MicVar::qci]->nGrowVect()); // cloud ice - amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qpl], 0, 3, 1, mic_fab_vars[MicVar::qpl]->nGrowVect()); // rain - amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qpi], 0, 4, 1, mic_fab_vars[MicVar::qpi]->nGrowVect()); // snow - - // Don't need to copy this since it is filled below - // amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qpi], 0, 5, 1, mic_fab_vars[MicVar::qci]->nGrowVect()); // graupel - - amrex::MultiFab qgraup_mf(qmoist, amrex::make_alias, 5, 1); - - // Get the temperature, density, theta, qt and qp from input - for ( amrex::MFIter mfi(cons,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { - auto states_arr = cons.array(mfi); - - auto rho_arr = mic_fab_vars[MicVar::rho]->array(mfi); - auto theta_arr = mic_fab_vars[MicVar::theta]->array(mfi); - auto qt_arr = mic_fab_vars[MicVar::qt]->array(mfi); - auto qp_arr = mic_fab_vars[MicVar::qp]->array(mfi); - auto qpl_arr = mic_fab_vars[MicVar::qpl]->array(mfi); - auto qpi_arr = mic_fab_vars[MicVar::qpi]->array(mfi); - - auto qgraup_arr= qgraup_mf.array(mfi); - - const auto& box3d = mfi.tilebox(); - - // get potential total density, temperature, qt, qp - amrex::ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k) { - states_arr(i,j,k,Rho_comp) = rho_arr(i,j,k); - states_arr(i,j,k,RhoTheta_comp) = rho_arr(i,j,k)*theta_arr(i,j,k); - states_arr(i,j,k,RhoQ1_comp) = rho_arr(i,j,k)*qt_arr(i,j,k); - states_arr(i,j,k,RhoQ2_comp) = rho_arr(i,j,k)*qp_arr(i,j,k); - - // Graupel == precip total - rain - snow (but must be >= 0) - qgraup_arr(i,j,k) = std::max(0.0, qp_arr(i,j,k)-qpl_arr(i,j,k)-qpi_arr(i,j,k)); - }); - } - - // Fill interior ghost cells and periodic boundaries - cons.FillBoundary(m_geom.periodicity()); - qmoist.FillBoundary(m_geom.periodicity()); + // copy multifab data to qc, qv, and qi + amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qv], 0, 0, 1, mic_fab_vars[MicVar::qv]->nGrowVect()); // vapor + amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qcl], 0, 1, 1, mic_fab_vars[MicVar::qcl]->nGrowVect()); // cloud water + amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qci], 0, 2, 1, mic_fab_vars[MicVar::qci]->nGrowVect()); // cloud ice + amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qpl], 0, 3, 1, mic_fab_vars[MicVar::qpl]->nGrowVect()); // rain + amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qpi], 0, 4, 1, mic_fab_vars[MicVar::qpi]->nGrowVect()); // snow + + // Don't need to copy this since it is filled below + // amrex::MultiFab::Copy(qmoist, *mic_fab_vars[MicVar::qpi], 0, 5, 1, mic_fab_vars[MicVar::qci]->nGrowVect()); // graupel + + amrex::MultiFab qgraup_mf(qmoist, amrex::make_alias, 5, 1); + + // Get the temperature, density, theta, qt and qp from input + for ( amrex::MFIter mfi(cons,amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi) { + auto states_arr = cons.array(mfi); + + auto rho_arr = mic_fab_vars[MicVar::rho]->array(mfi); + auto theta_arr = mic_fab_vars[MicVar::theta]->array(mfi); + auto qt_arr = mic_fab_vars[MicVar::qt]->array(mfi); + auto qp_arr = mic_fab_vars[MicVar::qp]->array(mfi); + auto qpl_arr = mic_fab_vars[MicVar::qpl]->array(mfi); + auto qpi_arr = mic_fab_vars[MicVar::qpi]->array(mfi); + + auto qgraup_arr= qgraup_mf.array(mfi); + + const auto& box3d = mfi.tilebox(); + + // get potential total density, temperature, qt, qp + amrex::ParallelFor( box3d, [=] AMREX_GPU_DEVICE (int i, int j, int k) + { + states_arr(i,j,k,Rho_comp) = rho_arr(i,j,k); + states_arr(i,j,k,RhoTheta_comp) = rho_arr(i,j,k)*theta_arr(i,j,k); + states_arr(i,j,k,RhoQ1_comp) = rho_arr(i,j,k)*qt_arr(i,j,k); + states_arr(i,j,k,RhoQ2_comp) = rho_arr(i,j,k)*qp_arr(i,j,k); + + // Graupel == precip total - rain - snow (but must be >= 0) + qgraup_arr(i,j,k) = std::max(0.0, qp_arr(i,j,k)-qpl_arr(i,j,k)-qpi_arr(i,j,k)); + }); + } + + // Fill interior ghost cells and periodic boundaries + cons.FillBoundary(m_geom.periodicity()); + qmoist.FillBoundary(m_geom.periodicity()); } /** diff --git a/Source/Radiation/Aero_rad_props.cpp b/Source/Radiation/Aero_rad_props.cpp index 9894d358a..340b49c0b 100644 --- a/Source/Radiation/Aero_rad_props.cpp +++ b/Source/Radiation/Aero_rad_props.cpp @@ -9,273 +9,284 @@ using yakl::fortran::parallel_for; using yakl::fortran::SimpleBounds; -void AerRadProps::initialize(int ngas_, int nmodes_, int num_aeroes_, - int nswbands_, int nlwbands_, - int ncol_, int nlev_, int nrh_, int top_lev_, - const std::vector& aero_names_, - const real2d& zi_, const real2d& pmid_, const real2d& temp_, - const real2d& qt_, const real2d& geom_radius) { - nmodes = nmodes_; - ngas = ngas_; - num_aeroes = num_aeroes_; - aero_names = aero_names_; - - nswbands = nswbands_; - nlwbands = nlwbands_; - ncol = ncol_; - nlev = nlev_; - nrh = nrh_; - top_lev = top_lev_; - - pmid = pmid_; - pdeldry = pmid_; - temp = temp_; - qt = qt_; - // geometric radius - geometric_radius = geom_radius; - // vertical grid - zi = zi_; - // initialize mam4 aero model - mam_aer.initialize(ncol, nlev, top_lev, nswbands, nlwbands); +void AerRadProps::initialize (int ngas_, int nmodes_, int num_aeroes_, + int nswbands_, int nlwbands_, + int ncol_, int nlev_, int nrh_, int top_lev_, + const std::vector& aero_names_, + const real2d& zi_, const real2d& pmid_, const real2d& temp_, + const real2d& qt_, const real2d& geom_radius) { + nmodes = nmodes_; + ngas = ngas_; + num_aeroes = num_aeroes_; + aero_names = aero_names_; + + nswbands = nswbands_; + nlwbands = nlwbands_; + ncol = ncol_; + nlev = nlev_; + nrh = nrh_; + top_lev = top_lev_; + + pmid = pmid_; + pdeldry = pmid_; + temp = temp_; + qt = qt_; + // geometric radius + geometric_radius = geom_radius; + // vertical grid + zi = zi_; + // initialize mam4 aero model + mam_aer.initialize(ncol, nlev, top_lev, nswbands, nlwbands); } -void AerRadProps::aer_rad_props_sw(const int& list_idx, const real& dt, const int& nnite, - const int1d& idxnite, const bool is_cmip6_volc, const real3d& tau, const real3d& tau_w, - const real3d& tau_w_g, const real3d& tau_w_f, const real2d& clear_rh) { - // radiative properties for each aerosol - real3d ta("ta", ncol, nlev, nswbands); - real3d tw("tw", ncol, nlev, nswbands); - real3d twf("twf", ncol, nlev, nswbands); - real3d twg("twg", ncol, nlev, nswbands); - - // aerosol masses - real2d aermmr("aermmr", ncol, nlev); // mass mixing ratio of aerosols - real2d mmr_to_mass("mmr_to_mass", ncol, nlev); // conversion factor for mmr to mass - real2d aermass("aermass", ncol, nlev); // mass of aerosols - - // for table lookup into rh grid - real2d es("es", ncol, nlev); // saturation vapor pressure - real2d qs("qs", ncol, nlev); // saturation specific humidity - real2d rh("rh", ncol, nlev); - real2d rhtrunc("rhtrunc", ncol, nlev); - real2d wrh("wrh", ncol, nlev); - int2d krh("krh", ncol, nlev); - - int numaerosols; // number of bulk aerosols in climate/diagnostic list - int nmodes; // number of aerosol modes in climate/diagnostic list - int iaerosol; // index into bulk aerosol list - - std::string opticstype; // hygro or nonhygro - - // for cmip6 style volcanic file - int1d trop_level("trop_level", ncol); - real3d ext_cmip6_sw_inv_m("ext_cmip6_sw_inv_m", ncol, nlev, nswbands); // short wave extinction in the units of 1/m - - // compute mixing ratio to mass conversion - parallel_for(SimpleBounds<2>(ncol, nlev) , YAKL_LAMBDA (int icol, int ilev) { - mmr_to_mass(icol,ilev) = rgas * pdeldry(icol,ilev); - }); - - // initialize to conditions that would cause failure - yakl::memset(tau, -100.); - yakl::memset(tau_w, -100.); - yakl::memset(tau_w_g, -100.); - yakl::memset(tau_w_f, -100.); - - // top layer (ilev = 0) has no aerosol (ie tau = 0) - // also initialize rest of layers to accumulate od's - parallel_for(SimpleBounds<2>(ncol, nswbands) , YAKL_LAMBDA (int icol, int isw) { - tau (icol,1,isw) = 0.; - tau_w (icol,1,isw) = 0.; - tau_w_g(icol,1,isw) = 0.; - tau_w_f(icol,1,isw) = 0.; - }); - - // calculate relative humidity for table lookup into rh grid - parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) { - WaterVaporSat::qsat(temp(icol,ilev), pmid(icol,ilev), es(icol,ilev), qs(icol,ilev)); - rh(icol, ilev) = qt(icol,ilev) / qs(icol,ilev); +void AerRadProps::aer_rad_props_sw (const int& list_idx, const real& dt, const int& nnite, + const int1d& idxnite, const bool is_cmip6_volc, const real3d& tau, const real3d& tau_w, + const real3d& tau_w_g, const real3d& tau_w_f, const real2d& clear_rh) { + // radiative properties for each aerosol + real3d ta("ta", ncol, nlev, nswbands); + real3d tw("tw", ncol, nlev, nswbands); + real3d twf("twf", ncol, nlev, nswbands); + real3d twg("twg", ncol, nlev, nswbands); + + // aerosol masses + real2d aermmr("aermmr", ncol, nlev); // mass mixing ratio of aerosols + real2d mmr_to_mass("mmr_to_mass", ncol, nlev); // conversion factor for mmr to mass + real2d aermass("aermass", ncol, nlev); // mass of aerosols + + // for table lookup into rh grid + real2d es("es", ncol, nlev); // saturation vapor pressure + real2d qs("qs", ncol, nlev); // saturation specific humidity + real2d rh("rh", ncol, nlev); + real2d rhtrunc("rhtrunc", ncol, nlev); + real2d wrh("wrh", ncol, nlev); + int2d krh("krh", ncol, nlev); + + int numaerosols; // number of bulk aerosols in climate/diagnostic list + int nmodes; // number of aerosol modes in climate/diagnostic list + int iaerosol; // index into bulk aerosol list + + std::string opticstype; // hygro or nonhygro + + // for cmip6 style volcanic file + int1d trop_level("trop_level", ncol); + real3d ext_cmip6_sw_inv_m("ext_cmip6_sw_inv_m", ncol, nlev, nswbands); // short wave extinction in the units of 1/m + + // compute mixing ratio to mass conversion + parallel_for(SimpleBounds<2>(ncol, nlev) , YAKL_LAMBDA (int icol, int ilev) + { + mmr_to_mass(icol,ilev) = rgas * pdeldry(icol,ilev); + }); + + // initialize to conditions that would cause failure + yakl::memset(tau, -100.); + yakl::memset(tau_w, -100.); + yakl::memset(tau_w_g, -100.); + yakl::memset(tau_w_f, -100.); + + // top layer (ilev = 0) has no aerosol (ie tau = 0) + // also initialize rest of layers to accumulate od's + parallel_for(SimpleBounds<2>(ncol, nswbands) , YAKL_LAMBDA (int icol, int isw) + { + tau (icol,1,isw) = 0.; + tau_w (icol,1,isw) = 0.; + tau_w_g(icol,1,isw) = 0.; + tau_w_f(icol,1,isw) = 0.; + }); + + // calculate relative humidity for table lookup into rh grid + parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) + { + WaterVaporSat::qsat(temp(icol,ilev), pmid(icol,ilev), es(icol,ilev), qs(icol,ilev)); + rh(icol, ilev) = qt(icol,ilev) / qs(icol,ilev); + + rhtrunc(icol,ilev) = std::min(rh(icol,ilev),1.); + krh(icol, ilev) = std::min(std::floor(rhtrunc(icol, ilev)*nrh )+1, nrh - 1.); // index into rh mesh + wrh(icol, ilev) = rhtrunc(icol,ilev)*nrh - krh(icol, ilev); // (-) weighting on left side values + }); + + // Special treatment for CMIP6 volcanic aerosols, where extinction, ssa + // and af are directly read from the prescribed volcanic aerosol file + + // Point ext_cmip6_sw to null so that the code breaks if they are used for is_cmip6_volc=.false. case + // This is done to avoid having optional arguments in modal_aero_sw call + yakl::memset(trop_level, 10000000); + + // I was thinking whether we have to include volcanic effects on radiation? + if (is_cmip6_volc) { + // get extinction so as to supply to modal_aero_sw routine for computing EXTINCT variable + // converting it from 1/km to 1/m + + // call pbuf_get_field(pbuf, idx_ext_sw, ext_cmip6_sw) + // call outfld('extinct_sw_inp',ext_cmip6_sw(:,:,idx_sw_diag), pcols, lchnk) + parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) + { + ext_cmip6_sw_inv_m(icol, ilev, isw) = 1.0e-3*ext_cmip6_sw(icol, ilev, isw); //convert from 1/km to 1/m + }); - rhtrunc(icol,ilev) = std::min(rh(icol,ilev),1.); - krh(icol, ilev) = std::min(std::floor(rhtrunc(icol, ilev)*nrh )+1, nrh - 1.); // index into rh mesh - wrh(icol, ilev) = rhtrunc(icol,ilev)*nrh - krh(icol, ilev); // (-) weighting on left side values - }); + //Find tropopause as extinction should be applied only above tropopause + //trop_level has value for tropopause for each column + //tropopause_find(state, trop_level) + // Iterate over all of the columns to find the troppause + real1d strop("strop",1); + parallel_for(SimpleBounds<1>(ncol), YAKL_LAMBDA (int i) + { + // Search from the bottom up, looking for the first minimum. + int tlev = -1; + for (auto k = nlev-1; k > 0; --k) { + real stobie = 0.03 * temp(i,k) - std::log10(pmid(i, k)); + if (pmid(i, k) <= 4000.) break; + if (pmid(i, k) >= 55000.) continue; + if ((tlev == -1) || (stobie < strop(1))) { + tlev = k; + strop(1) = stobie; + } + } + if (tlev != -1) trop_level(i) = tlev; + }); - // Special treatment for CMIP6 volcanic aerosols, where extinction, ssa - // and af are directly read from the prescribed volcanic aerosol file - - // Point ext_cmip6_sw to null so that the code breaks if they are used for is_cmip6_volc=.false. case - // This is done to avoid having optional arguments in modal_aero_sw call - yakl::memset(trop_level, 10000000); - - // I was thinking whether we have to include volcanic effects on radiation? - if (is_cmip6_volc) { - // get extinction so as to supply to modal_aero_sw routine for computing EXTINCT variable - // converting it from 1/km to 1/m - -// call pbuf_get_field(pbuf, idx_ext_sw, ext_cmip6_sw) -// call outfld('extinct_sw_inp',ext_cmip6_sw(:,:,idx_sw_diag), pcols, lchnk) - parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) { - ext_cmip6_sw_inv_m(icol, ilev, isw) = 1.0e-3*ext_cmip6_sw(icol, ilev, isw); //convert from 1/km to 1/m - }); - - //Find tropopause as extinction should be applied only above tropopause - //trop_level has value for tropopause for each column - //tropopause_find(state, trop_level) - // Iterate over all of the columns to find the troppause - real1d strop("strop",1); - parallel_for(SimpleBounds<1>(ncol), YAKL_LAMBDA (int i) { - // Search from the bottom up, looking for the first minimum. - int tlev = -1; - for (auto k = nlev-1; k > 0; --k) { - real stobie = 0.03 * temp(i,k) - std::log10(pmid(i, k)); - if (pmid(i, k) <= 4000.) break; - if (pmid(i, k) >= 55000.) continue; - if ((tlev == -1) || (stobie < strop(1))) { - tlev = k; - strop(1) = stobie; - } + // + //Quit if tropopause is not found + if (yakl::intrinsics::any(trop_level) == -1) { + amrex::Print() << "aer_rad_props.F90: subr aer_rad_props_sw: tropopause not found\n"; } - if (tlev != -1) trop_level(i) = tlev; - }); + } + + // get number of bulk aerosols and number of modes in current list + mam_consti.get_nmodes(list_idx, nmodes); + mam_consti.get_ngas(list_idx, ngas); + mam_consti.get_naero(list_idx, numaerosols); + + // Contributions from modal aerosols. + if (nmodes > 0) { + real2d ext_cmip6_sw_2d("ext_cmip6_sw",ncol,nlev); + parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) + { + ext_cmip6_sw_2d(icol,ilev) = ext_cmip6_sw_inv_m(icol,ilev,RadConstants::idx_sw_diag); + }); - // - //Quit if tropopause is not found - if (yakl::intrinsics::any(trop_level) == -1) { - amrex::Print() << "aer_rad_props.F90: subr aer_rad_props_sw: tropopause not found\n"; - } - } - - // get number of bulk aerosols and number of modes in current list - mam_consti.get_nmodes(list_idx, nmodes); - mam_consti.get_ngas(list_idx, ngas); - mam_consti.get_naero(list_idx, numaerosols); - - // Contributions from modal aerosols. - if (nmodes > 0) { - real2d ext_cmip6_sw_2d("ext_cmip6_sw",ncol,nlev); - parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) { - ext_cmip6_sw_2d(icol,ilev) = ext_cmip6_sw_inv_m(icol,ilev,RadConstants::idx_sw_diag); - }); - - mam_aer.modal_aero_sw(list_idx, dt, nnite, idxnite, is_cmip6_volc, ext_cmip6_sw_2d, - trop_level, tau, tau_w, tau_w_g, tau_w_f, clear_rh); - } else { - yakl::memset(tau, 0.); - yakl::memset(tau_w, 0.); - yakl::memset(tau_w_g, 0.); - yakl::memset(tau_w_f, 0.); - } - - - if (is_cmip6_volc) { - //update tau, tau_w, tau_w_g, and tau_w_f with the read in values of extinction, ssa and asymmetry factors - volcanic_cmip_sw (trop_level, zi, ext_cmip6_sw_inv_m, ssa_cmip6_sw, af_cmip6_sw, - tau, tau_w, tau_w_g, tau_w_f); - } - - // Contributions from bulk aerosols. - for (auto iaerosol = 0; iaerosol < numaerosols; ++iaerosol) { - - // get bulk aerosol mass mixing ratio -// mam_consti.rad_cnst_get_aer_mmr(list_idx, iaerosol, aermmr); - parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) { - if (ilev < top_lev) { - aermass(icol,ilev) = 0.; + mam_aer.modal_aero_sw(list_idx, dt, nnite, idxnite, is_cmip6_volc, ext_cmip6_sw_2d, + trop_level, tau, tau_w, tau_w_g, tau_w_f, clear_rh); + } else { + yakl::memset(tau, 0.); + yakl::memset(tau_w, 0.); + yakl::memset(tau_w_g, 0.); + yakl::memset(tau_w_f, 0.); + } + + + if (is_cmip6_volc) { + //update tau, tau_w, tau_w_g, and tau_w_f with the read in values of extinction, ssa and asymmetry factors + volcanic_cmip_sw (trop_level, zi, ext_cmip6_sw_inv_m, ssa_cmip6_sw, af_cmip6_sw, + tau, tau_w, tau_w_g, tau_w_f); + } + + // Contributions from bulk aerosols. + for (auto iaerosol = 0; iaerosol < numaerosols; ++iaerosol) { + + // get bulk aerosol mass mixing ratio + // mam_consti.rad_cnst_get_aer_mmr(list_idx, iaerosol, aermmr); + parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) + { + if (ilev < top_lev) { + aermass(icol,ilev) = 0.; + } else { + aermass(icol,ilev) = aermmr(icol,ilev) * mmr_to_mass(icol,ilev); + } + }); + + // get optics type + mam_consti.get_aer_opticstype(list_idx, iaerosol, opticstype); + + if (opticstype == "hygro") { + // get optical properties for hygroscopic aerosols + // optical props for each aerosol hygroscopic + real2d h_ext("h_ext", ncol, nlev); + real2d h_ssa("h_ssa", ncol, nlev); + real2d h_asm("h_asm", ncol, nlev); + mam_consti.get_aer_sw_hygro_ext(list_idx, iaerosol, h_ext); + mam_consti.get_aer_sw_hygro_ssa(list_idx, iaerosol, h_ssa); + mam_consti.get_aer_sw_hygro_asm(list_idx, iaerosol, h_asm); + get_hygro_rad_props(ncol, krh, wrh, aermass, h_ext, h_ssa, h_asm, ta, tw, twg, twf); + parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) + { + tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); + tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); + tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); + tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); + }); + } else if (opticstype == "nonhygro") { + // get optical properties for non-hygroscopic aerosols + // non-hygroscopic + real1d n_ext("n_ext", ncol); + real1d n_ssa("n_ssa", ncol); + real1d n_asm("n_asm", ncol); + mam_consti.get_aer_sw_nonhygro_ext(list_idx, iaerosol, n_ext); + mam_consti.get_aer_sw_nonhygro_ssa(list_idx, iaerosol, n_ssa); + mam_consti.get_aer_sw_nonhygro_asm(list_idx, iaerosol, n_asm); + get_nonhygro_rad_props(ncol, aermass, n_ext, n_ssa, n_asm, ta, tw, twg, twf); + parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) + { + tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); + tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); + tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); + tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); + }); + } else if (opticstype == "volcanic") { + // get optical properties for volcanic aerosols + real1d n_ext("n_ext", ncol); + real1d n_scat("n_scat", ncol); + real1d n_ascat("n_ascat", ncol); + mam_consti.get_aer_sw_nonhygro_ext(list_idx, iaerosol, n_ext); + mam_consti.get_aer_sw_nonhygro_scat(list_idx, iaerosol, n_scat); + mam_consti.get_aer_sw_nonhygro_ascat(list_idx, iaerosol, n_ascat); + get_volcanic_rad_props(ncol, aermass, n_ext, n_scat, n_ascat, ta, tw, twg, twf); + parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) + { + tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); + tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); + tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); + tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); + }); + } else if (opticstype == "volcanic_radius") { + // get optical properties for volcanic aerosols + real2d r_ext("r_ext",ncol,nlev); + real2d r_scat("r_scat",ncol,nlev); + real2d r_ascat("r_ascat",ncol,nlev); + real1d r_mu("r_mu", ncol); + mam_consti.get_aer_r_sw_ext(list_idx, iaerosol, r_ext); + mam_consti.get_aer_r_sw_scat(list_idx, iaerosol, r_scat); + mam_consti.get_aer_r_sw_ascat(list_idx, iaerosol, r_ascat); + mam_consti.get_aer_mu(list_idx, iaerosol, r_mu); + get_volcanic_radius_rad_props(ncol, aermass, r_ext, r_scat, r_ascat, r_mu, ta, tw, twg, twf); + //get_volcanic_radius_rad_props(const real2d& mass, + // const real2d& r_ext, + // const real2d& r_scat, + // const real2d& r_ascat, + // const real1d& r_mu, + // real3d& tau, + // real3d& tau_w, + // real3d& tau_w_g, + // real3d& tau_w_f) + + parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) + { + tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); + tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); + tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); + tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); + }); } else { - aermass(icol,ilev) = aermmr(icol,ilev) * mmr_to_mass(icol,ilev); + amrex::Print() << "aer_rad_props_sw: unsupported opticstype\n"; } - }); - - // get optics type - mam_consti.get_aer_opticstype(list_idx, iaerosol, opticstype); - - if (opticstype == "hygro") { - // get optical properties for hygroscopic aerosols - // optical props for each aerosol hygroscopic - real2d h_ext("h_ext", ncol, nlev); - real2d h_ssa("h_ssa", ncol, nlev); - real2d h_asm("h_asm", ncol, nlev); - mam_consti.get_aer_sw_hygro_ext(list_idx, iaerosol, h_ext); - mam_consti.get_aer_sw_hygro_ssa(list_idx, iaerosol, h_ssa); - mam_consti.get_aer_sw_hygro_asm(list_idx, iaerosol, h_asm); - get_hygro_rad_props(ncol, krh, wrh, aermass, h_ext, h_ssa, h_asm, ta, tw, twg, twf); - parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) { - tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); - tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); - tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); - tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); - }); - } else if (opticstype == "nonhygro") { - // get optical properties for non-hygroscopic aerosols - // non-hygroscopic - real1d n_ext("n_ext", ncol); - real1d n_ssa("n_ssa", ncol); - real1d n_asm("n_asm", ncol); - mam_consti.get_aer_sw_nonhygro_ext(list_idx, iaerosol, n_ext); - mam_consti.get_aer_sw_nonhygro_ssa(list_idx, iaerosol, n_ssa); - mam_consti.get_aer_sw_nonhygro_asm(list_idx, iaerosol, n_asm); - get_nonhygro_rad_props(ncol, aermass, n_ext, n_ssa, n_asm, ta, tw, twg, twf); - parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) { - tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); - tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); - tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); - tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); - }); - } else if (opticstype == "volcanic") { - // get optical properties for volcanic aerosols - real1d n_ext("n_ext", ncol); - real1d n_scat("n_scat", ncol); - real1d n_ascat("n_ascat", ncol); - mam_consti.get_aer_sw_nonhygro_ext(list_idx, iaerosol, n_ext); - mam_consti.get_aer_sw_nonhygro_scat(list_idx, iaerosol, n_scat); - mam_consti.get_aer_sw_nonhygro_ascat(list_idx, iaerosol, n_ascat); - get_volcanic_rad_props(ncol, aermass, n_ext, n_scat, n_ascat, ta, tw, twg, twf); - parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) { - tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); - tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); - tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); - tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); - }); - } else if (opticstype == "volcanic_radius") { - // get optical properties for volcanic aerosols - real2d r_ext("r_ext",ncol,nlev); - real2d r_scat("r_scat",ncol,nlev); - real2d r_ascat("r_ascat",ncol,nlev); - real1d r_mu("r_mu", ncol); - mam_consti.get_aer_r_sw_ext(list_idx, iaerosol, r_ext); - mam_consti.get_aer_r_sw_scat(list_idx, iaerosol, r_scat); - mam_consti.get_aer_r_sw_ascat(list_idx, iaerosol, r_ascat); - mam_consti.get_aer_mu(list_idx, iaerosol, r_mu); - get_volcanic_radius_rad_props(ncol, aermass, r_ext, r_scat, r_ascat, r_mu, ta, tw, twg, twf); - //get_volcanic_radius_rad_props(const real2d& mass, - // const real2d& r_ext, - // const real2d& r_scat, - // const real2d& r_ascat, - // const real1d& r_mu, - // real3d& tau, - // real3d& tau_w, - // real3d& tau_w_g, - // real3d& tau_w_f) - - parallel_for(SimpleBounds<3>(ncol, nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) { - tau (icol,ilev,isw) = tau (icol,ilev,isw) + ta (icol,ilev,isw); - tau_w (icol,ilev,isw) = tau_w (icol,ilev,isw) + tw (icol,ilev,isw); - tau_w_g(icol,ilev,isw) = tau_w_g(icol,ilev,isw) + twg(icol,ilev,isw); - tau_w_f(icol,ilev,isw) = tau_w_f(icol,ilev,isw) + twf(icol,ilev,isw); - }); - } else { - amrex::Print() << "aer_rad_props_sw: unsupported opticstype\n"; - } - // diagnostic output of individual aerosol optical properties - // currently implemented for climate list only -// call aer_vis_diag_out(lchnk, ncol, nnite, idxnite, iaerosol, ta(:,:,idx_sw_diag), list_idx) - } + // diagnostic output of individual aerosol optical properties + // currently implemented for climate list only + // call aer_vis_diag_out(lchnk, ncol, nnite, idxnite, iaerosol, ta(:,:,idx_sw_diag), list_idx) + } - // diagnostic output of total aerosol optical properties - // currently implemented for climate list only -// call aer_vis_diag_out(lchnk, ncol, nnite, idxnite, 0, tau(:,:,idx_sw_diag), list_idx) + // diagnostic output of total aerosol optical properties + // currently implemented for climate list only + // call aer_vis_diag_out(lchnk, ncol, nnite, idxnite, 0, tau(:,:,idx_sw_diag), list_idx) } // Purpose: Compute aerosol transmissions needed in absorptivity/ @@ -285,257 +296,267 @@ void AerRadProps::aer_rad_props_sw(const int& list_idx, const real& dt, const in // species. If this changes, this routine will need to do something // similar to the sw with routines like get_hygro_lw_abs -void AerRadProps::aer_rad_props_lw(const bool& is_cmip6_volc, - const int& list_idx, - const real& dt, - const real2d& zi, - const real3d& odap_aer, - const real2d& clear_rh) { - int numaerosols; // number of bulk aerosols in climate/diagnostic list - int nmodes; // number of aerosol modes in climate/diagnostic list - std::string opticstype; // hygro or nonhygro - - // optical props for each aerosol - real1d lw_abs("lw_abs", ncol); - real2d lw_hygro_abs("lw_hygro", ncol, nlev); - real2d geometric_radius("geometric_radius", ncol, nlev); - - // volcanic lookup table - real2d r_lw_abs("r_lw_abs", ncol, nlev); // radius dependent mass-specific absorption coefficient - real1d r_mu("r_mu", ncol); // log(geometric_mean_radius) domain samples of r_lw_abs(:,:) - real2d mu("mu", ncol, nlev); // log(geometric_radius) - real r_mu_min, r_mu_max, wmu, mutrunc; - int nmu, kmu; - - // for table lookup into rh grid - real2d es("es", ncol, nlev); // saturation vapor pressure - real2d qs("qs", ncol, nlev); // saturation specific humidity - real2d rh("rh", ncol, nlev); - real2d rhtrunc("rhtrunc", ncol, nlev); - real2d wrh("wrh", ncol, nlev); - int2d krh("krh", ncol, nlev); - - // aerosol (vertical) mass path and extinction aerosol masses - real2d aermmr("aermmr", ncol, nlev); // mass mixing ratio of aerosols - real2d mmr_to_mass("mmr_to_mass", ncol, nlev); // conversion factor for mmr to mass - real2d aermass("aermass", ncol, nlev); // mass of aerosols - - //For cmip6 volcanic file - int1d trop_level("trop_level", ncol); - real lyr_thk; - real3d ext_cmip6_lw("ext_cmip6_lw", ncol, nlev, nlwbands); - real3d ext_cmip6_lw_inv_m("ext_cmip6_lw_inv_m",ncol, nlev, nlwbands); //long wave extinction in the units of 1/m - - const real km_inv_to_m_inv = 0.001; - - // get number of bulk aerosols and number of modes in current list - mam_consti.get_nmodes(list_idx, nmodes); - mam_consti.get_naero(list_idx, numaerosols); - - // Contributions from modal aerosols. - if (nmodes > 0) { - mam_aer.modal_aero_lw(list_idx, dt, odap_aer,clear_rh); - } else { - yakl::memset(odap_aer, 0.); - } - - // Contributions from bulk aerosols. - if (numaerosols > 0) { - - // compute mixing ratio to mass conversion - parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) { - mmr_to_mass(icol,ilev) = rgas * pdeldry(icol,ilev); - }); - - // calculate relative humidity for table lookup into rh grid - parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) { - WaterVaporSat::qsat(temp(icol,ilev), pmid(icol,ilev), es(icol,ilev), qs(icol,ilev)); - rh(icol,ilev) = qt(icol,ilev) / qs(icol,ilev); - - rhtrunc(icol, ilev) = std::min(rh(icol, ilev),1.); - krh(icol, ilev) = std::min(std::floor(rhtrunc(icol, ilev) * nrh ) + 1, nrh - 1.); // index into rh mesh - wrh(icol, ilev) = rhtrunc(icol, ilev) * nrh - krh(icol, ilev); // (-) weighting on left side values - }); - } - - yakl::memset(ext_cmip6_lw, 0.); - if(is_cmip6_volc) { - // Logic: - // Update odap_aer with the read in volcanic aerosol extinction (1/km). - // It needs to be converted to 1/m and multiplied by layer thickness first. - - // Obtain read in values for ext from the volcanic input file -// call pbuf_get_field(pbuf, idx_ext_lw, ext_cmip6_lw) -// call outfld('extinct_lw_inp',ext_cmip6_lw(:,:,idx_lw_diag), pcols, lchnk) -// ext_cmip6_lw_inv_m = ext_cmip6_lw * km_inv_to_m_inv !convert from 1/km to 1/m -// - // Above the tropopause, the read in values from the file include both the stratospheric - // and volcanic aerosols. Therefore, we need to zero out odap_aer above the tropopause - // and populate it exclusively from the read in values. - - // Find tropopause - // trop_level has value for tropopause for each column -// tropopause_find(state, trop_level) - real1d strop("strop",1); - parallel_for(SimpleBounds<1>(ncol), YAKL_LAMBDA (int i) { - // Search from the bottom up, looking for the first minimum. - int tlev = -1; - for (auto k = nlev-1; k > 0; --k) { - real stobie = 0.03 * temp(i,k) - std::log10(pmid(i, k)); - if (pmid(i, k) <= 4000.) break; - if (pmid(i, k) >= 55000.) continue; - if ((tlev == -1) || (stobie < strop(0))) { - tlev = k; - strop(0) = stobie; - } - } - if (tlev != -1) trop_level(i) = tlev; - }); - - // Quit if tropopause is not found - if (yakl::intrinsics::any(trop_level) == -1) - amrex::Print() << "aer_rad_props_lw: tropopause not found\n"; - - // If tropopause is found, update taus with 50% contributuions from the volcanic input - // file and 50% from the existing model computed values - // First handle the case of tropopause layer itself: - parallel_for(SimpleBounds<2>(ncol, nlwbands), YAKL_LAMBDA (int icol, int ilw) { - int ilev_tropp = trop_level(icol); //tropopause level - auto lyr_thk = zi(icol,ilev_tropp) - zi(icol,ilev_tropp+1); //in meters - auto ext_cmip6_inv_m = km_inv_to_m_inv * ext_cmip6_lw_inv_m(icol,ilev_tropp,ilw); - odap_aer(icol,ilev_tropp,ilw) = 0.5 * (odap_aer(icol,ilev_tropp,ilw) + lyr_thk * ext_cmip6_inv_m); - }); - - // As it will be more efficient for FORTRAN to loop over levels and then columns, the following loops - // are nested keeping that in mind - parallel_for(SimpleBounds<3>(ncol, nlev, nlwbands), YAKL_LAMBDA (int icol, int ilev, int ilw) { - int ilev_tropp = trop_level(icol); //tropopause level - if (ilev < ilev_tropp) { - auto lyr_thk = zi(icol,ilev) - zi(icol,ilev+1); - // odap_aer(icol,ilev,ilw) = lyr_thk * ext_cmip6_lw_inv_m(icol,ilev,ilw); - } - }); - } - - - // Loop over bulk aerosols in list. - for (auto iaerosol = 0; iaerosol < numaerosols; ++iaerosol) { - - // get aerosol mass mixing ratio -// mam_consti.rad_cnst_get_aer_mmr(list_idx, iaerosol, aermmr); - parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) { - if (ilev < top_lev) { - aermass(icol,ilev) = 0.; - } else { - aermass(icol,ilev) = aermmr(icol,ilev) * mmr_to_mass(icol,ilev); - } - }); - - // get optics type - mam_consti.get_aer_opticstype(list_idx, iaerosol, opticstype); - - if (opticstype == "hygroscopic") { - // get optical properties for hygroscopic aerosols - mam_consti.get_aer_lw_hygro_abs(list_idx, iaerosol, lw_hygro_abs); - parallel_for(SimpleBounds<3>(ncol, nlev, nlwbands), YAKL_LAMBDA (int icol, int ilev, int bnd_idx) { - odap_aer(icol, ilev, bnd_idx) = odap_aer(icol, ilev, bnd_idx) + aermass(icol, ilev) * - ((1 + wrh(icol,ilev)) * lw_hygro_abs(krh(icol, ilev)+1,bnd_idx) - - wrh(icol, ilev) * lw_hygro_abs(krh(icol, ilev), bnd_idx)); - }); - } else if (opticstype == "insoluble" || opticstype == "nonhygro" || opticstype == "hygro" || opticstype == "volcanic") { - // get optical properties for hygroscopic aerosols - mam_consti.get_aer_lw_abs(list_idx, iaerosol, lw_abs); - parallel_for(SimpleBounds<3>(ncol, nlev, nlwbands), YAKL_LAMBDA (int icol, int ilev, int bnd_idx) { - odap_aer(icol,ilev,bnd_idx) = odap_aer(icol,ilev,bnd_idx) + lw_abs(bnd_idx)*aermass(icol,ilev); - }); - } else if (opticstype == "volcanic_radius") { - // get optical properties for hygroscopic aerosols - mam_consti.get_aer_r_lw_abs(list_idx, iaerosol, r_lw_abs); - mam_consti.get_aer_mu(list_idx, iaerosol, r_mu); - // get microphysical properties for volcanic aerosols -// idx = pbuf_get_index('VOLC_RAD_GEOM') -// call pbuf_get_field(pbuf, idx, geometric_radius ) - - // interpolate in radius - // caution: clip the table with no warning when outside bounds - parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) { - auto nmu = r_mu.extent(0); - auto r_mu_max = r_mu(nmu); - auto r_mu_min = r_mu(1); - - if(geometric_radius(icol,ilev) > 0.) { - mu(icol,ilev) = std::log(geometric_radius(icol,ilev)); - } else { - mu(icol,ilev) = 0.; +void AerRadProps::aer_rad_props_lw (const bool& is_cmip6_volc, + const int& list_idx, + const real& dt, + const real2d& zi, + const real3d& odap_aer, + const real2d& clear_rh) { + int numaerosols; // number of bulk aerosols in climate/diagnostic list + int nmodes; // number of aerosol modes in climate/diagnostic list + std::string opticstype; // hygro or nonhygro + + // optical props for each aerosol + real1d lw_abs("lw_abs", ncol); + real2d lw_hygro_abs("lw_hygro", ncol, nlev); + real2d geometric_radius("geometric_radius", ncol, nlev); + + // volcanic lookup table + real2d r_lw_abs("r_lw_abs", ncol, nlev); // radius dependent mass-specific absorption coefficient + real1d r_mu("r_mu", ncol); // log(geometric_mean_radius) domain samples of r_lw_abs(:,:) + real2d mu("mu", ncol, nlev); // log(geometric_radius) + real r_mu_min, r_mu_max, wmu, mutrunc; + int nmu, kmu; + + // for table lookup into rh grid + real2d es("es", ncol, nlev); // saturation vapor pressure + real2d qs("qs", ncol, nlev); // saturation specific humidity + real2d rh("rh", ncol, nlev); + real2d rhtrunc("rhtrunc", ncol, nlev); + real2d wrh("wrh", ncol, nlev); + int2d krh("krh", ncol, nlev); + + // aerosol (vertical) mass path and extinction aerosol masses + real2d aermmr("aermmr", ncol, nlev); // mass mixing ratio of aerosols + real2d mmr_to_mass("mmr_to_mass", ncol, nlev); // conversion factor for mmr to mass + real2d aermass("aermass", ncol, nlev); // mass of aerosols + + //For cmip6 volcanic file + int1d trop_level("trop_level", ncol); + real lyr_thk; + real3d ext_cmip6_lw("ext_cmip6_lw", ncol, nlev, nlwbands); + real3d ext_cmip6_lw_inv_m("ext_cmip6_lw_inv_m",ncol, nlev, nlwbands); //long wave extinction in the units of 1/m + + const real km_inv_to_m_inv = 0.001; + + // get number of bulk aerosols and number of modes in current list + mam_consti.get_nmodes(list_idx, nmodes); + mam_consti.get_naero(list_idx, numaerosols); + + // Contributions from modal aerosols. + if (nmodes > 0) { + mam_aer.modal_aero_lw(list_idx, dt, odap_aer,clear_rh); + } else { + yakl::memset(odap_aer, 0.); + } + + // Contributions from bulk aerosols. + if (numaerosols > 0) { + + // compute mixing ratio to mass conversion + parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) { + mmr_to_mass(icol,ilev) = rgas * pdeldry(icol,ilev); + }); + + // calculate relative humidity for table lookup into rh grid + parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) + { + WaterVaporSat::qsat(temp(icol,ilev), pmid(icol,ilev), es(icol,ilev), qs(icol,ilev)); + rh(icol,ilev) = qt(icol,ilev) / qs(icol,ilev); + + rhtrunc(icol, ilev) = std::min(rh(icol, ilev),1.); + krh(icol, ilev) = std::min(std::floor(rhtrunc(icol, ilev) * nrh ) + 1, nrh - 1.); // index into rh mesh + wrh(icol, ilev) = rhtrunc(icol, ilev) * nrh - krh(icol, ilev); // (-) weighting on left side values + }); + } + + yakl::memset(ext_cmip6_lw, 0.); + if(is_cmip6_volc) { + // Logic: + // Update odap_aer with the read in volcanic aerosol extinction (1/km). + // It needs to be converted to 1/m and multiplied by layer thickness first. + + // Obtain read in values for ext from the volcanic input file + // call pbuf_get_field(pbuf, idx_ext_lw, ext_cmip6_lw) + // call outfld('extinct_lw_inp',ext_cmip6_lw(:,:,idx_lw_diag), pcols, lchnk) + // ext_cmip6_lw_inv_m = ext_cmip6_lw * km_inv_to_m_inv !convert from 1/km to 1/m + // + // Above the tropopause, the read in values from the file include both the stratospheric + // and volcanic aerosols. Therefore, we need to zero out odap_aer above the tropopause + // and populate it exclusively from the read in values. + + // Find tropopause + // trop_level has value for tropopause for each column + // tropopause_find(state, trop_level) + real1d strop("strop",1); + parallel_for(SimpleBounds<1>(ncol), YAKL_LAMBDA (int i) + { + // Search from the bottom up, looking for the first minimum. + int tlev = -1; + for (auto k = nlev-1; k > 0; --k) { + real stobie = 0.03 * temp(i,k) - std::log10(pmid(i, k)); + if (pmid(i, k) <= 4000.) break; + if (pmid(i, k) >= 55000.) continue; + if ((tlev == -1) || (stobie < strop(0))) { + tlev = k; + strop(0) = stobie; + } } - auto mutrunc = std::max(std::min(mu(icol,ilev),r_mu_max),r_mu_min); - auto kmu = std::max(std::min(1 + (mutrunc-r_mu_min)/(r_mu_max-r_mu_min)*(nmu-1),nmu-1.),1.); - auto wmu = std::max(std::min( (mutrunc -r_mu(kmu)) / (r_mu(kmu+1) - r_mu(kmu)) ,1.),0.); - for (auto bnd_idx = 0; bnd_idx < nlwbands; ++bnd_idx) { - odap_aer(icol,ilev,bnd_idx) = odap_aer(icol,ilev,bnd_idx) + - aermass(icol,ilev) * ((1. - wmu) * r_lw_abs(bnd_idx, kmu) + - (wmu) * r_lw_abs(bnd_idx, kmu+1)); + if (tlev != -1) trop_level(i) = tlev; + }); + + // Quit if tropopause is not found + if (yakl::intrinsics::any(trop_level) == -1) + amrex::Print() << "aer_rad_props_lw: tropopause not found\n"; + + // If tropopause is found, update taus with 50% contributuions from the volcanic input + // file and 50% from the existing model computed values + // First handle the case of tropopause layer itself: + parallel_for(SimpleBounds<2>(ncol, nlwbands), YAKL_LAMBDA (int icol, int ilw) + { + int ilev_tropp = trop_level(icol); //tropopause level + auto lyr_thk = zi(icol,ilev_tropp) - zi(icol,ilev_tropp+1); //in meters + auto ext_cmip6_inv_m = km_inv_to_m_inv * ext_cmip6_lw_inv_m(icol,ilev_tropp,ilw); + odap_aer(icol,ilev_tropp,ilw) = 0.5 * (odap_aer(icol,ilev_tropp,ilw) + lyr_thk * ext_cmip6_inv_m); + }); + + // As it will be more efficient for FORTRAN to loop over levels and then columns, the following loops + // are nested keeping that in mind + parallel_for(SimpleBounds<3>(ncol, nlev, nlwbands), YAKL_LAMBDA (int icol, int ilev, int ilw) + { + int ilev_tropp = trop_level(icol); //tropopause level + if (ilev < ilev_tropp) { + auto lyr_thk = zi(icol,ilev) - zi(icol,ilev+1); + // odap_aer(icol,ilev,ilw) = lyr_thk * ext_cmip6_lw_inv_m(icol,ilev,ilw); } }); - } - } - } - - void AerRadProps::get_hygro_rad_props(const int& ncol, - const int2d& krh, - const real2d& wrh, - const real2d& mass, - const real2d& extb, - const real2d& ssab, - const real2d& asmb, - const real3d& tau, - const real3d& tau_w, - const real3d& tau_w_g, - const real3d& tau_w_f) { - - parallel_for(SimpleBounds<3>(ncol,nlev,nswbands) , YAKL_LAMBDA (int icol, int ilev, int iswband) { - auto ext1 = (1 + wrh(icol,ilev)) * extb(krh(icol,ilev)+1,iswband) - wrh(icol,ilev) * extb(krh(icol,ilev),iswband); - auto ssa1 = (1 + wrh(icol,ilev)) * ssab(krh(icol,ilev)+1,iswband) - wrh(icol,ilev) * ssab(krh(icol,ilev),iswband); - auto asm1 = (1 + wrh(icol,ilev)) * asmb(krh(icol,ilev)+1,iswband) - wrh(icol,ilev) * asmb(krh(icol,ilev),iswband); - - tau (icol, ilev, iswband) = mass(icol, ilev) * ext1; - tau_w (icol, ilev, iswband) = mass(icol, ilev) * ext1 * ssa1; - tau_w_g(icol, ilev, iswband) = mass(icol, ilev) * ext1 * ssa1 * asm1; - tau_w_f(icol, ilev, iswband) = mass(icol, ilev) * ext1 * ssa1 * asm1 * asm1; - }); + } + + + // Loop over bulk aerosols in list. + for (auto iaerosol = 0; iaerosol < numaerosols; ++iaerosol) { + + // get aerosol mass mixing ratio + // mam_consti.rad_cnst_get_aer_mmr(list_idx, iaerosol, aermmr); + parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) + { + if (ilev < top_lev) { + aermass(icol,ilev) = 0.; + } else { + aermass(icol,ilev) = aermmr(icol,ilev) * mmr_to_mass(icol,ilev); + } + }); + + // get optics type + mam_consti.get_aer_opticstype(list_idx, iaerosol, opticstype); + + if (opticstype == "hygroscopic") { + // get optical properties for hygroscopic aerosols + mam_consti.get_aer_lw_hygro_abs(list_idx, iaerosol, lw_hygro_abs); + parallel_for(SimpleBounds<3>(ncol, nlev, nlwbands), YAKL_LAMBDA (int icol, int ilev, int bnd_idx) + { + odap_aer(icol, ilev, bnd_idx) = odap_aer(icol, ilev, bnd_idx) + aermass(icol, ilev) * + ((1 + wrh(icol,ilev)) * lw_hygro_abs(krh(icol, ilev)+1,bnd_idx) + - wrh(icol, ilev) * lw_hygro_abs(krh(icol, ilev), bnd_idx)); + }); + } else if (opticstype == "insoluble" || opticstype == "nonhygro" || opticstype == "hygro" || opticstype == "volcanic") { + // get optical properties for hygroscopic aerosols + mam_consti.get_aer_lw_abs(list_idx, iaerosol, lw_abs); + parallel_for(SimpleBounds<3>(ncol, nlev, nlwbands), YAKL_LAMBDA (int icol, int ilev, int bnd_idx) + { + odap_aer(icol,ilev,bnd_idx) = odap_aer(icol,ilev,bnd_idx) + lw_abs(bnd_idx)*aermass(icol,ilev); + }); + } else if (opticstype == "volcanic_radius") { + // get optical properties for hygroscopic aerosols + mam_consti.get_aer_r_lw_abs(list_idx, iaerosol, r_lw_abs); + mam_consti.get_aer_mu(list_idx, iaerosol, r_mu); + // get microphysical properties for volcanic aerosols + // idx = pbuf_get_index('VOLC_RAD_GEOM') + // call pbuf_get_field(pbuf, idx, geometric_radius ) + + // interpolate in radius + // caution: clip the table with no warning when outside bounds + parallel_for(SimpleBounds<2>(ncol, nlev), YAKL_LAMBDA (int icol, int ilev) + { + auto nmu = r_mu.extent(0); + auto r_mu_max = r_mu(nmu); + auto r_mu_min = r_mu(1); + + if(geometric_radius(icol,ilev) > 0.) { + mu(icol,ilev) = std::log(geometric_radius(icol,ilev)); + } else { + mu(icol,ilev) = 0.; + } + auto mutrunc = std::max(std::min(mu(icol,ilev),r_mu_max),r_mu_min); + auto kmu = std::max(std::min(1 + (mutrunc-r_mu_min)/(r_mu_max-r_mu_min)*(nmu-1),nmu-1.),1.); + auto wmu = std::max(std::min( (mutrunc -r_mu(kmu)) / (r_mu(kmu+1) - r_mu(kmu)) ,1.),0.); + for (auto bnd_idx = 0; bnd_idx < nlwbands; ++bnd_idx) { + odap_aer(icol,ilev,bnd_idx) = odap_aer(icol,ilev,bnd_idx) + + aermass(icol,ilev) * ((1. - wmu) * r_lw_abs(bnd_idx, kmu) + + (wmu) * r_lw_abs(bnd_idx, kmu+1)); + } + }); + } + } +} + + void AerRadProps::get_hygro_rad_props (const int& ncol, + const int2d& krh, + const real2d& wrh, + const real2d& mass, + const real2d& extb, + const real2d& ssab, + const real2d& asmb, + const real3d& tau, + const real3d& tau_w, + const real3d& tau_w_g, + const real3d& tau_w_f) { + + parallel_for(SimpleBounds<3>(ncol,nlev,nswbands) , YAKL_LAMBDA (int icol, int ilev, int iswband) + { + auto ext1 = (1 + wrh(icol,ilev)) * extb(krh(icol,ilev)+1,iswband) - wrh(icol,ilev) * extb(krh(icol,ilev),iswband); + auto ssa1 = (1 + wrh(icol,ilev)) * ssab(krh(icol,ilev)+1,iswband) - wrh(icol,ilev) * ssab(krh(icol,ilev),iswband); + auto asm1 = (1 + wrh(icol,ilev)) * asmb(krh(icol,ilev)+1,iswband) - wrh(icol,ilev) * asmb(krh(icol,ilev),iswband); + + tau (icol, ilev, iswband) = mass(icol, ilev) * ext1; + tau_w (icol, ilev, iswband) = mass(icol, ilev) * ext1 * ssa1; + tau_w_g(icol, ilev, iswband) = mass(icol, ilev) * ext1 * ssa1 * asm1; + tau_w_f(icol, ilev, iswband) = mass(icol, ilev) * ext1 * ssa1 * asm1 * asm1; + }); } -void AerRadProps::get_nonhygro_rad_props(const int& ncol, - const real2d& mass, - const real1d& extb, - const real1d& ssab, - const real1d& asmb, - const real3d& tau, - const real3d& tau_w, - const real3d& tau_w_g, - const real3d& tau_w_f) { - - parallel_for(SimpleBounds<3>(ncol,nlev,nswbands) , YAKL_LAMBDA (int icol, int ilev, int iswband) { - auto ext1 = extb(iswband); - auto ssa1 = ssab(iswband); - auto asm1 = asmb(iswband); - tau (icol,ilev,iswband) = mass(icol,ilev) * ext1; - tau_w (icol,ilev,iswband) = mass(icol,ilev) * ext1 * ssa1; - tau_w_g(icol,ilev,iswband) = mass(icol,ilev) * ext1 * ssa1 * asm1; - tau_w_f(icol,ilev,iswband) = mass(icol,ilev) * ext1 * ssa1 * asm1 * asm1; +void AerRadProps::get_nonhygro_rad_props (const int& ncol, + const real2d& mass, + const real1d& extb, + const real1d& ssab, + const real1d& asmb, + const real3d& tau, + const real3d& tau_w, + const real3d& tau_w_g, + const real3d& tau_w_f) { + + parallel_for(SimpleBounds<3>(ncol,nlev,nswbands) , YAKL_LAMBDA (int icol, int ilev, int iswband) + { + auto ext1 = extb(iswband); + auto ssa1 = ssab(iswband); + auto asm1 = asmb(iswband); + tau (icol,ilev,iswband) = mass(icol,ilev) * ext1; + tau_w (icol,ilev,iswband) = mass(icol,ilev) * ext1 * ssa1; + tau_w_g(icol,ilev,iswband) = mass(icol,ilev) * ext1 * ssa1 * asm1; + tau_w_f(icol,ilev,iswband) = mass(icol,ilev) * ext1 * ssa1 * asm1 * asm1; }); } - void AerRadProps::get_volcanic_radius_rad_props(const int& ncol, - const real2d& mass, - const real2d& r_ext, - const real2d& r_scat, - const real2d& r_ascat, - const real1d& r_mu, - const real3d& tau, - const real3d& tau_w, - const real3d& tau_w_g, - const real3d& tau_w_f) { + void AerRadProps::get_volcanic_radius_rad_props (const int& ncol, + const real2d& mass, + const real2d& r_ext, + const real2d& r_scat, + const real2d& r_ascat, + const real1d& r_mu, + const real3d& tau, + const real3d& tau_w, + const real3d& tau_w_g, + const real3d& tau_w_f) { yakl::memset(tau, 0.); yakl::memset(tau_w, 0.); yakl::memset(tau_w_g, 0.); @@ -557,25 +578,26 @@ void AerRadProps::get_nonhygro_rad_props(const int& ncol, real1d ascat("ascat", nswbands); real2d mu("mu", ncol, nlev); - parallel_for(SimpleBounds<3>(ncol,nlev,nswbands), YAKL_LAMBDA (int icol, int ilev, int iswband) { + parallel_for(SimpleBounds<3>(ncol,nlev,nswbands), YAKL_LAMBDA (int icol, int ilev, int iswband) + { if(geometric_radius(icol,ilev) > 0.) - mu(icol,ilev) = std::log(geometric_radius(icol,ilev)); + mu(icol,ilev) = std::log(geometric_radius(icol,ilev)); else - mu(icol,ilev) = 0.; + mu(icol,ilev) = 0.; auto mutrunc = std::max(std::min(mu(icol,ilev),r_mu_max),r_mu_min); auto kmu = std::max(std::min(1 + (mutrunc-r_mu_min)/(r_mu_max-r_mu_min)*(nmu-1),nmu-1.),1.); auto wmu = std::max(std::min((mutrunc -r_mu(kmu)) / (r_mu(kmu+1) - r_mu(kmu)),1.),0.); ext(iswband) = ((1. - wmu) * r_ext(iswband, kmu ) + - (wmu) * r_ext(iswband, kmu+1)); + (wmu) * r_ext(iswband, kmu+1)); scat(iswband) = ((1. - wmu) * r_scat(iswband, kmu ) + - (wmu) * r_scat(iswband, kmu+1)); + (wmu) * r_scat(iswband, kmu+1)); ascat(iswband) = ((1. - wmu) * r_ascat(iswband, kmu ) + - (wmu) * r_ascat(iswband, kmu+1)); + (wmu) * r_ascat(iswband, kmu+1)); real g = 0; if (scat(iswband) > 0.) - g = ascat(iswband)/scat(iswband); + g = ascat(iswband)/scat(iswband); tau (icol,ilev,iswband) = mass(icol,ilev) * ext(iswband); tau_w (icol,ilev,iswband) = mass(icol,ilev) * scat(iswband); @@ -609,60 +631,63 @@ void AerRadProps::get_nonhygro_rad_props(const int& ncol, ext_ssa_asym("ext_ssa_asym",nswbands); // First handle the case of tropopause layer itself: - parallel_for(SimpleBounds<2>(ncol,nswbands), YAKL_LAMBDA (int icol, int isw) { - auto ilev_tropp = trop_level(icol); //tropopause level - auto lyr_thk = zi(icol,ilev_tropp) - zi(icol,ilev_tropp+1); - - ext_unitless(isw) = lyr_thk * ext_cmip6_sw_inv_m(icol,ilev_tropp,isw); - asym_unitless(isw) = af_cmip6_sw (icol,ilev_tropp,isw); - ext_ssa(isw) = ext_unitless(isw) * ssa_cmip6_sw(icol,ilev_tropp,isw); - ext_ssa_asym(isw) = ext_ssa(isw) * asym_unitless(isw); - - tau (icol,ilev_tropp,isw) = 0.5 * ( tau (icol,ilev_tropp,isw) + ext_unitless(isw) ); - tau_w (icol,ilev_tropp,isw) = 0.5 * ( tau_w (icol,ilev_tropp,isw) + ext_ssa(isw)); - tau_w_g(icol,ilev_tropp,isw) = 0.5 * ( tau_w_g(icol,ilev_tropp,isw) + ext_ssa_asym(isw)); - tau_w_f(icol,ilev_tropp,isw) = 0.5 * ( tau_w_f(icol,ilev_tropp,isw) + ext_ssa_asym(isw) * asym_unitless(isw)); + parallel_for(SimpleBounds<2>(ncol,nswbands), YAKL_LAMBDA (int icol, int isw) + { + auto ilev_tropp = trop_level(icol); //tropopause level + auto lyr_thk = zi(icol,ilev_tropp) - zi(icol,ilev_tropp+1); + + ext_unitless(isw) = lyr_thk * ext_cmip6_sw_inv_m(icol,ilev_tropp,isw); + asym_unitless(isw) = af_cmip6_sw (icol,ilev_tropp,isw); + ext_ssa(isw) = ext_unitless(isw) * ssa_cmip6_sw(icol,ilev_tropp,isw); + ext_ssa_asym(isw) = ext_ssa(isw) * asym_unitless(isw); + + tau (icol,ilev_tropp,isw) = 0.5 * ( tau (icol,ilev_tropp,isw) + ext_unitless(isw) ); + tau_w (icol,ilev_tropp,isw) = 0.5 * ( tau_w (icol,ilev_tropp,isw) + ext_ssa(isw)); + tau_w_g(icol,ilev_tropp,isw) = 0.5 * ( tau_w_g(icol,ilev_tropp,isw) + ext_ssa_asym(isw)); + tau_w_f(icol,ilev_tropp,isw) = 0.5 * ( tau_w_f(icol,ilev_tropp,isw) + ext_ssa_asym(isw) * asym_unitless(isw)); }); // As it will be more efficient for FORTRAN to loop over levels and then columns, the following loops // are nested keeping that in mind - parallel_for(SimpleBounds<3>(ncol,nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) { - auto ilev_tropp = trop_level(icol); //tropopause level - - if (ilev < ilev_tropp) { //BALLI: see if this is right! - auto lyr_thk = zi(icol,ilev) - zi(icol,ilev+1); - - ext_unitless(isw) = lyr_thk * ext_cmip6_sw_inv_m(icol,ilev,isw); - asym_unitless(isw) = af_cmip6_sw(icol,ilev,isw); - ext_ssa(isw) = ext_unitless(isw) * ssa_cmip6_sw(icol,ilev,isw); - ext_ssa_asym(isw) = ext_ssa(isw) * asym_unitless(isw); - - tau (icol,ilev,isw) = ext_unitless(isw); - tau_w (icol,ilev,isw) = ext_ssa(isw); - tau_w_g(icol,ilev,isw) = ext_ssa_asym(isw); - tau_w_f(icol,ilev,isw) = ext_ssa_asym(isw) * asym_unitless(isw); - } + parallel_for(SimpleBounds<3>(ncol,nlev, nswbands), YAKL_LAMBDA (int icol, int ilev, int isw) + { + auto ilev_tropp = trop_level(icol); //tropopause level + + if (ilev < ilev_tropp) { //BALLI: see if this is right! + auto lyr_thk = zi(icol,ilev) - zi(icol,ilev+1); + + ext_unitless(isw) = lyr_thk * ext_cmip6_sw_inv_m(icol,ilev,isw); + asym_unitless(isw) = af_cmip6_sw(icol,ilev,isw); + ext_ssa(isw) = ext_unitless(isw) * ssa_cmip6_sw(icol,ilev,isw); + ext_ssa_asym(isw) = ext_ssa(isw) * asym_unitless(isw); + + tau (icol,ilev,isw) = ext_unitless(isw); + tau_w (icol,ilev,isw) = ext_ssa(isw); + tau_w_g(icol,ilev,isw) = ext_ssa_asym(isw); + tau_w_f(icol,ilev,isw) = ext_ssa_asym(isw) * asym_unitless(isw); + } }); } -void AerRadProps::get_volcanic_rad_props(const int& ncol, - const real2d& mass, - const real1d& ext, - const real1d& scat, - const real1d& ascat, - const real3d& tau, - const real3d& tau_w, - const real3d& tau_w_g, - const real3d& tau_w_f) { +void AerRadProps::get_volcanic_rad_props (const int& ncol, + const real2d& mass, + const real1d& ext, + const real1d& scat, + const real1d& ascat, + const real3d& tau, + const real3d& tau_w, + const real3d& tau_w_g, + const real3d& tau_w_f) { int nswbands; - parallel_for(SimpleBounds<3>(nswbands, ncol,nlev), YAKL_LAMBDA (int iswband, int icol, int ilev) { - real g = 0; - if (scat(iswband) > 0.) - g = ascat(iswband)/scat(iswband); - - tau (icol, ilev, iswband) = mass(icol, ilev) * ext(iswband); - tau_w (icol, ilev, iswband) = mass(icol, ilev) * scat(iswband); - tau_w_g(icol, ilev, iswband) = mass(icol, ilev) * ascat(iswband); - tau_w_f(icol, ilev, iswband) = mass(icol, ilev) * g * ascat(iswband); - }); + parallel_for(SimpleBounds<3>(nswbands, ncol,nlev), YAKL_LAMBDA (int iswband, int icol, int ilev) + { + real g = 0; + if (scat(iswband) > 0.) + g = ascat(iswband)/scat(iswband); + + tau (icol, ilev, iswband) = mass(icol, ilev) * ext(iswband); + tau_w (icol, ilev, iswband) = mass(icol, ilev) * scat(iswband); + tau_w_g(icol, ilev, iswband) = mass(icol, ilev) * ascat(iswband); + tau_w_f(icol, ilev, iswband) = mass(icol, ilev) * g * ascat(iswband); + }); } diff --git a/Source/TimeIntegration/ERF_ApplySpongeZoneBCs.cpp b/Source/TimeIntegration/ERF_ApplySpongeZoneBCs.cpp index cb9825950..69152d0a8 100644 --- a/Source/TimeIntegration/ERF_ApplySpongeZoneBCs.cpp +++ b/Source/TimeIntegration/ERF_ApplySpongeZoneBCs.cpp @@ -18,7 +18,7 @@ using namespace amrex; void -ApplySpongeZoneBCs( +ApplySpongeZoneBCs ( const SpongeChoice& spongeChoice, const amrex::Geometry geom, const Box& tbx, @@ -34,274 +34,278 @@ ApplySpongeZoneBCs( const Array4& cell_rhs, const Array4& cell_data) { - // Domain cell size and real bounds - auto dx = geom.CellSizeArray(); - auto ProbHiArr = geom.ProbHiArray(); - auto ProbLoArr = geom.ProbLoArray(); - - const amrex::Real sponge_strength = spongeChoice.sponge_strength; - const int use_xlo_sponge_damping = spongeChoice.use_xlo_sponge_damping; - const int use_xhi_sponge_damping = spongeChoice.use_xhi_sponge_damping; - const int use_ylo_sponge_damping = spongeChoice.use_ylo_sponge_damping; - const int use_yhi_sponge_damping = spongeChoice.use_yhi_sponge_damping; - const int use_zlo_sponge_damping = spongeChoice.use_zlo_sponge_damping; - const int use_zhi_sponge_damping = spongeChoice.use_zhi_sponge_damping; - - const amrex::Real xlo_sponge_end = spongeChoice.xlo_sponge_end; - const amrex::Real xhi_sponge_start = spongeChoice.xhi_sponge_start; - const amrex::Real ylo_sponge_end = spongeChoice.ylo_sponge_end; - const amrex::Real yhi_sponge_start = spongeChoice.yhi_sponge_start; - const amrex::Real zlo_sponge_end = spongeChoice.zlo_sponge_end; - const amrex::Real zhi_sponge_start = spongeChoice.zhi_sponge_start; - - const amrex::Real sponge_density = spongeChoice.sponge_density; - const amrex::Real sponge_x_velocity = spongeChoice.sponge_x_velocity; - const amrex::Real sponge_y_velocity = spongeChoice.sponge_y_velocity; - const amrex::Real sponge_z_velocity = spongeChoice.sponge_z_velocity; - - // Domain valid box - const amrex::Box& domain = geom.Domain(); - int domlo_x = domain.smallEnd(0); - int domhi_x = domain.bigEnd(0) + 1; - int domlo_y = domain.smallEnd(1); - int domhi_y = domain.bigEnd(1) + 1; - int domlo_z = domain.smallEnd(2); - int domhi_z = domain.bigEnd(2) + 1; - - if(use_xlo_sponge_damping)AMREX_ALWAYS_ASSERT(xlo_sponge_end > ProbLoArr[0]); - if(use_xhi_sponge_damping)AMREX_ALWAYS_ASSERT(xhi_sponge_start < ProbHiArr[0]); - if(use_ylo_sponge_damping)AMREX_ALWAYS_ASSERT(ylo_sponge_end > ProbLoArr[1]); - if(use_yhi_sponge_damping)AMREX_ALWAYS_ASSERT(yhi_sponge_start < ProbHiArr[1]); - if(use_zlo_sponge_damping)AMREX_ALWAYS_ASSERT(zlo_sponge_end > ProbLoArr[2]); - if(use_zhi_sponge_damping)AMREX_ALWAYS_ASSERT(zhi_sponge_start < ProbHiArr[2]); - -ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { - int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); - int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); - int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); - - Real x = (ii+0.5) * dx[0]; - Real y = (jj+0.5) * dx[1]; - Real z = (kk+0.5) * dx[2]; - - // x left sponge - if(use_xlo_sponge_damping){ - if (x < xlo_sponge_end) { - Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); - cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + // Domain cell size and real bounds + auto dx = geom.CellSizeArray(); + auto ProbHiArr = geom.ProbHiArray(); + auto ProbLoArr = geom.ProbLoArray(); + + const amrex::Real sponge_strength = spongeChoice.sponge_strength; + const int use_xlo_sponge_damping = spongeChoice.use_xlo_sponge_damping; + const int use_xhi_sponge_damping = spongeChoice.use_xhi_sponge_damping; + const int use_ylo_sponge_damping = spongeChoice.use_ylo_sponge_damping; + const int use_yhi_sponge_damping = spongeChoice.use_yhi_sponge_damping; + const int use_zlo_sponge_damping = spongeChoice.use_zlo_sponge_damping; + const int use_zhi_sponge_damping = spongeChoice.use_zhi_sponge_damping; + + const amrex::Real xlo_sponge_end = spongeChoice.xlo_sponge_end; + const amrex::Real xhi_sponge_start = spongeChoice.xhi_sponge_start; + const amrex::Real ylo_sponge_end = spongeChoice.ylo_sponge_end; + const amrex::Real yhi_sponge_start = spongeChoice.yhi_sponge_start; + const amrex::Real zlo_sponge_end = spongeChoice.zlo_sponge_end; + const amrex::Real zhi_sponge_start = spongeChoice.zhi_sponge_start; + + const amrex::Real sponge_density = spongeChoice.sponge_density; + const amrex::Real sponge_x_velocity = spongeChoice.sponge_x_velocity; + const amrex::Real sponge_y_velocity = spongeChoice.sponge_y_velocity; + const amrex::Real sponge_z_velocity = spongeChoice.sponge_z_velocity; + + // Domain valid box + const amrex::Box& domain = geom.Domain(); + int domlo_x = domain.smallEnd(0); + int domhi_x = domain.bigEnd(0) + 1; + int domlo_y = domain.smallEnd(1); + int domhi_y = domain.bigEnd(1) + 1; + int domlo_z = domain.smallEnd(2); + int domhi_z = domain.bigEnd(2) + 1; + + if(use_xlo_sponge_damping)AMREX_ALWAYS_ASSERT(xlo_sponge_end > ProbLoArr[0]); + if(use_xhi_sponge_damping)AMREX_ALWAYS_ASSERT(xhi_sponge_start < ProbHiArr[0]); + if(use_ylo_sponge_damping)AMREX_ALWAYS_ASSERT(ylo_sponge_end > ProbLoArr[1]); + if(use_yhi_sponge_damping)AMREX_ALWAYS_ASSERT(yhi_sponge_start < ProbHiArr[1]); + if(use_zlo_sponge_damping)AMREX_ALWAYS_ASSERT(zlo_sponge_end > ProbLoArr[2]); + if(use_zhi_sponge_damping)AMREX_ALWAYS_ASSERT(zhi_sponge_start < ProbHiArr[2]); + + ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept + { + int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); + int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); + int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); + + Real x = (ii+0.5) * dx[0]; + Real y = (jj+0.5) * dx[1]; + Real z = (kk+0.5) * dx[2]; + + // x left sponge + if(use_xlo_sponge_damping){ + if (x < xlo_sponge_end) { + Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); + cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + } } - } - // x right sponge - if(use_xhi_sponge_damping){ - if (x > xhi_sponge_start) { - Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); - cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + // x right sponge + if(use_xhi_sponge_damping){ + if (x > xhi_sponge_start) { + Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); + cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + } } - } - // y left sponge - if(use_ylo_sponge_damping){ - if (y < ylo_sponge_end) { - Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); - cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + // y left sponge + if(use_ylo_sponge_damping){ + if (y < ylo_sponge_end) { + Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); + cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + } } - } - // x right sponge - if(use_yhi_sponge_damping){ - if (y > yhi_sponge_start) { - Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); - cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + // x right sponge + if(use_yhi_sponge_damping){ + if (y > yhi_sponge_start) { + Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); + cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + } } - } - // x left sponge - if(use_zlo_sponge_damping){ - if (z < zlo_sponge_end) { - Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); - cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + // x left sponge + if(use_zlo_sponge_damping){ + if (z < zlo_sponge_end) { + Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); + cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + } } - } - // x right sponge - if(use_zhi_sponge_damping){ - if (z > zhi_sponge_start) { - Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); - cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + // x right sponge + if(use_zhi_sponge_damping){ + if (z > zhi_sponge_start) { + Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); + cell_rhs(i, j, k, 0) -= sponge_strength * xi * xi * (cell_data(i, j, k, 0) - sponge_density); + } } - } - }); - -amrex::ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) { - int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); - int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); - int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); - - Real x = ii * dx[0]; - Real y = (jj+0.5) * dx[1]; - Real z = (kk+0.5) * dx[2]; - - // x lo sponge - if(use_xlo_sponge_damping){ - if (x < xlo_sponge_end) { - Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); - rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + }); + + amrex::ParallelFor(tbx, [=] AMREX_GPU_DEVICE(int i, int j, int k) + { + int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); + int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); + int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); + + Real x = ii * dx[0]; + Real y = (jj+0.5) * dx[1]; + Real z = (kk+0.5) * dx[2]; + + // x lo sponge + if(use_xlo_sponge_damping){ + if (x < xlo_sponge_end) { + Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); + rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + } } - } - // x hi sponge - if(use_xhi_sponge_damping){ - if (x > xhi_sponge_start) { - Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); - rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + // x hi sponge + if(use_xhi_sponge_damping){ + if (x > xhi_sponge_start) { + Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); + rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + } } - } - // y lo sponge - if(use_ylo_sponge_damping){ - if (y < ylo_sponge_end) { - Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); - rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + // y lo sponge + if(use_ylo_sponge_damping){ + if (y < ylo_sponge_end) { + Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); + rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + } } - } - // x right sponge - if(use_yhi_sponge_damping){ - if (y > yhi_sponge_start) { - Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); - rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + // x right sponge + if(use_yhi_sponge_damping){ + if (y > yhi_sponge_start) { + Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); + rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + } } - } - // z lo sponge - if(use_zlo_sponge_damping){ - if (z < zlo_sponge_end) { - Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); - rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + // z lo sponge + if(use_zlo_sponge_damping){ + if (z < zlo_sponge_end) { + Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); + rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + } } - } - // z hi sponge - if(use_zhi_sponge_damping){ - if (z > zhi_sponge_start) { - Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); - rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + // z hi sponge + if(use_zhi_sponge_damping){ + if (z > zhi_sponge_start) { + Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); + rho_u_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_u(i, j, k) - sponge_density*sponge_x_velocity); + } } - } - }); + }); - amrex::ParallelFor(tby, [=] AMREX_GPU_DEVICE(int i, int j, int k) { - int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); - int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); - int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); + amrex::ParallelFor(tby, [=] AMREX_GPU_DEVICE(int i, int j, int k) + { + int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); + int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); + int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); - Real x = (ii+0.5) * dx[0]; - Real y = jj * dx[1]; - Real z = (kk+0.5) * dx[2]; + Real x = (ii+0.5) * dx[0]; + Real y = jj * dx[1]; + Real z = (kk+0.5) * dx[2]; - // x lo sponge - if(use_xlo_sponge_damping){ - if (x < xlo_sponge_end) { - Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); - rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + // x lo sponge + if(use_xlo_sponge_damping){ + if (x < xlo_sponge_end) { + Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); + rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + } } - } - // x hi sponge - if(use_xhi_sponge_damping){ - if (x > xhi_sponge_start) { - Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); - rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + // x hi sponge + if(use_xhi_sponge_damping){ + if (x > xhi_sponge_start) { + Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); + rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + } } - } - // y lo sponge - if(use_ylo_sponge_damping){ - if (y < ylo_sponge_end) { - Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); - rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + // y lo sponge + if(use_ylo_sponge_damping){ + if (y < ylo_sponge_end) { + Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); + rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + } } - } - // x right sponge - if(use_yhi_sponge_damping){ - if (y > yhi_sponge_start) { - Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); - rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + // x right sponge + if(use_yhi_sponge_damping){ + if (y > yhi_sponge_start) { + Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); + rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + } } - } - // z lo sponge - if(use_zlo_sponge_damping){ - if (z < zlo_sponge_end) { - Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); - rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + // z lo sponge + if(use_zlo_sponge_damping){ + if (z < zlo_sponge_end) { + Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); + rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + } } - } - // z hi sponge - if(use_zhi_sponge_damping){ - if (z > zhi_sponge_start) { - Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); - rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + // z hi sponge + if(use_zhi_sponge_damping){ + if (z > zhi_sponge_start) { + Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); + rho_v_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_v(i, j, k) - sponge_density*sponge_y_velocity); + } } - } - }); + }); - amrex::ParallelFor(tbz, [=] AMREX_GPU_DEVICE(int i, int j, int k) { - int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); - int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); - int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); + amrex::ParallelFor(tbz, [=] AMREX_GPU_DEVICE(int i, int j, int k) + { + int ii = amrex::min(amrex::max(i, domlo_x), domhi_x); + int jj = amrex::min(amrex::max(j, domlo_y), domhi_y); + int kk = amrex::min(amrex::max(k, domlo_z), domhi_z); - Real x = (ii+0.5) * dx[0]; - Real y = (jj+0.5) * dx[1]; - Real z = kk * dx[2]; + Real x = (ii+0.5) * dx[0]; + Real y = (jj+0.5) * dx[1]; + Real z = kk * dx[2]; - // x left sponge - if(use_xlo_sponge_damping){ - if (x < xlo_sponge_end) { - Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); - rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + // x left sponge + if(use_xlo_sponge_damping){ + if (x < xlo_sponge_end) { + Real xi = (xlo_sponge_end - x) / (xlo_sponge_end - ProbLoArr[0]); + rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + } } - } - // x right sponge - if(use_xhi_sponge_damping){ - if (x > xhi_sponge_start) { - Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); - rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + // x right sponge + if(use_xhi_sponge_damping){ + if (x > xhi_sponge_start) { + Real xi = (x - xhi_sponge_start) / (ProbHiArr[0] - xhi_sponge_start); + rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + } } - } - // y lo sponge - if(use_ylo_sponge_damping){ - if (y < ylo_sponge_end) { - Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); - rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + // y lo sponge + if(use_ylo_sponge_damping){ + if (y < ylo_sponge_end) { + Real xi = (ylo_sponge_end - y) / (ylo_sponge_end - ProbLoArr[1]); + rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + } } - } - // x right sponge - if(use_yhi_sponge_damping){ - if (y > yhi_sponge_start) { - Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); - rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + // x right sponge + if(use_yhi_sponge_damping){ + if (y > yhi_sponge_start) { + Real xi = (y - yhi_sponge_start) / (ProbHiArr[1] - yhi_sponge_start); + rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + } } - } - // z lo sponge - if(use_zlo_sponge_damping){ - if (z < zlo_sponge_end) { - Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); - rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + // z lo sponge + if(use_zlo_sponge_damping){ + if (z < zlo_sponge_end) { + Real xi = (zlo_sponge_end - z) / (zlo_sponge_end - ProbLoArr[2]); + rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + } } - } - // z top sponge - if(use_zhi_sponge_damping){ - if (z > zhi_sponge_start) { - Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); - rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + // z top sponge + if(use_zhi_sponge_damping){ + if (z > zhi_sponge_start) { + Real xi = (z - zhi_sponge_start) / (ProbHiArr[2] - zhi_sponge_start); + rho_w_rhs(i, j, k) -= sponge_strength * xi * xi * (rho_w(i, j, k) - sponge_density*sponge_z_velocity); + } } - } - }); + }); } diff --git a/Source/TimeIntegration/ERF_ComputeTimestep.cpp b/Source/TimeIntegration/ERF_ComputeTimestep.cpp index 3b56aedd5..711620e58 100644 --- a/Source/TimeIntegration/ERF_ComputeTimestep.cpp +++ b/Source/TimeIntegration/ERF_ComputeTimestep.cpp @@ -46,28 +46,28 @@ ERF::ComputeDt () * @param[out] dt_fast_ratio ratio of slow to fast time step */ Real -ERF::estTimeStep(int level, long& dt_fast_ratio) const +ERF::estTimeStep (int level, long& dt_fast_ratio) const { - BL_PROFILE("ERF::estTimeStep()"); + BL_PROFILE("ERF::estTimeStep()"); - amrex::Real estdt_comp = 1.e20; - amrex::Real estdt_lowM = 1.e20; + amrex::Real estdt_comp = 1.e20; + amrex::Real estdt_lowM = 1.e20; - auto const dxinv = geom[level].InvCellSizeArray(); - auto const dzinv = 1.0 / dz_min; + auto const dxinv = geom[level].InvCellSizeArray(); + auto const dzinv = 1.0 / dz_min; - MultiFab const& S_new = vars_new[level][Vars::cons]; + MultiFab const& S_new = vars_new[level][Vars::cons]; - MultiFab ccvel(grids[level],dmap[level],3,0); + MultiFab ccvel(grids[level],dmap[level],3,0); - average_face_to_cellcenter(ccvel,0, - Array{&vars_new[level][Vars::xvel], - &vars_new[level][Vars::yvel], - &vars_new[level][Vars::zvel]}); + average_face_to_cellcenter(ccvel,0, + Array{&vars_new[level][Vars::xvel], + &vars_new[level][Vars::yvel], + &vars_new[level][Vars::zvel]}); - int l_no_substepping = solverChoice.no_substepping; + int l_no_substepping = solverChoice.no_substepping; - Real estdt_comp_inv = amrex::ReduceMax(S_new, ccvel, 0, + Real estdt_comp_inv = amrex::ReduceMax(S_new, ccvel, 0, [=] AMREX_GPU_HOST_DEVICE (Box const& b, Array4 const& s, Array4 const& u) -> Real @@ -101,10 +101,10 @@ ERF::estTimeStep(int level, long& dt_fast_ratio) const return new_comp_dt; }); - amrex::ParallelDescriptor::ReduceRealMax(estdt_comp_inv); - estdt_comp = cfl / estdt_comp_inv;; + amrex::ParallelDescriptor::ReduceRealMax(estdt_comp_inv); + estdt_comp = cfl / estdt_comp_inv; - Real estdt_lowM_inv = amrex::ReduceMax(ccvel, 0, + Real estdt_lowM_inv = amrex::ReduceMax(ccvel, 0, [=] AMREX_GPU_HOST_DEVICE (Box const& b, Array4 const& u) -> Real { @@ -118,65 +118,65 @@ ERF::estTimeStep(int level, long& dt_fast_ratio) const return new_lm_dt; }); - amrex::ParallelDescriptor::ReduceRealMax(estdt_lowM_inv); - if (estdt_lowM_inv > 0.0_rt) - estdt_lowM = cfl / estdt_lowM_inv;; - - if (verbose) { - if (fixed_dt <= 0.0) { - amrex::Print() << "Using cfl = " << cfl << std::endl; - amrex::Print() << "Fast dt at level " << level << ": " << estdt_comp << std::endl; - if (estdt_lowM_inv > 0.0_rt) { - amrex::Print() << "Slow dt at level " << level << ": " << estdt_lowM << std::endl; - } else { - amrex::Print() << "Slow dt at level " << level << ": undefined " << std::endl; - } - } - - if (fixed_dt > 0.0) { - amrex::Print() << "Based on cfl of 1.0 " << std::endl; - amrex::Print() << "Fast dt at level " << level << " would be: " << estdt_comp/cfl << std::endl; - if (estdt_lowM_inv > 0.0_rt) { - amrex::Print() << "Slow dt at level " << level << " would be: " << estdt_lowM/cfl << std::endl; - } else { - amrex::Print() << "Slow dt at level " << level << " would be undefined " << std::endl; - } - amrex::Print() << "Fixed dt at level " << level << " is: " << fixed_dt << std::endl; - if (fixed_fast_dt > 0.0) { - amrex::Print() << "Fixed fast dt at level " << level << " is: " << fixed_fast_dt << std::endl; - } - } - } - - if (fixed_dt > 0. && fixed_fast_dt > 0.) { - dt_fast_ratio = static_cast( fixed_dt / fixed_fast_dt ); - } else if (fixed_dt > 0.) { - dt_fast_ratio = static_cast( std::ceil((fixed_dt/estdt_comp)) ); - } else { - dt_fast_ratio = (estdt_lowM_inv > 0.0) ? static_cast( std::ceil((estdt_lowM/estdt_comp)) ) : 1; - } - - // Force time step ratio to be an even value - if (solverChoice.force_stage1_single_substep) { - if ( dt_fast_ratio%2 != 0) dt_fast_ratio += 1; - } else { - if ( dt_fast_ratio%6 != 0) { - amrex::Print() << "mri_dt_ratio = " << dt_fast_ratio - << " not divisible by 6 for N/3 substeps in stage 1" << std::endl; - dt_fast_ratio = static_cast(std::ceil(dt_fast_ratio/6.0) * 6); - } - } - - if (verbose) - amrex::Print() << "smallest even ratio is: " << dt_fast_ratio << std::endl; - - if (fixed_dt > 0.0) { - return fixed_dt; - } else { - if (l_no_substepping) { - return estdt_comp; - } else { - return estdt_lowM; - } - } + amrex::ParallelDescriptor::ReduceRealMax(estdt_lowM_inv); + if (estdt_lowM_inv > 0.0_rt) + estdt_lowM = cfl / estdt_lowM_inv; + + if (verbose) { + if (fixed_dt <= 0.0) { + amrex::Print() << "Using cfl = " << cfl << std::endl; + amrex::Print() << "Fast dt at level " << level << ": " << estdt_comp << std::endl; + if (estdt_lowM_inv > 0.0_rt) { + amrex::Print() << "Slow dt at level " << level << ": " << estdt_lowM << std::endl; + } else { + amrex::Print() << "Slow dt at level " << level << ": undefined " << std::endl; + } + } + + if (fixed_dt > 0.0) { + amrex::Print() << "Based on cfl of 1.0 " << std::endl; + amrex::Print() << "Fast dt at level " << level << " would be: " << estdt_comp/cfl << std::endl; + if (estdt_lowM_inv > 0.0_rt) { + amrex::Print() << "Slow dt at level " << level << " would be: " << estdt_lowM/cfl << std::endl; + } else { + amrex::Print() << "Slow dt at level " << level << " would be undefined " << std::endl; + } + amrex::Print() << "Fixed dt at level " << level << " is: " << fixed_dt << std::endl; + if (fixed_fast_dt > 0.0) { + amrex::Print() << "Fixed fast dt at level " << level << " is: " << fixed_fast_dt << std::endl; + } + } + } + + if (fixed_dt > 0. && fixed_fast_dt > 0.) { + dt_fast_ratio = static_cast( fixed_dt / fixed_fast_dt ); + } else if (fixed_dt > 0.) { + dt_fast_ratio = static_cast( std::ceil((fixed_dt/estdt_comp)) ); + } else { + dt_fast_ratio = (estdt_lowM_inv > 0.0) ? static_cast( std::ceil((estdt_lowM/estdt_comp)) ) : 1; + } + + // Force time step ratio to be an even value + if (solverChoice.force_stage1_single_substep) { + if ( dt_fast_ratio%2 != 0) dt_fast_ratio += 1; + } else { + if ( dt_fast_ratio%6 != 0) { + amrex::Print() << "mri_dt_ratio = " << dt_fast_ratio + << " not divisible by 6 for N/3 substeps in stage 1" << std::endl; + dt_fast_ratio = static_cast(std::ceil(dt_fast_ratio/6.0) * 6); + } + } + + if (verbose) + amrex::Print() << "smallest even ratio is: " << dt_fast_ratio << std::endl; + + if (fixed_dt > 0.0) { + return fixed_dt; + } else { + if (l_no_substepping) { + return estdt_comp; + } else { + return estdt_lowM; + } + } } diff --git a/Source/TimeIntegration/ERF_advance_radiation.cpp b/Source/TimeIntegration/ERF_advance_radiation.cpp index 826c0d934..305a7f30f 100644 --- a/Source/TimeIntegration/ERF_advance_radiation.cpp +++ b/Source/TimeIntegration/ERF_advance_radiation.cpp @@ -8,23 +8,23 @@ void ERF::advance_radiation (int lev, MultiFab& cons, const Real& dt_advance) { - bool do_sw_rad {true}; - bool do_lw_rad {true}; - bool do_aero_rad {true}; - bool do_snow_opt {true}; - bool is_cmip6_volcano {true}; + bool do_sw_rad {true}; + bool do_lw_rad {true}; + bool do_aero_rad {true}; + bool do_snow_opt {true}; + bool is_cmip6_volcano {true}; - // TODO: Only passing qv from the qmoist vector!!! - rad.initialize(cons, *(qmoist[lev][0]), - grids[lev], - Geom(lev), - dt_advance, - do_sw_rad, - do_lw_rad, - do_aero_rad, - do_snow_opt, - is_cmip6_volcano); - rad.run(); - rad.on_complete(); + // TODO: Only passing qv from the qmoist vector!!! + rad.initialize(cons, *(qmoist[lev][0]), + grids[lev], + Geom(lev), + dt_advance, + do_sw_rad, + do_lw_rad, + do_aero_rad, + do_snow_opt, + is_cmip6_volcano); + rad.run(); + rad.on_complete(); } #endif diff --git a/Source/Utils/DirectionSelector.H b/Source/Utils/DirectionSelector.H index 42ecd57dc..a18fce6c1 100644 --- a/Source/Utils/DirectionSelector.H +++ b/Source/Utils/DirectionSelector.H @@ -12,25 +12,25 @@ template struct DirectionSelector { - [[nodiscard]] int getIndx(int i, int j, int k) const; + [[nodiscard]] int getIndx (int i, int j, int k) const; }; template <> struct DirectionSelector<0> { - [[nodiscard]] AMREX_GPU_HOST_DEVICE static int getIndx(int i, int, int) { return i; } + [[nodiscard]] AMREX_GPU_HOST_DEVICE static int getIndx (int i, int, int) { return i; } }; template <> struct DirectionSelector<1> { - [[nodiscard]] AMREX_GPU_HOST_DEVICE static int getIndx(int, int j, int) { return j; } + [[nodiscard]] AMREX_GPU_HOST_DEVICE static int getIndx (int, int j, int) { return j; } }; template <> struct DirectionSelector<2> { - [[nodiscard]] AMREX_GPU_HOST_DEVICE static int getIndx(int, int, int k) { return k; } + [[nodiscard]] AMREX_GPU_HOST_DEVICE static int getIndx (int, int, int k) { return k; } }; using XDir = DirectionSelector<0>; @@ -48,7 +48,7 @@ using ZDir = DirectionSelector<2>; template AMREX_GPU_HOST_DEVICE amrex::Box -PerpendicularBox(const amrex::Box& bx, const amrex::IntVect& iv) +PerpendicularBox (const amrex::Box& bx, const amrex::IntVect& iv) { amrex::IntVect plane_lo, plane_hi; @@ -80,7 +80,7 @@ PerpendicularBox(const amrex::Box& bx, const amrex::IntVect& iv) template AMREX_GPU_HOST_DEVICE amrex::Box -ParallelBox(const amrex::Box& bx, const amrex::IntVect& iv) +ParallelBox (const amrex::Box& bx, const amrex::IntVect& iv) { amrex::IntVect line_lo, line_hi; diff --git a/Source/Utils/ERF_PoissonSolve.cpp b/Source/Utils/ERF_PoissonSolve.cpp index 505a3aa00..1ff2c7507 100644 --- a/Source/Utils/ERF_PoissonSolve.cpp +++ b/Source/Utils/ERF_PoissonSolve.cpp @@ -36,7 +36,7 @@ ERF::get_projection_bc (Orientation::Side side) const noexcept /** * Project the single-level velocity field to enforce incompressibility */ -void ERF::project_velocities(Vector& vmf) +void ERF::project_velocities (Vector& vmf) { Vector> tmpmf(1); for (auto& mf : vmf) { @@ -49,7 +49,7 @@ void ERF::project_velocities(Vector& vmf) * Project the multi-level velocity field to enforce incompressibility */ void -ERF::project_velocities(Vector>& vars) +ERF::project_velocities (Vector>& vars) { BL_PROFILE("ERF::project_velocities()"); diff --git a/Source/Utils/Microphysics_Utils.H b/Source/Utils/Microphysics_Utils.H index 36807aeb2..278f45323 100644 --- a/Source/Utils/Microphysics_Utils.H +++ b/Source/Utils/Microphysics_Utils.H @@ -11,186 +11,185 @@ #include AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real erf_gammafff(amrex::Real x){ - return std::exp(lgamma(x)); +amrex::Real erf_gammafff (amrex::Real x){ + return std::exp(lgamma(x)); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real erf_esati(amrex::Real t) { - amrex::Real const a0 = 6.11147274; - amrex::Real const a1 = 0.503160820; - amrex::Real const a2 = 0.188439774e-1; - amrex::Real const a3 = 0.420895665e-3; - amrex::Real const a4 = 0.615021634e-5; - amrex::Real const a5 = 0.602588177e-7; - amrex::Real const a6 = 0.385852041e-9; - amrex::Real const a7 = 0.146898966e-11; - amrex::Real const a8 = 0.252751365e-14; - - amrex::Real dtt = t-273.16; - amrex::Real esati; - if(dtt > -80.0) { - esati = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); - } - else { - esati = 0.01*std::exp(9.550426 - 5723.265/t + 3.53068*std::log(t) - 0.00728332*t); - } - return esati; +amrex::Real erf_esati (amrex::Real t) { + amrex::Real const a0 = 6.11147274; + amrex::Real const a1 = 0.503160820; + amrex::Real const a2 = 0.188439774e-1; + amrex::Real const a3 = 0.420895665e-3; + amrex::Real const a4 = 0.615021634e-5; + amrex::Real const a5 = 0.602588177e-7; + amrex::Real const a6 = 0.385852041e-9; + amrex::Real const a7 = 0.146898966e-11; + amrex::Real const a8 = 0.252751365e-14; + + amrex::Real dtt = t-273.16; + amrex::Real esati; + if(dtt > -80.0) { + esati = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); + } + else { + esati = 0.01*std::exp(9.550426 - 5723.265/t + 3.53068*std::log(t) - 0.00728332*t); + } + return esati; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real erf_esatw(amrex::Real t) { - amrex::Real const a0 = 6.105851; - amrex::Real const a1 = 0.4440316; - amrex::Real const a2 = 0.1430341e-1; - amrex::Real const a3 = 0.2641412e-3; - amrex::Real const a4 = 0.2995057e-5; - amrex::Real const a5 = 0.2031998e-7; - amrex::Real const a6 = 0.6936113e-10; - amrex::Real const a7 = 0.2564861e-13; - amrex::Real const a8 = -0.3704404e-15; - - amrex::Real dtt = t-273.16; - - amrex::Real esatw; - if(dtt > -80.0) { - esatw = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); - } - else { - esatw = 2.0*0.01*std::exp(9.550426 - 5723.265/t + 3.53068*std::log(t) - 0.00728332*t); - } - return esatw; +amrex::Real erf_esatw (amrex::Real t) { + amrex::Real const a0 = 6.105851; + amrex::Real const a1 = 0.4440316; + amrex::Real const a2 = 0.1430341e-1; + amrex::Real const a3 = 0.2641412e-3; + amrex::Real const a4 = 0.2995057e-5; + amrex::Real const a5 = 0.2031998e-7; + amrex::Real const a6 = 0.6936113e-10; + amrex::Real const a7 = 0.2564861e-13; + amrex::Real const a8 = -0.3704404e-15; + + amrex::Real dtt = t-273.16; + + amrex::Real esatw; + if(dtt > -80.0) { + esatw = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); + } + else { + esatw = 2.0*0.01*std::exp(9.550426 - 5723.265/t + 3.53068*std::log(t) - 0.00728332*t); + } + return esatw; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real erf_dtesati(amrex::Real t) { - amrex::Real const a0 = 0.503223089; - amrex::Real const a1 = 0.377174432e-1; - amrex::Real const a2 = 0.126710138e-2; - amrex::Real const a3 = 0.249065913e-4; - amrex::Real const a4 = 0.312668753e-6; - amrex::Real const a5 = 0.255653718e-8; - amrex::Real const a6 = 0.132073448e-10; - amrex::Real const a7 = 0.390204672e-13; - amrex::Real const a8 = 0.497275778e-16; - - amrex::Real dtt = t-273.16; - amrex::Real dtesati; - if(dtt > -80.0) { - dtesati = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); - } - else { - dtesati= erf_esati(t+1.0)-erf_esati(t); - } - - return dtesati; -} +amrex::Real erf_dtesati (amrex::Real t) { + amrex::Real const a0 = 0.503223089; + amrex::Real const a1 = 0.377174432e-1; + amrex::Real const a2 = 0.126710138e-2; + amrex::Real const a3 = 0.249065913e-4; + amrex::Real const a4 = 0.312668753e-6; + amrex::Real const a5 = 0.255653718e-8; + amrex::Real const a6 = 0.132073448e-10; + amrex::Real const a7 = 0.390204672e-13; + amrex::Real const a8 = 0.497275778e-16; + + amrex::Real dtt = t-273.16; + amrex::Real dtesati; + if(dtt > -80.0) { + dtesati = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); + } + else { + dtesati= erf_esati(t+1.0)-erf_esati(t); + } -AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real erf_dtesatw(amrex::Real t) { - amrex::Real const a0 = 0.443956472; - amrex::Real const a1 = 0.285976452e-1; - amrex::Real const a2 = 0.794747212e-3; - amrex::Real const a3 = 0.121167162e-4; - amrex::Real const a4 = 0.103167413e-6; - amrex::Real const a5 = 0.385208005e-9; - amrex::Real const a6 = -0.604119582e-12; - amrex::Real const a7 = -0.792933209e-14; - amrex::Real const a8 = -0.599634321e-17; - - amrex::Real dtt = t-273.16; - amrex::Real dtesatw; - if(dtt > -80.0) { - dtesatw = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); - } - else { - dtesatw = erf_esatw(t+1.0)-erf_esatw(t); - } - return dtesatw; + return dtesati; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void erf_qsati(amrex::Real t, amrex::Real p, amrex::Real &qsati) { - amrex::Real esati; - esati = erf_esati(t); - qsati = 0.622*esati/std::max(esati,p-esati); +amrex::Real erf_dtesatw (amrex::Real t) { + amrex::Real const a0 = 0.443956472; + amrex::Real const a1 = 0.285976452e-1; + amrex::Real const a2 = 0.794747212e-3; + amrex::Real const a3 = 0.121167162e-4; + amrex::Real const a4 = 0.103167413e-6; + amrex::Real const a5 = 0.385208005e-9; + amrex::Real const a6 = -0.604119582e-12; + amrex::Real const a7 = -0.792933209e-14; + amrex::Real const a8 = -0.599634321e-17; + + amrex::Real dtt = t-273.16; + amrex::Real dtesatw; + if(dtt > -80.0) { + dtesatw = a0 + dtt*(a1+dtt*(a2+dtt*(a3+dtt*(a4+dtt*(a5+dtt*(a6+dtt*(a7+a8*dtt))))))); + } + else { + dtesatw = erf_esatw(t+1.0)-erf_esatw(t); + } + return dtesatw; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void erf_qsatw(amrex::Real t, amrex::Real p, amrex::Real &qsatw) { - amrex::Real esatw; - esatw = erf_esatw(t); - qsatw = 0.622*esatw/std::max(esatw,p-esatw); +void erf_qsati (amrex::Real t, amrex::Real p, amrex::Real &qsati) { + amrex::Real esati; + esati = erf_esati(t); + qsati = 0.622*esati/std::max(esati,p-esati); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void erf_dtqsati(amrex::Real t, amrex::Real p, amrex::Real &dtqsati) { - dtqsati = 0.622*erf_dtesati(t)/p; +void erf_qsatw (amrex::Real t, amrex::Real p, amrex::Real &qsatw) { + amrex::Real esatw; + esatw = erf_esatw(t); + qsatw = 0.622*esatw/std::max(esatw,p-esatw); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void erf_dtqsatw(amrex::Real t, amrex::Real p, amrex::Real &dtqsatw) { - dtqsatw = 0.622*erf_dtesatw(t)/p; +void erf_dtqsati (amrex::Real t, amrex::Real p, amrex::Real &dtqsati) { + dtqsati = 0.622*erf_dtesati(t)/p; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -void z0_est(amrex::Real z, amrex::Real bflx, amrex::Real wnd, amrex::Real ustar, amrex::Real &z0) { - amrex::Real vonk = 0.4; - amrex::Real eps = 1.0e-10; - amrex::Real am = 4.8; - amrex::Real bm = 19.3; - amrex::Real c1 = 3.14159/2.0 - 3.0*log(2.0); - amrex::Real rlmo = -bflx*vonk/(ustar*ustar*ustar+eps); - amrex::Real zeta = std::min(1.0,z*rlmo); - amrex::Real x; - amrex::Real psi1; - if(zeta >= 0.0) { - psi1 = -am*zeta; - } - else { - x = std::sqrt(sqrt(1.0-bm*zeta)); - psi1 = 2.0*std::log(1.0+x) + std::log(1.0+x*x) -2.0*std::atan(x) + c1; - } - amrex::Real lnz = std::max(0.0, vonk*wnd/(ustar+eps) +psi1); - z0 = z*std::exp(-lnz); +void erf_dtqsatw (amrex::Real t, amrex::Real p, amrex::Real &dtqsatw) { + dtqsatw = 0.622*erf_dtesatw(t)/p; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real term_vel_qp(int /*i*/, int /*j*/, int /*k*/, amrex::Real qploc, amrex::Real vrain, amrex::Real vsnow, - amrex::Real vgrau, amrex::Real rho, amrex::Real tabs) { - amrex::Real term_vel = 0.0; - if(qploc > qp_threshold) { - amrex::Real omp = std::max(0.0,std::min(1.0,(tabs-tprmin)*a_pr)); - if(omp == 1.0) { - term_vel = vrain*std::pow(rho*qploc,crain); - } - else if(omp == 0.0) { - amrex::Real omg = std::max(0.0,std::min(1.0,(tabs-tgrmin)*a_gr)); - amrex::Real qgg = omg*qploc; - amrex::Real qss = qploc-qgg; - term_vel = (omg*vgrau*std::pow(rho*qgg,cgrau) + (1.0-omg)*vsnow*std::pow(rho*qss,csnow)); +void z0_est (amrex::Real z, amrex::Real bflx, amrex::Real wnd, amrex::Real ustar, amrex::Real &z0) { + amrex::Real vonk = 0.4; + amrex::Real eps = 1.0e-10; + amrex::Real am = 4.8; + amrex::Real bm = 19.3; + amrex::Real c1 = 3.14159/2.0 - 3.0*log(2.0); + amrex::Real rlmo = -bflx*vonk/(ustar*ustar*ustar+eps); + amrex::Real zeta = std::min(1.0,z*rlmo); + amrex::Real x; + amrex::Real psi1; + if(zeta >= 0.0) { + psi1 = -am*zeta; } else { - amrex::Real omg = std::max(0.0,std::min(1.0,(tabs-tgrmin)*a_gr)); - amrex::Real qrr = omp*qploc; - amrex::Real qss = qploc-qrr; - amrex::Real qgg = omg*qss; - qss = qss-qgg; - term_vel = (omp*vrain*std::pow(rho*qrr,crain) + (1.0-omp)*(omg*vgrau*std::pow(rho*qgg,cgrau) + (1.0-omg)*vsnow*std::pow(rho*qss,csnow))); + x = std::sqrt(sqrt(1.0-bm*zeta)); + psi1 = 2.0*std::log(1.0+x) + std::log(1.0+x*x) -2.0*std::atan(x) + c1; } - } - return term_vel; + amrex::Real lnz = std::max(0.0, vonk*wnd/(ustar+eps) +psi1); + z0 = z*std::exp(-lnz); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real pp(amrex::Real y) { - return std::max(0.0,y); +amrex::Real term_vel_qp (int /*i*/, int /*j*/, int /*k*/, amrex::Real qploc, amrex::Real vrain, amrex::Real vsnow, + amrex::Real vgrau, amrex::Real rho, amrex::Real tabs) { + amrex::Real term_vel = 0.0; + if(qploc > qp_threshold) { + amrex::Real omp = std::max(0.0,std::min(1.0,(tabs-tprmin)*a_pr)); + if(omp == 1.0) { + term_vel = vrain*std::pow(rho*qploc,crain); + } + else if(omp == 0.0) { + amrex::Real omg = std::max(0.0,std::min(1.0,(tabs-tgrmin)*a_gr)); + amrex::Real qgg = omg*qploc; + amrex::Real qss = qploc-qgg; + term_vel = (omg*vgrau*std::pow(rho*qgg,cgrau) + (1.0-omg)*vsnow*std::pow(rho*qss,csnow)); + } + else { + amrex::Real omg = std::max(0.0,std::min(1.0,(tabs-tgrmin)*a_gr)); + amrex::Real qrr = omp*qploc; + amrex::Real qss = qploc-qrr; + amrex::Real qgg = omg*qss; + qss = qss-qgg; + term_vel = (omp*vrain*std::pow(rho*qrr,crain) + (1.0-omp)*(omg*vgrau*std::pow(rho*qgg,cgrau) + (1.0-omg)*vsnow*std::pow(rho*qss,csnow))); + } + } + return term_vel; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE -amrex::Real pn(amrex::Real y) { - return -std::min(0.0,y); +amrex::Real pp (amrex::Real y) { + return std::max(0.0,y); } +AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE +amrex::Real pn (amrex::Real y) { + return -std::min(0.0,y); +} #endif diff --git a/Source/Utils/MomentumToVelocity.cpp b/Source/Utils/MomentumToVelocity.cpp index f2922acaf..5bc30360c 100644 --- a/Source/Utils/MomentumToVelocity.cpp +++ b/Source/Utils/MomentumToVelocity.cpp @@ -20,9 +20,9 @@ using namespace amrex; */ void -MomentumToVelocity(MultiFab& xvel, MultiFab& yvel, MultiFab& zvel, - const MultiFab& density, - const MultiFab& xmom_in, const MultiFab& ymom_in, const MultiFab& zmom_in) +MomentumToVelocity (MultiFab& xvel, MultiFab& yvel, MultiFab& zvel, + const MultiFab& density, + const MultiFab& xmom_in, const MultiFab& ymom_in, const MultiFab& zmom_in) { BL_PROFILE_VAR("MomentumToVelocity()",MomentumToVelocity); diff --git a/Source/Utils/PlaneAverage.H b/Source/Utils/PlaneAverage.H index a18b765f4..2db136e6c 100644 --- a/Source/Utils/PlaneAverage.H +++ b/Source/Utils/PlaneAverage.H @@ -13,45 +13,45 @@ class PlaneAverage { public: AMREX_FORCE_INLINE - explicit PlaneAverage(const amrex::MultiFab* field_in, - amrex::Geometry geom_in, - int axis_in); - PlaneAverage() = delete; - ~PlaneAverage() = default; + explicit PlaneAverage (const amrex::MultiFab* field_in, + amrex::Geometry geom_in, + int axis_in); + PlaneAverage () = delete; + ~PlaneAverage () = default; AMREX_FORCE_INLINE void operator()(); /** evaluate line average at specific location for any average component */ [[nodiscard]] AMREX_FORCE_INLINE - amrex::Real line_average_interpolated(amrex::Real x, int comp) const; + amrex::Real line_average_interpolated (amrex::Real x, int comp) const; /** change precision of text file output */ - void set_precision(int p) { m_precision = p; } + void set_precision (int p) { m_precision = p; } - [[nodiscard]] amrex::Real dx() const { return m_dx; } - [[nodiscard]] amrex::Real xlo() const { return m_xlo; } + [[nodiscard]] amrex::Real dx () const { return m_dx; } + [[nodiscard]] amrex::Real xlo () const { return m_xlo; } - [[nodiscard]] int axis() const { return m_axis; } - [[nodiscard]] int level() const { return m_level; } - [[nodiscard]] int ncomp() const { return m_ncomp; } - [[nodiscard]] int ncell_plane() const { return m_ncell_plane; } - [[nodiscard]] int ncell_line() const { return m_ncell_line; } + [[nodiscard]] int axis () const { return m_axis; } + [[nodiscard]] int level () const { return m_level; } + [[nodiscard]] int ncomp () const { return m_ncomp; } + [[nodiscard]] int ncell_plane () const { return m_ncell_plane; } + [[nodiscard]] int ncell_line () const { return m_ncell_line; } - [[nodiscard]] const amrex::Vector& line_average() const + [[nodiscard]] const amrex::Vector& line_average () const { return m_line_average; } AMREX_FORCE_INLINE - void line_average(int comp, amrex::Gpu::HostVector& l_vec); + void line_average (int comp, amrex::Gpu::HostVector& l_vec); - [[nodiscard]] const amrex::Vector& line_centroids() const + [[nodiscard]] const amrex::Vector& line_centroids () const { return m_line_xcentroid; } - [[nodiscard]] const amrex::MultiFab& field() const { return *m_field; } + [[nodiscard]] const amrex::MultiFab& field () const { return *m_field; } protected: int m_ncomp; /** number of average components */ @@ -78,7 +78,7 @@ public: /** fill line storage with averages */ template AMREX_FORCE_INLINE - void compute_averages(const IndexSelector& idxOp, const amrex::MultiFab& mfab); + void compute_averages (const IndexSelector& idxOp, const amrex::MultiFab& mfab); }; @@ -113,7 +113,7 @@ PlaneAverage::PlaneAverage (const amrex::MultiFab* field_in, } amrex::Real -PlaneAverage::line_average_interpolated(amrex::Real x, int comp) const +PlaneAverage::line_average_interpolated (amrex::Real x, int comp) const { AMREX_ALWAYS_ASSERT(comp >= 0 && comp < m_ncomp); @@ -138,7 +138,7 @@ PlaneAverage::line_average_interpolated(amrex::Real x, int comp) const } void -PlaneAverage::line_average(int comp, amrex::Gpu::HostVector& l_vec) +PlaneAverage::line_average (int comp, amrex::Gpu::HostVector& l_vec) { AMREX_ALWAYS_ASSERT(comp >= 0 && comp < m_ncomp); @@ -168,7 +168,7 @@ PlaneAverage::operator()() template void -PlaneAverage::compute_averages(const IndexSelector& idxOp, const amrex::MultiFab& mfab) +PlaneAverage::compute_averages (const IndexSelector& idxOp, const amrex::MultiFab& mfab) { const amrex::Real denom = 1.0 / (amrex::Real)m_ncell_plane; amrex::AsyncArray lavg(m_line_average.data(), m_line_average.size()); @@ -184,8 +184,9 @@ PlaneAverage::compute_averages(const IndexSelector& idxOp, const amrex::MultiFab amrex::Box pbx = PerpendicularBox(bx, amrex::IntVect{0, 0, 0}); ParallelFor(amrex::Gpu::KernelInfo().setReduction(true), pbx, [=] - AMREX_GPU_DEVICE( int p_i, int p_j, int p_k, - amrex::Gpu::Handler const& handler) noexcept { + AMREX_GPU_DEVICE( int p_i, int p_j, int p_k, + amrex::Gpu::Handler const& handler) noexcept + { // Loop over the direction perpendicular to the plane. // This reduces the atomic pressure on the destination arrays. @@ -197,12 +198,12 @@ PlaneAverage::compute_averages(const IndexSelector& idxOp, const amrex::MultiFab int ind = idxOp.getIndx(i, j, k); for (int n = 0; n < ncomp; ++n) { amrex::Gpu::deviceReduceSum(&line_avg[ncomp * ind + n], - fab_arr(i, j, k, n) * denom, handler); + fab_arr(i, j, k, n) * denom, handler); } - } - } - } - }); + } + } + } + }); } lavg.copyToHost(m_line_average.data(), m_line_average.size()); diff --git a/Source/Utils/Sat_methods.H b/Source/Utils/Sat_methods.H index 25aff0f29..6e6fdb786 100644 --- a/Source/Utils/Sat_methods.H +++ b/Source/Utils/Sat_methods.H @@ -35,158 +35,158 @@ #include "ERF_Constants.H" class SatMethods { - public: +public: // Get saturation specific humidity given pressure and SVP. // Specific humidity is limited to range 0-1. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real wv_sat_svp_to_qsat(const amrex::Real& es, const amrex::Real& p) { - // If pressure is less than SVP, set qs to maximum of 1. - if ( (p - es) <= 0. ) - return 1.0; - else - return epsilo*es / (p - omeps*es); + static amrex::Real wv_sat_svp_to_qsat (const amrex::Real& es, const amrex::Real& p) { + // If pressure is less than SVP, set qs to maximum of 1. + if ( (p - es) <= 0. ) + return 1.0; + else + return epsilo*es / (p - omeps*es); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void wv_sat_qsat_water(const amrex::Real& t, const amrex::Real& p, - amrex::Real es, amrex::Real qs, const int idx = 1) { - // Purpose: - // Calculate SVP over water at a given temperature, and then - // calculate and return saturation specific humidity. + static void wv_sat_qsat_water (const amrex::Real& t, const amrex::Real& p, + amrex::Real es, amrex::Real qs, const int idx = 1) { + // Purpose: + // Calculate SVP over water at a given temperature, and then + // calculate and return saturation specific humidity. - es = wv_sat_svp_water(t, idx); + es = wv_sat_svp_water(t, idx); - qs = wv_sat_svp_to_qsat(es, p); + qs = wv_sat_svp_to_qsat(es, p); - // Ensures returned es is consistent with limiters on qs. - es = std::min(es, p); + // Ensures returned es is consistent with limiters on qs. + es = std::min(es, p); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void wv_sat_qsat_ice(const amrex::Real& t, const amrex::Real& p, - amrex::Real es, amrex::Real qs, const int idx = 1) { - // Purpose: - // Calculate SVP over ice at a given temperature, and then - // calculate and return saturation specific humidity. + static void wv_sat_qsat_ice (const amrex::Real& t, const amrex::Real& p, + amrex::Real es, amrex::Real qs, const int idx = 1) { + // Purpose: + // Calculate SVP over ice at a given temperature, and then + // calculate and return saturation specific humidity. - es = wv_sat_svp_ice(t, idx); + es = wv_sat_svp_ice(t, idx); - qs = wv_sat_svp_to_qsat(es, p); + qs = wv_sat_svp_to_qsat(es, p); - // Ensures returned es is consistent with limiters on qs. - es = std::min(es, p); + // Ensures returned es is consistent with limiters on qs. + es = std::min(es, p); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void wv_sat_qsat_trans(const amrex::Real& t, const amrex::Real& p, - amrex::Real es, amrex::Real qs, const int idx = 1) { - // Purpose: - // Calculate SVP over ice at a given temperature, and then - // calculate and return saturation specific humidity. + static void wv_sat_qsat_trans (const amrex::Real& t, const amrex::Real& p, + amrex::Real es, amrex::Real qs, const int idx = 1) { + // Purpose: + // Calculate SVP over ice at a given temperature, and then + // calculate and return saturation specific humidity. - es = wv_sat_svp_trans(t, idx); + es = wv_sat_svp_trans(t, idx); - qs = wv_sat_svp_to_qsat(es, p); + qs = wv_sat_svp_to_qsat(es, p); - // Ensures returned es is consistent with limiters on qs. - es = std::min(es, p); + // Ensures returned es is consistent with limiters on qs. + es = std::min(es, p); } // SVP INTERFACE FUNCTIONS AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real wv_sat_svp_water(const amrex::Real& t, const int idx = 1) { - amrex::Real es; - switch(idx) - { - case GoffGratch: - es = GoffGratch_svp_water(t); break; - case MurphyKoop: - es = MurphyKoop_svp_water(t); break; - case OldGoffGratch: - es = OldGoffGratch_svp_water(t); break; - case Bolton: - es = Bolton_svp_water(t); break; - } - return es; + static amrex::Real wv_sat_svp_water (const amrex::Real& t, const int idx = 1) { + amrex::Real es; + switch(idx) + { + case GoffGratch: + es = GoffGratch_svp_water(t); break; + case MurphyKoop: + es = MurphyKoop_svp_water(t); break; + case OldGoffGratch: + es = OldGoffGratch_svp_water(t); break; + case Bolton: + es = Bolton_svp_water(t); break; + } + return es; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real wv_sat_svp_ice(const amrex::Real& t, const int idx = 1) { - amrex::Real es; - switch(idx) - { - case GoffGratch: - es = GoffGratch_svp_ice(t); break; - case MurphyKoop: - es = MurphyKoop_svp_ice(t); break; - case OldGoffGratch: - es = OldGoffGratch_svp_ice(t); break; - case Bolton: - es = Bolton_svp_water(t); break; - } - return es; + static amrex::Real wv_sat_svp_ice (const amrex::Real& t, const int idx = 1) { + amrex::Real es; + switch(idx) + { + case GoffGratch: + es = GoffGratch_svp_ice(t); break; + case MurphyKoop: + es = MurphyKoop_svp_ice(t); break; + case OldGoffGratch: + es = OldGoffGratch_svp_ice(t); break; + case Bolton: + es = Bolton_svp_water(t); break; + } + return es; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real wv_sat_svp_trans(const amrex::Real& t, const int idx = 1) { - amrex::Real esice; // Saturation vapor pressure over ice - amrex::Real weight; // Intermediate scratch variable for es transition - amrex::Real es; - - // Water - if (t >= (tmelt - ttrice)) - es = wv_sat_svp_water(t,idx); - else - es = 0.0; - - // Ice - if (t < tmelt) { - esice = wv_sat_svp_ice(t,idx); - if ( (tmelt - t) > ttrice ) - weight = 1.0; - else - weight = (tmelt - t)/ttrice; - - es = weight*esice + (1.0 - weight)*es; - } - return es; + static amrex::Real wv_sat_svp_trans (const amrex::Real& t, const int idx = 1) { + amrex::Real esice; // Saturation vapor pressure over ice + amrex::Real weight; // Intermediate scratch variable for es transition + amrex::Real es; + + // Water + if (t >= (tmelt - ttrice)) + es = wv_sat_svp_water(t,idx); + else + es = 0.0; + + // Ice + if (t < tmelt) { + esice = wv_sat_svp_ice(t,idx); + if ( (tmelt - t) > ttrice ) + weight = 1.0; + else + weight = (tmelt - t)/ttrice; + + es = weight*esice + (1.0 - weight)*es; + } + return es; } // Goff & Gratch (1946) AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real GoffGratch_svp_water(const amrex::Real& t) { - // uncertain below -70 C - return pow(10., (-7.90298*(tboil/t-1.)+ - 5.02808*std::log10(tboil/t)- - 1.3816e-7*(pow(10., (11.344*(1.-t/tboil)))-1.)+ - 8.1328e-3*(pow(10., (-3.49149*(tboil/t-1.)))-1.)+ - std::log10(1013.246)))*100.; + static amrex::Real GoffGratch_svp_water (const amrex::Real& t) { + // uncertain below -70 C + return pow(10., (-7.90298*(tboil/t-1.)+ + 5.02808*std::log10(tboil/t)- + 1.3816e-7*(pow(10., (11.344*(1.-t/tboil)))-1.)+ + 8.1328e-3*(pow(10., (-3.49149*(tboil/t-1.)))-1.)+ + std::log10(1013.246)))*100.; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real GoffGratch_svp_ice(const amrex::Real& t) { - // good down to -100 C - return pow(10., (-9.09718*(h2otrip/t-1.)-3.56654* - log10(h2otrip/t)+0.876793*(1.-t/h2otrip)+ - log10(6.1071)))*100.; + static amrex::Real GoffGratch_svp_ice (const amrex::Real& t) { + // good down to -100 C + return pow(10., (-9.09718*(h2otrip/t-1.)-3.56654* + log10(h2otrip/t)+0.876793*(1.-t/h2otrip)+ + log10(6.1071)))*100.; } // Murphy & Koop (2005) AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real MurphyKoop_svp_water(const amrex::Real& t) { - // (good for 123 < T < 332 K) - return exp(54.842763 - (6763.22 / t) - (4.210 * log(t)) + - (0.000367 * t) + (tanh(0.0415 * (t - 218.8)) * - (53.878 - (1331.22 / t) - (9.44523 * log(t)) + - 0.014025 * t))); + static amrex::Real MurphyKoop_svp_water (const amrex::Real& t) { + // (good for 123 < T < 332 K) + return exp(54.842763 - (6763.22 / t) - (4.210 * log(t)) + + (0.000367 * t) + (tanh(0.0415 * (t - 218.8)) * + (53.878 - (1331.22 / t) - (9.44523 * log(t)) + + 0.014025 * t))); } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real MurphyKoop_svp_ice(const amrex::Real& t) { - // (good down to 110 K) - return exp(9.550426 - (5723.265 / t) + (3.53068 * log(t)) - - (0.00728332 * t)); + static amrex::Real MurphyKoop_svp_ice (const amrex::Real& t) { + // (good down to 110 K) + return exp(9.550426 - (5723.265 / t) + (3.53068 * log(t)) + - (0.00728332 * t)); } @@ -204,25 +204,25 @@ class SatMethods { // probably a mistake, it mildly improves accuracy for ice svp, // since it compensates for a systematic error in Goff & Gratch. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real OldGoffGratch_svp_water(const amrex::Real& t) { - auto ps = 1013.246; - auto e1 = 11.344*(1.0 - t/tboil); - auto e2 = -3.49149*(tboil/t - 1.0); - auto f1 = -7.90298*(tboil/t - 1.0); - auto f2 = 5.02808*log10(tboil/t); - auto f3 = -1.3816*(pow(10.0, e1) - 1.0)/10000000.0; - auto f4 = 8.1328*(pow(10.0, e2) - 1.0)/1000.0; - auto f5 = log10(ps); - auto f = f1 + f2 + f3 + f4 + f5; - return (pow(10.0, f))*100.0; + static amrex::Real OldGoffGratch_svp_water (const amrex::Real& t) { + auto ps = 1013.246; + auto e1 = 11.344*(1.0 - t/tboil); + auto e2 = -3.49149*(tboil/t - 1.0); + auto f1 = -7.90298*(tboil/t - 1.0); + auto f2 = 5.02808*log10(tboil/t); + auto f3 = -1.3816*(pow(10.0, e1) - 1.0)/10000000.0; + auto f4 = 8.1328*(pow(10.0, e2) - 1.0)/1000.0; + auto f5 = log10(ps); + auto f = f1 + f2 + f3 + f4 + f5; + return (pow(10.0, f))*100.0; } AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real OldGoffGratch_svp_ice(const amrex::Real& t) { - auto term1 = 2.01889049/(tmelt/t); - auto term2 = 3.56654*log(tmelt/t); - auto term3 = 20.947031*(tmelt/t); - return 575.185606e10*exp(-(term1 + term2 + term3)); + static amrex::Real OldGoffGratch_svp_ice (const amrex::Real& t) { + auto term1 = 2.01889049/(tmelt/t); + auto term2 = 3.56654*log(tmelt/t); + auto term3 = 20.947031*(tmelt/t); + return 575.185606e10*exp(-(term1 + term2 + term3)); } // Bolton (1980) @@ -234,22 +234,22 @@ class SatMethods { // The original formula used degrees C, but this function // takes Kelvin and internally converts. AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real Bolton_svp_water(const amrex::Real& t) { - constexpr auto c1 = 611.2; - constexpr auto c2 = 17.67; - constexpr auto c3 = 243.5; - return c1*exp( (c2*(t - tmelt))/((t - tmelt)+c3) ); + static amrex::Real Bolton_svp_water (const amrex::Real& t) { + constexpr auto c1 = 611.2; + constexpr auto c2 = 17.67; + constexpr auto c3 = 243.5; + return c1*exp( (c2*(t - tmelt))/((t - tmelt)+c3) ); } // private data - private: - // Indices representing individual schemes - enum Type { - Invalid = -1, - OldGoffGratch = 0, - GoffGratch = 1, - MurphyKoop = 2, - Bolton = 3 - }; +private: + // Indices representing individual schemes + enum Type { + Invalid = -1, + OldGoffGratch = 0, + GoffGratch = 1, + MurphyKoop = 2, + Bolton = 3 + }; }; #endif diff --git a/Source/Utils/TileNoZ.H b/Source/Utils/TileNoZ.H index 1bd8de132..b43bd24a7 100644 --- a/Source/Utils/TileNoZ.H +++ b/Source/Utils/TileNoZ.H @@ -8,7 +8,7 @@ */ AMREX_FORCE_INLINE -amrex::IntVect TileNoZ() +amrex::IntVect TileNoZ () { if (amrex::TilingIfNotGPU()) { return amrex::IntVect{amrex::FabArrayBase::mfiter_tile_size[0], diff --git a/Source/Utils/Utils.H b/Source/Utils/Utils.H index fb4b34037..2e71e81bd 100644 --- a/Source/Utils/Utils.H +++ b/Source/Utils/Utils.H @@ -121,23 +121,23 @@ wrfbdy_zero_rhs_in_set_region (const int& icomp, const amrex::Box& bx_yhi, const amrex::Array4& rhs_arr) { - amrex::ParallelFor(bx_xlo, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept - { - rhs_arr(i,j,k,n+icomp) = 0.0; - }, - bx_xhi, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept - { + amrex::ParallelFor(bx_xlo, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { rhs_arr(i,j,k,n+icomp) = 0.0; - }); + }, + bx_xhi, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + rhs_arr(i,j,k,n+icomp) = 0.0; + }); - amrex::ParallelFor(bx_ylo, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept - { - rhs_arr(i,j,k,n+icomp) = 0.0; - }, - bx_yhi, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept - { - rhs_arr(i,j,k,n+icomp) = 0.0; - }); + amrex::ParallelFor(bx_ylo, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + rhs_arr(i,j,k,n+icomp) = 0.0; + }, + bx_yhi, num_var, [=] AMREX_GPU_DEVICE (int i, int j, int k, int n) noexcept + { + rhs_arr(i,j,k,n+icomp) = 0.0; + }); } /** diff --git a/Source/Utils/VelocityToMomentum.cpp b/Source/Utils/VelocityToMomentum.cpp index f89ab3018..eaf6bf448 100644 --- a/Source/Utils/VelocityToMomentum.cpp +++ b/Source/Utils/VelocityToMomentum.cpp @@ -22,7 +22,7 @@ using namespace amrex; * @param[in] l_use_ndiff flag describing whether we will later add explicit numerical diffusion */ -void VelocityToMomentum( const MultiFab& xvel_in, +void VelocityToMomentum (const MultiFab& xvel_in, const IntVect& xvel_ngrow, const MultiFab& yvel_in, const IntVect& yvel_ngrow, diff --git a/Source/Utils/Water_vapor_saturation.H b/Source/Utils/Water_vapor_saturation.H index 0a747429a..f2b4d9220 100644 --- a/Source/Utils/Water_vapor_saturation.H +++ b/Source/Utils/Water_vapor_saturation.H @@ -26,342 +26,342 @@ // Radiation code interface class class WaterVaporSat { - public: - // Make these public parameters in case another module wants to see the - // extent of the table. - static constexpr amrex::Real tmin = 127.16; - static constexpr amrex::Real tmax = 375.16; - - // Set coefficients for polynomial approximation of difference - // between saturation vapor press over water and saturation pressure - // over ice for -ttrice < t < 0 (degrees C). NOTE: polynomial is - // valid in the range -40 < t < 0 (degrees C). - static constexpr int npcf = 5; - static constexpr const amrex::Real pcf[npcf] = {5.04469588506e-01, - -5.47288442819e+00, - -3.67471858735e-01, - -8.95963532403e-03, - -7.78053686625e-05}; - - // Compute saturation vapor pressure over water - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real svp_water(const amrex::Real& t) { - return SatMethods::wv_sat_svp_water(t); - } - - // Compute saturation vapor pressure over ice - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real svp_ice(const amrex::Real& t) { - return SatMethods::wv_sat_svp_ice(t); - } - - // Compute saturation vapor pressure with an ice-water transition - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real svp_trans(const amrex::Real& t) { - return SatMethods::wv_sat_svp_trans(t); - } - - // Get enthalpy based only on temperature - // and specific humidity. - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static amrex::Real tq_enthalpy(const amrex::Real& t, - const amrex::Real& q, - const amrex::Real& hltalt) { - return Cp_d * t + hltalt * q; - } - - //------------------------------------------------ - // LATENT HEAT OF VAPORIZATION CORRECTIONS - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void no_ip_hltalt(const amrex::Real& t, - amrex::Real hltalt) { - hltalt = latvap; - // Account for change of latvap with t above freezing where - // constant slope is given by -2369 j/(kg c) = cpv - cw - if (t >= tmelt) hltalt = hltalt - 2369.0*(t-tmelt); - } - - // Calculate latent heat of vaporization of water at a given - // temperature, taking into account the ice phase if temperature - // is below freezing. - // Optional argument also calculates a term used to calculate - // d(es)/dT within the water-ice transition range. - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void calc_hltalt(const amrex::Real& t, - amrex::Real hltalt, - amrex::Real tterm = 0.) { - amrex::Real tc, weight; - no_ip_hltalt(t, hltalt); - if (t < tmelt) { - // Weighting of hlat accounts for transition from water to ice. - tc = t - tmelt; - if (tc >= -ttrice) { - weight = -tc/ttrice; - - // polynomial expression approximates difference between es - // over water and es over ice from 0 to -ttrice (C) (max of - // ttrice is 40): required for accurate estimate of es - // derivative in transition range from ice to water - - for(auto i = npcf-1; i > 0; --i) tterm = pcf[i] + tc*tterm; - tterm = tterm/ttrice; - } - else { - weight = 1.0; - } - - hltalt = hltalt + weight*latice; +public: + // Make these public parameters in case another module wants to see the + // extent of the table. + static constexpr amrex::Real tmin = 127.16; + static constexpr amrex::Real tmax = 375.16; + + // Set coefficients for polynomial approximation of difference + // between saturation vapor press over water and saturation pressure + // over ice for -ttrice < t < 0 (degrees C). NOTE: polynomial is + // valid in the range -40 < t < 0 (degrees C). + static constexpr int npcf = 5; + static constexpr const amrex::Real pcf[npcf] = {5.04469588506e-01, + -5.47288442819e+00, + -3.67471858735e-01, + -8.95963532403e-03, + -7.78053686625e-05}; + + // Compute saturation vapor pressure over water + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static amrex::Real svp_water (const amrex::Real& t) { + return SatMethods::wv_sat_svp_water(t); } - } - // Temperature derivative outputs, for qsat_* - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void deriv_outputs(const amrex::Real& t, + // Compute saturation vapor pressure over ice + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static amrex::Real svp_ice (const amrex::Real& t) { + return SatMethods::wv_sat_svp_ice(t); + } + + // Compute saturation vapor pressure with an ice-water transition + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static amrex::Real svp_trans (const amrex::Real& t) { + return SatMethods::wv_sat_svp_trans(t); + } + + // Get enthalpy based only on temperature + // and specific humidity. + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static amrex::Real tq_enthalpy (const amrex::Real& t, + const amrex::Real& q, + const amrex::Real& hltalt) { + return Cp_d * t + hltalt * q; + } + + //------------------------------------------------ + // LATENT HEAT OF VAPORIZATION CORRECTIONS + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static void no_ip_hltalt (const amrex::Real& t, + amrex::Real hltalt) { + hltalt = latvap; + // Account for change of latvap with t above freezing where + // constant slope is given by -2369 j/(kg c) = cpv - cw + if (t >= tmelt) hltalt = hltalt - 2369.0*(t-tmelt); + } + + // Calculate latent heat of vaporization of water at a given + // temperature, taking into account the ice phase if temperature + // is below freezing. + // Optional argument also calculates a term used to calculate + // d(es)/dT within the water-ice transition range. + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static void calc_hltalt (const amrex::Real& t, + amrex::Real hltalt, + amrex::Real tterm = 0.) { + amrex::Real tc, weight; + no_ip_hltalt(t, hltalt); + if (t < tmelt) { + // Weighting of hlat accounts for transition from water to ice. + tc = t - tmelt; + if (tc >= -ttrice) { + weight = -tc/ttrice; + + // polynomial expression approximates difference between es + // over water and es over ice from 0 to -ttrice (C) (max of + // ttrice is 40): required for accurate estimate of es + // derivative in transition range from ice to water + + for(auto i = npcf-1; i > 0; --i) tterm = pcf[i] + tc*tterm; + tterm = tterm/ttrice; + } + else { + weight = 1.0; + } + + hltalt = hltalt + weight*latice; + } + } + + // Temperature derivative outputs, for qsat_* + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static void deriv_outputs (const amrex::Real& t, + const amrex::Real& p, + const amrex::Real& es, + const amrex::Real& qs, + const amrex::Real& hltalt, + const amrex::Real& tterm, + amrex::Real& gam, + amrex::Real& dqsdt) { + + // Local variables + amrex::Real desdt; // d(es)/dt + amrex::Real dqsdt_loc; // local copy of dqsdt + + if (qs == 1.0) { + dqsdt_loc = 0.; + } + else { + desdt = hltalt*es/(R_v*t*t) + tterm; + dqsdt_loc = qs*p*desdt/(es*(p-omeps*es)); + } + + dqsdt = dqsdt_loc; + gam = dqsdt_loc * (hltalt/Cp_d); + } + + // Look up and return saturation vapor pressure from precomputed + // table, then calculate and return saturation specific humidity. + // Optionally return various temperature derivatives or enthalpy + // at saturation. + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static void qsat (const amrex::Real& t, + const amrex::Real& p, + amrex::Real& es, + amrex::Real& qs, + amrex::Real gam = 0., + amrex::Real dqsdt = 0. , + amrex::Real enthalpy = 0.) { + // Local variables + amrex::Real hltalt; // Modified latent heat for T derivatives + amrex::Real tterm; // Account for d(es)/dT in transition region + + es = svp_trans(t); //estblf(t); + + qs = SatMethods::wv_sat_svp_to_qsat(es, p); + + // Ensures returned es is consistent with limiters on qs. + es = std::min(es, p); + + // Calculate optional arguments. + // "generalized" analytic expression for t derivative of es + // accurate to within 1 percent for 173.16 < t < 373.16 + calc_hltalt(t, hltalt, tterm); + + enthalpy = tq_enthalpy(t, qs, hltalt); + + deriv_outputs(t, p, es, qs, hltalt, tterm, gam, dqsdt); + } + + // Calculate SVP over water at a given temperature, and then + // calculate and return saturation specific humidity. + // Optionally return various temperature derivatives or enthalpy + // at saturation. + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static void qsat_water (const amrex::Real& t, const amrex::Real& p, - const amrex::Real& es, - const amrex::Real& qs, - const amrex::Real& hltalt, - const amrex::Real& tterm, - amrex::Real& gam, - amrex::Real& dqsdt) { - - // Local variables - amrex::Real desdt; // d(es)/dt - amrex::Real dqsdt_loc; // local copy of dqsdt - - if (qs == 1.0) { - dqsdt_loc = 0.; + amrex::Real& es, + amrex::Real& qs, + amrex::Real gam = 0., + amrex::Real dqsdt = 0., + amrex::Real enthalpy = 0.) { + // Local variables + amrex::Real hltalt; // Modified latent heat for T derivatives + + SatMethods::wv_sat_qsat_water(t, p, es, qs); + + // "generalized" analytic expression for t derivative of es + // accurate to within 1 percent for 173.16 < t < 373.16 + + no_ip_hltalt(t, hltalt); + + enthalpy = tq_enthalpy(t, qs, hltalt); + + // For pure water/ice transition term is 0. + deriv_outputs(t, p, es, qs, hltalt, 0., gam, dqsdt); } - else { - desdt = hltalt*es/(R_v*t*t) + tterm; - dqsdt_loc = qs*p*desdt/(es*(p-omeps*es)); + + // Calculate SVP over ice at a given temperature, and then + // calculate and return saturation specific humidity. + // Optionally return various temperature derivatives or enthalpy + // at saturation. + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static void qsat_ice (const amrex::Real& t, + const amrex::Real& p, + amrex::Real& es, + amrex::Real& qs, + amrex::Real& gam, + amrex::Real& dqsdt, + amrex::Real& enthalpy) { + // Local variables + amrex::Real hltalt; // Modified latent heat for T derivatives + + SatMethods::wv_sat_qsat_ice(t, p, es, qs); + + // For pure ice, just add latent heats. + hltalt = latvap + latice; + + enthalpy = tq_enthalpy(t, qs, hltalt); + + // For pure water/ice transition term is 0. + deriv_outputs(t, p, es, qs, hltalt, 0., gam, dqsdt); } - dqsdt = dqsdt_loc; - gam = dqsdt_loc * (hltalt/Cp_d); - } - - // Look up and return saturation vapor pressure from precomputed - // table, then calculate and return saturation specific humidity. - // Optionally return various temperature derivatives or enthalpy - // at saturation. - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void qsat(const amrex::Real& t, - const amrex::Real& p, - amrex::Real& es, - amrex::Real& qs, - amrex::Real gam = 0., - amrex::Real dqsdt = 0. , - amrex::Real enthalpy = 0.) { - // Local variables - amrex::Real hltalt; // Modified latent heat for T derivatives - amrex::Real tterm; // Account for d(es)/dT in transition region - - es = svp_trans(t); //estblf(t); - - qs = SatMethods::wv_sat_svp_to_qsat(es, p); - - // Ensures returned es is consistent with limiters on qs. - es = std::min(es, p); - - // Calculate optional arguments. - // "generalized" analytic expression for t derivative of es - // accurate to within 1 percent for 173.16 < t < 373.16 - calc_hltalt(t, hltalt, tterm); - - enthalpy = tq_enthalpy(t, qs, hltalt); - - deriv_outputs(t, p, es, qs, hltalt, tterm, gam, dqsdt); - } - - // Calculate SVP over water at a given temperature, and then - // calculate and return saturation specific humidity. - // Optionally return various temperature derivatives or enthalpy - // at saturation. - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void qsat_water(const amrex::Real& t, - const amrex::Real& p, - amrex::Real& es, - amrex::Real& qs, - amrex::Real gam = 0., - amrex::Real dqsdt = 0., - amrex::Real enthalpy = 0.) { - // Local variables - amrex::Real hltalt; // Modified latent heat for T derivatives - - SatMethods::wv_sat_qsat_water(t, p, es, qs); - - // "generalized" analytic expression for t derivative of es - // accurate to within 1 percent for 173.16 < t < 373.16 - - no_ip_hltalt(t, hltalt); - - enthalpy = tq_enthalpy(t, qs, hltalt); - - // For pure water/ice transition term is 0. - deriv_outputs(t, p, es, qs, hltalt, 0., gam, dqsdt); - } - - // Calculate SVP over ice at a given temperature, and then - // calculate and return saturation specific humidity. - // Optionally return various temperature derivatives or enthalpy - // at saturation. - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void qsat_ice(const amrex::Real& t, - const amrex::Real& p, - amrex::Real& es, - amrex::Real& qs, - amrex::Real& gam, - amrex::Real& dqsdt, - amrex::Real& enthalpy) { - // Local variables - amrex::Real hltalt; // Modified latent heat for T derivatives - - SatMethods::wv_sat_qsat_ice(t, p, es, qs); - - // For pure ice, just add latent heats. - hltalt = latvap + latice; - - enthalpy = tq_enthalpy(t, qs, hltalt); - - // For pure water/ice transition term is 0. - deriv_outputs(t, p, es, qs, hltalt, 0., gam, dqsdt); - } - - // find the wet bulb temperature for a given t and q - // in a longitude height section - // wet bulb temp is the temperature and spec humidity that is - // just saturated and has the same enthalpy - // if q > qs(t) then tsp > t and qsp = qs(tsp) < q - // if q < qs(t) then tsp < t and qsp = qs(tsp) > q - // - // Method: - // a Newton method is used - // first guess uses an algorithm provided by John Petch from the UKMO - // we exclude points where the physical situation is unrealistic - // e.g. where the temperature is outside the range of validity for the - // saturation vapor pressure, or where the water vapor pressure - // exceeds the ambient pressure, or the saturation specific humidity is - // unrealistic - AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE - static void findsp(const amrex::Real& q, - const amrex::Real& t, - const amrex::Real& p, - const bool& use_ice, - amrex::Real& tsp, - amrex::Real& qsp, - int& status) { - - // - // local variables - // - int iter = 8; // max number of times to iterate the calculation - - amrex::Real es; // sat. vapor pressure - amrex::Real gam; // change in sat spec. hum. wrt temperature (times hltalt/cpair) - amrex::Real dgdt; // work variable - amrex::Real g; // work variable - amrex::Real hltalt; // lat. heat. of vap. - amrex::Real qs; // spec. hum. of water vapor - - // work variables - amrex::Real t1, q1, dt, dq; - amrex::Real qvd; - amrex::Real r1b, c1, c2, c3; - constexpr amrex::Real dttol = 1.e-4; // the relative temp error tolerance required to quit the iteration - constexpr amrex::Real dqtol = 1.e-4; // the relative moisture error tolerance required to quit the iteration - amrex::Real enin, enout; - - c3 = 287.04*(7.5*log(10.))/Cp_d; - - // Saturation specific humidity at this temperature - if (use_ice) { - qsat(t, p, es, qs); - } - else { - qsat_water(t, p, es, qs); - } - - // make sure a meaningful calculation is possible - if (p <= 5.*es || qs <= 0. || qs >= 0.5 || t < tmin || t > tmax) { - status = 1; - // Keep initial parameters when conditions aren't suitable - tsp = t; - qsp = q; - enin = 1.; - enout = 1.; - return; - } - - // Prepare to iterate - status = 2; - - // Get initial enthalpy - if (use_ice) - calc_hltalt(t,hltalt); - else - no_ip_hltalt(t,hltalt); - - enin = tq_enthalpy(t, q, hltalt); - - // make a guess at the wet bulb temp using a UKMO algorithm (from J. Petch) - c1 = hltalt*c3; - c2 = std::pow(t + 36., 2); - r1b = c2/(c2 + c1*qs); - qvd = r1b * (q - qs); - tsp = t + ((hltalt/Cp_d)*qvd); - - // Generate qsp, gam, and enout from tsp. - if (use_ice) - qsat(tsp, p, es, qsp, gam, enout); - else - qsat_water(tsp, p, es, qsp, gam, enout); - - // iterate on first guess - for(auto l = 1; l < iter; ++l) { - - g = enin - enout; - dgdt = -Cp_d * (1 + gam); - - // New tsp - t1 = tsp - g/dgdt; - dt = abs(t1 - tsp)/t1; - tsp = t1; - - // bail out if past end of temperature range - if ( tsp < tmin ) { - tsp = tmin; - // Get latent heat and set qsp to a value - // that preserves enthalpy. + // find the wet bulb temperature for a given t and q + // in a longitude height section + // wet bulb temp is the temperature and spec humidity that is + // just saturated and has the same enthalpy + // if q > qs(t) then tsp > t and qsp = qs(tsp) < q + // if q < qs(t) then tsp < t and qsp = qs(tsp) > q + // + // Method: + // a Newton method is used + // first guess uses an algorithm provided by John Petch from the UKMO + // we exclude points where the physical situation is unrealistic + // e.g. where the temperature is outside the range of validity for the + // saturation vapor pressure, or where the water vapor pressure + // exceeds the ambient pressure, or the saturation specific humidity is + // unrealistic + AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE + static void findsp (const amrex::Real& q, + const amrex::Real& t, + const amrex::Real& p, + const bool& use_ice, + amrex::Real& tsp, + amrex::Real& qsp, + int& status) { + + // + // local variables + // + int iter = 8; // max number of times to iterate the calculation + + amrex::Real es; // sat. vapor pressure + amrex::Real gam; // change in sat spec. hum. wrt temperature (times hltalt/cpair) + amrex::Real dgdt; // work variable + amrex::Real g; // work variable + amrex::Real hltalt; // lat. heat. of vap. + amrex::Real qs; // spec. hum. of water vapor + + // work variables + amrex::Real t1, q1, dt, dq; + amrex::Real qvd; + amrex::Real r1b, c1, c2, c3; + constexpr amrex::Real dttol = 1.e-4; // the relative temp error tolerance required to quit the iteration + constexpr amrex::Real dqtol = 1.e-4; // the relative moisture error tolerance required to quit the iteration + amrex::Real enin, enout; + + c3 = 287.04*(7.5*log(10.))/Cp_d; + + // Saturation specific humidity at this temperature + if (use_ice) { + qsat(t, p, es, qs); + } + else { + qsat_water(t, p, es, qs); + } + + // make sure a meaningful calculation is possible + if (p <= 5.*es || qs <= 0. || qs >= 0.5 || t < tmin || t > tmax) { + status = 1; + // Keep initial parameters when conditions aren't suitable + tsp = t; + qsp = q; + enin = 1.; + enout = 1.; + return; + } + + // Prepare to iterate + status = 2; + + // Get initial enthalpy if (use_ice) - calc_hltalt(tsp,hltalt); + calc_hltalt(t,hltalt); else - no_ip_hltalt(tsp,hltalt); - - qsp = (enin - Cp_d*tsp)/hltalt; - enout = tq_enthalpy(tsp, qsp, hltalt); - status = 4; - break; - } - - // Re-generate qsp, gam, and enout from new tsp. - if (use_ice) - qsat(tsp, p, es, q1, gam, enout); - else - qsat_water(tsp, p, es, q1, gam, enout); - - dq = abs(q1 - qsp)/std::max(q1,1.e-12); - qsp = q1; - - // if converged at this point, exclude it from more iterations - if (dt < dttol && dq < dqtol) { - status = 0; - break; - } - } - // Test for enthalpy conservation - if (abs((enin-enout)/(enin+enout)) > 1.e-4) status = 8; - return; - } + no_ip_hltalt(t,hltalt); + + enin = tq_enthalpy(t, q, hltalt); + + // make a guess at the wet bulb temp using a UKMO algorithm (from J. Petch) + c1 = hltalt*c3; + c2 = std::pow(t + 36., 2); + r1b = c2/(c2 + c1*qs); + qvd = r1b * (q - qs); + tsp = t + ((hltalt/Cp_d)*qvd); + + // Generate qsp, gam, and enout from tsp. + if (use_ice) + qsat(tsp, p, es, qsp, gam, enout); + else + qsat_water(tsp, p, es, qsp, gam, enout); + + // iterate on first guess + for(auto l = 1; l < iter; ++l) { + + g = enin - enout; + dgdt = -Cp_d * (1 + gam); + + // New tsp + t1 = tsp - g/dgdt; + dt = abs(t1 - tsp)/t1; + tsp = t1; + + // bail out if past end of temperature range + if ( tsp < tmin ) { + tsp = tmin; + // Get latent heat and set qsp to a value + // that preserves enthalpy. + if (use_ice) + calc_hltalt(tsp,hltalt); + else + no_ip_hltalt(tsp,hltalt); + + qsp = (enin - Cp_d*tsp)/hltalt; + enout = tq_enthalpy(tsp, qsp, hltalt); + status = 4; + break; + } + + // Re-generate qsp, gam, and enout from new tsp. + if (use_ice) + qsat(tsp, p, es, q1, gam, enout); + else + qsat_water(tsp, p, es, q1, gam, enout); + + dq = abs(q1 - qsp)/std::max(q1,1.e-12); + qsp = q1; + + // if converged at this point, exclude it from more iterations + if (dt < dttol && dq < dqtol) { + status = 0; + break; + } + } + // Test for enthalpy conservation + if (abs((enin-enout)/(enin+enout)) > 1.e-4) status = 8; + return; + } }; #endif // WATER_VAPOR_SATURATION_H_