77#include " AMReX_REAL.H"
88#include " AMReX_MultiFab.H"
99#include " AMReX_ParmParse.H"
10+ #include " amr-wind/wind_energy/ABL.H"
1011
1112namespace amr_wind {
1213namespace turbulence {
@@ -25,7 +26,6 @@ Kosovic<Transport>::Kosovic(CFDSim& sim)
2526 m_Cs = std::sqrt (8 * (1 + m_Cb) / (27 * M_PI * M_PI));
2627 m_C1 = std::sqrt (960 ) * m_Cb / (7 * (1 + m_Cb) * m_Sk);
2728 m_C2 = m_C1;
28- pp.query (" refMOL" , m_refMOL);
2929 pp.query (" surfaceRANS" , m_surfaceRANS);
3030 if (m_surfaceRANS) {
3131 m_surfaceFactor = 1 ;
@@ -40,6 +40,13 @@ Kosovic<Transport>::Kosovic(CFDSim& sim)
4040 this ->m_sim .io_manager ().register_io_var (" divNij" );
4141 }
4242 pp.query (" LESOff" , m_LESTurnOff);
43+ amrex::ParmParse pp_abl (" ABL" );
44+ pp_abl.query (" wall_het_model" , m_wall_het_model);
45+ pp_abl.query (" monin_obukhov_length" , m_monin_obukhov_length);
46+ pp_abl.query (" kappa" , m_kappa);
47+ pp_abl.query (" mo_gamma_m" , m_gamma_m);
48+ pp_abl.query (" mo_beta_m" , m_beta_m);
49+ pp_abl.query (" surface_roughness_z0" , m_surface_roughness_z0);
4350}
4451template <typename Transport>
4552void Kosovic<Transport>::update_turbulent_viscosity(
@@ -59,6 +66,13 @@ void Kosovic<Transport>::update_turbulent_viscosity(
5966 const auto * m_terrain_blank =
6067 has_terrain ? &this ->m_sim .repo ().get_int_field (" terrain_blank" )
6168 : nullptr ;
69+ const auto * m_terrain_drag =
70+ has_terrain ? &this ->m_sim .repo ().get_int_field (" terrain_drag" )
71+ : nullptr ;
72+ const auto * m_terrain_height =
73+ has_terrain ? &this ->m_sim .repo ().get_field (" terrain_height" ) : nullptr ;
74+ const auto * m_terrain_z0 =
75+ has_terrain ? &this ->m_sim .repo ().get_field (" terrainz0" ) : nullptr ;
6276 // Populate strainrate into the turbulent viscosity arrays to avoid creating
6377 // a temporary buffer
6478 fvm::strainrate (mu_turb, vel);
@@ -75,29 +89,54 @@ void Kosovic<Transport>::update_turbulent_viscosity(
7589 const amrex::Real ds = std::cbrt (dx * dy * dz);
7690 const amrex::Real ds_sqr = ds * ds;
7791 const amrex::Real smag_factor = Cs_sqr * ds_sqr;
78- const amrex::Real locMOL = m_refMOL;
7992 const amrex::Real locLESTurnOff = m_LESTurnOff;
8093 const amrex::Real locSwitchLoc = m_switchLoc;
8194 const amrex::Real locSurfaceRANSExp = m_surfaceRANSExp;
8295 const amrex::Real locSurfaceFactor = m_surfaceFactor;
8396 const amrex::Real locC1 = m_C1;
8497 const auto & mu_arrs = mu_turb (lev).arrays ();
8598 const auto & rho_arrs = den (lev).const_arrays ();
99+ const auto & vel_arrs = vel (lev).const_arrays ();
86100 const auto & divNij_arrs = (this ->m_divNij )(lev).arrays ();
87101 const auto & blank_arrs = has_terrain
88102 ? (*m_terrain_blank)(lev).const_arrays ()
89103 : amrex::MultiArray4<const int >();
104+ const auto & drag_arrs = has_terrain
105+ ? (*m_terrain_drag)(lev).const_arrays ()
106+ : amrex::MultiArray4<const int >();
107+ const auto & height_arrs = has_terrain
108+ ? (*m_terrain_height)(lev).const_arrays ()
109+ : amrex::MultiArray4<const double >();
110+ const auto & z0_arrs = has_terrain ? (*m_terrain_z0)(lev).const_arrays ()
111+ : amrex::MultiArray4<const double >();
112+ const amrex::Real monin_obukhov_length = m_monin_obukhov_length;
113+ const amrex::Real kappa = m_kappa;
114+ const amrex::Real surface_roughness_z0 = m_surface_roughness_z0;
115+ const amrex::Real non_neutral_neighbour =
116+ (m_wall_het_model == " mol" )
117+ ? MOData::calc_psi_m (
118+ 1.5 * dz / monin_obukhov_length, m_beta_m, m_gamma_m)
119+ : 0.0 ;
90120 amrex::ParallelFor (
91121 mu_turb (lev),
92122 [=] AMREX_GPU_DEVICE (int nbx, int i, int j, int k) noexcept {
93123 const amrex::Real rho = rho_arrs[nbx](i, j, k);
94- const amrex::Real x3 = problo[2 ] + (k + 0.5 ) * dz;
124+ amrex::Real x3 = problo[2 ] + (k + 0.5 ) * dz;
125+ x3 = (has_terrain)
126+ ? std::max (x3 - height_arrs[nbx](i, j, k, 0 ), 0.5 * dz)
127+ : x3;
95128 const amrex::Real fmu = std::exp (-x3 / locSwitchLoc);
96129 const amrex::Real phiM =
97- (locMOL < 0 ) ? std::pow (1 - 16 * x3 / locMOL, -0.25 )
98- : 1 + 5 * x3 / locMOL;
130+ (monin_obukhov_length < 0 )
131+ ? std::pow (1 - 16 * x3 / monin_obukhov_length, -0.25 )
132+ : 1 + 5 * x3 / monin_obukhov_length;
133+ const amrex::Real wall_distance =
134+ (has_terrain)
135+ ? std::max (
136+ (k + 1 ) * dz - height_arrs[nbx](i, j, k, 0 ), dz)
137+ : (k + 1 ) * dz;
99138 const amrex::Real ransL =
100- std::pow (0.41 * (k + 1 ) * dz / phiM, 2 );
139+ std::pow (0.41 * wall_distance / phiM, 2 );
101140 amrex::Real turnOff = std::exp (-x3 / locLESTurnOff);
102141 amrex::Real viscosityScale =
103142 locSurfaceFactor *
@@ -108,6 +147,29 @@ void Kosovic<Transport>::update_turbulent_viscosity(
108147 (has_terrain) ? 1 - blank_arrs[nbx](i, j, k, 0 ) : 1.0 ;
109148 mu_arrs[nbx](i, j, k) *=
110149 rho * viscosityScale * turnOff * blankTerrain;
150+ // log-law
151+ const amrex::Real ux = vel_arrs[nbx](i, j, k + 1 , 0 );
152+ const amrex::Real uy = vel_arrs[nbx](i, j, k + 1 , 1 );
153+ const amrex::Real m = std::sqrt (ux * ux + uy * uy);
154+ const amrex::Real local_z0 =
155+ (has_terrain) ? std::max (z0_arrs[nbx](i, j, k, 0 ), 1e-4 )
156+ : surface_roughness_z0;
157+ // ustar from neighbor cell above
158+ const amrex::Real ustar =
159+ m * kappa /
160+ (std::log (1.5 * dz / local_z0) - non_neutral_neighbour);
161+ const amrex::Real ux0 = vel_arrs[nbx](i, j, k, 0 );
162+ const amrex::Real uy0 = vel_arrs[nbx](i, j, k, 1 );
163+ const amrex::Real m0 = std::sqrt (ux0 * ux0 + uy0 * uy0);
164+ const amrex::Real uxm1 = vel_arrs[nbx](i, j, k - 1 , 0 );
165+ const amrex::Real uym1 = vel_arrs[nbx](i, j, k - 1 , 1 );
166+ const amrex::Real mm1 = std::sqrt (uxm1 * uxm1 + uym1 * uym1);
167+ const amrex::Real dMdz = std::max ((m0 - mm1) / dz, 0.01 );
168+ amrex::Real mut_loglaw = 2 * ustar * ustar * rho / dMdz;
169+ const amrex::Real drag =
170+ (has_terrain) ? drag_arrs[nbx](i, j, k, 0 ) : 0.0 ;
171+ mu_arrs[nbx](i, j, k) =
172+ mu_arrs[nbx](i, j, k) * (1 - drag) + drag * mut_loglaw;
111173 amrex::Real stressScale =
112174 locSurfaceFactor *
113175 (std::pow (1 - fmu, locSurfaceRANSExp) * smag_factor *
@@ -135,7 +197,7 @@ void Kosovic<Transport>::update_alphaeff(Field& alphaeff)
135197 auto lam_alpha = (this ->m_transport ).alpha ();
136198 auto & mu_turb = this ->m_mu_turb ;
137199 auto & repo = mu_turb.repo ();
138- const amrex::Real muCoeff = (m_refMOL < 0 ) ? 3 : 1 ;
200+ const amrex::Real muCoeff = (m_monin_obukhov_length < 0 ) ? 3 : 1 ;
139201 const int nlevels = repo.num_active_levels ();
140202 for (int lev = 0 ; lev < nlevels; ++lev) {
141203 const auto & muturb_arrs = mu_turb (lev).const_arrays ();
0 commit comments