1010// Homme includes
1111#include " Context.hpp"
1212#include " ColumnOps.hpp"
13- #include " ElementOps.hpp"
14- #include " EquationOfState.hpp"
1513#include " HommexxEnums.hpp"
1614#include " HybridVCoord.hpp"
17- #include " KernelVariables.hpp"
1815#include " SimulationParams.hpp"
1916#include " Types.hpp"
2017
18+ // SCREAM includes
19+ #include " share/util/scream_common_physics_functions.hpp"
20+
2121// EKAT includes
2222#include " ekat/ekat_workspace.hpp"
2323#include " ekat/kokkos/ekat_kokkos_types.hpp"
@@ -222,11 +222,7 @@ void HommeDynamics::
222222apply_iop_forcing (const Real dt)
223223{
224224 using ESU = ekat::ExeSpaceUtils<KT::ExeSpace>;
225-
226- using EOS = Homme::EquationOfState;
227- using ElementOps = Homme::ElementOps;
228- using KV = Homme::KernelVariables;
229-
225+ using PF = PhysicsFunctions<DefaultDevice>;
230226 using ColOps = ColumnOps<DefaultDevice, Real>;
231227 using C = physics::Constants<Real>;
232228 constexpr Real Rair = C::Rair;
@@ -263,7 +259,7 @@ apply_iop_forcing(const Real dt)
263259 const auto hyai = m_dyn_grid->get_geometry_data (" hyai" ).get_view <const Real*>();
264260 const auto hybi = m_dyn_grid->get_geometry_data (" hybi" ).get_view <const Real*>();
265261
266- // Homme element states and EOS/EO classes
262+ // Homme element states
267263 auto ps_dyn = get_internal_field (" ps_dyn" ).get_view <Real***>();
268264 auto dp3d_dyn = get_internal_field (" dp3d_dyn" ).get_view <Pack****>();
269265 auto vtheta_dp_dyn = get_internal_field (" vtheta_dp_dyn" ).get_view <Pack****>();
@@ -272,11 +268,6 @@ apply_iop_forcing(const Real dt)
272268 auto Q_dyn = m_helper_fields.at (" Q_dyn" ).get_view <Pack*****>();
273269 auto Qdp_dyn = get_internal_field (" Qdp_dyn" ).get_view <Pack*****>();
274270
275- EOS eos;
276- eos.init (params.theta_hydrostatic_mode , hvcoord);
277-
278- ElementOps elem_ops;
279- elem_ops.init (hvcoord);
280271 const bool use_moisture = (params.moisture == Homme::MoistDry::MOIST);
281272
282273 // Load data from IOP files, if necessary
@@ -319,92 +310,66 @@ apply_iop_forcing(const Real dt)
319310 : m_iop->get_iop_field (" v" ).get_view <const Pack*>();
320311 }
321312
322- // Team policy and workspace manager for both homme and scream
323- // related loops. We need separate policies since hommexx functions used here
324- // assume they are called inside nested loops for elements and Gaussian points,
325- // whereas EAMxx function we use expects a single level of parallelism
326- // for elements and Guassian points.
327- // TODO: scream::ColumnOps functions could take an arbitary loop boundary
328- // (TeamVectorRange, TeamThreadRange, ThreadVectorRange) so that
329- // all 3 kernel launches here could be combined.
330- const auto policy_homme = ESU::get_default_team_policy (nelem, NLEV);
331- const auto policy_eamxx = ESU::get_default_team_policy (nelem*NGP*NGP, NLEV);
313+ // Team policy and workspace manager for eamxx
314+ const auto policy_iop = ESU::get_default_team_policy (nelem*NGP*NGP, NLEV);
332315
333316 // TODO: Create a memory buffer for this class
334317 // and add the below WSM and views
335- WorkspaceMgr eamxx_wsm (NLEVI, 7 +qsize, policy_eamxx);
336- WorkspaceMgr homme_wsm (NLEV, 16 + (theta_hydrostatic_mode ? 16 : 0 ), policy_homme);
318+ WorkspaceMgr iop_wsm (NLEVI, 7 +qsize, policy_iop);
337319 view_Nd<Pack, 4 >
338- rstar (" rstar" , nelem, NGP, NGP, NLEV),
339- exner (" exner" , nelem, NGP, NGP, NLEV),
340320 temperature (" temperature" , nelem, NGP, NGP, NLEV);
341321
342- // Lambda for computing rstar, exner, and temperature from Hommexx
343- auto compute_homme_states = [&] () {
344- Kokkos::parallel_for (" compute_rstar_exner_and_temperature" , policy_homme, KOKKOS_LAMBDA (const KT::MemberType& team) {
345- KV kv (team);
346- const int ie = team.league_rank ();
322+ // Lambda for computing temperature
323+ auto compute_temperature = [&] () {
324+ Kokkos::parallel_for (" compute_temperature_for_iop" , policy_iop, KOKKOS_LAMBDA (const KT::MemberType& team) {
325+ const int ie = team.league_rank ()/(NGP*NGP);
326+ const int igp = (team.league_rank ()/NGP)%NGP;
327+ const int jgp = team.league_rank ()%NGP;
347328
348329 // Get temp views from workspace
349- auto ws = homme_wsm.get_workspace (team);
350- auto pnh_slot = ws.take_macro_block (" pnh" , NGP*NGP);
351- uview_2d<Pack> pnh (reinterpret_cast <Pack*>(pnh_slot.data ()), NGP*NGP, NLEV);
352-
353- Kokkos::parallel_for (Kokkos::TeamThreadRange (kv.team , NGP*NGP), [&] (const int idx) {
354- const int igp = idx/NGP;
355- const int jgp = idx%NGP;
356-
357- auto dp3d_i = ekat::subview (dp3d_dyn, ie, igp, jgp);
358- auto vtheta_dp_i = ekat::subview (vtheta_dp_dyn, ie, igp, jgp);
359- auto phi_int_i = ekat::subview (phi_int_dyn, ie, igp, jgp);
360- auto qv_i = ekat::subview (Q_dyn, ie, 0 , igp, jgp);
361- auto pnh_i = ekat::subview (pnh, idx);
362- auto rstar_i = ekat::subview (rstar, ie, igp, jgp);
363- auto exner_i = ekat::subview (exner, ie, igp, jgp);
364- auto temperature_i = ekat::subview (temperature, ie, igp, jgp);
365-
366- // Reinterperate into views of Homme::Scalar for calling Hommexx function.
367- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> dp3d_scalar (reinterpret_cast <Homme::Scalar*>(dp3d_i.data ()), NLEV);
368- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> vtheta_dp_scalar (reinterpret_cast <Homme::Scalar*>(vtheta_dp_i.data ()), NLEV);
369- Homme::ExecViewUnmanaged<Homme::Scalar[NLEVI]> phi_int_scalar (reinterpret_cast <Homme::Scalar*>(phi_int_i.data ()), NLEVI);
370- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> qv_scalar (reinterpret_cast <Homme::Scalar*>(qv_i.data ()), NLEV);
371- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> pnh_scalar (reinterpret_cast <Homme::Scalar*>(pnh_i.data ()), NLEV);
372- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> exner_scalar (reinterpret_cast <Homme::Scalar*>(exner_i.data ()), NLEV);
373- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> rstar_scalar (reinterpret_cast <Homme::Scalar*>(rstar_i.data ()), NLEV);
374- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> temperature_scalar (reinterpret_cast <Homme::Scalar*>(temperature_i.data ()), NLEV);
375-
376- // Compute exner from EOS
377- if (theta_hydrostatic_mode) {
378- auto hydro_p_int = ws.take (" hydro_p_int" );
379- Homme::ExecViewUnmanaged<Homme::Scalar[NLEVI]> hydro_p_int_scalar (reinterpret_cast <Homme::Scalar*>(hydro_p_int.data ()), NLEVI);
380- elem_ops.compute_hydrostatic_p (kv, dp3d_scalar, hydro_p_int_scalar, pnh_scalar);
381- eos.compute_exner (kv, pnh_scalar, exner_scalar);
382- ws.release (hydro_p_int);
383- } else {
384- eos.compute_pnh_and_exner (kv, vtheta_dp_scalar, phi_int_scalar, pnh_scalar, exner_scalar);
385- }
330+ auto ws = iop_wsm.get_workspace (team);
331+ uview_1d<Pack> pmid;
332+ ws.take_many_contiguous_unsafe <1 >({" pmid" },{&pmid});
333+
334+ auto ps_i = ps_dyn (ie, igp, jgp);
335+ auto dp3d_i = ekat::subview (dp3d_dyn, ie, igp, jgp);
336+ auto vtheta_dp_i = ekat::subview (vtheta_dp_dyn, ie, igp, jgp);
337+ auto qv_i = ekat::subview (Q_dyn, ie, 0 , igp, jgp);
338+ auto temperature_i = ekat::subview (temperature, ie, igp, jgp);
339+
340+ // Compute reference pressures and layer thickness.
341+ // TODO: Allow geometry data to allocate packsize
342+ auto s_pmid = ekat::scalarize (pmid);
343+ Kokkos::parallel_for (Kokkos::TeamVectorRange (team, total_levels), [&](const int & k) {
344+ s_pmid (k) = hyam (k)*ps0 + hybm (k)*ps_i;
345+ });
346+ team.team_barrier ();
386347
387- // Get the temperature from dynamics states
388- elem_ops.get_temperature (kv, eos, use_moisture, dp3d_scalar, exner_scalar, vtheta_dp_scalar, qv_scalar, rstar_scalar, temperature_scalar);
348+ // Compute temperature from virtual potential temperature
349+ Kokkos::parallel_for (Kokkos::TeamVectorRange (team, NLEV), [&] (const int k) {
350+ auto T_val = vtheta_dp_i (k);
351+ T_val /= dp3d_i (k);
352+ T_val = PF::calculate_temperature_from_virtual_temperature (T_val,qv_i (k));
353+ temperature_i (k) = PF::calculate_T_from_theta (T_val,pmid (k));
389354 });
390355
391356 // Release WS views
392- ws.release_macro_block (pnh_slot, NGP*NGP );
357+ ws.release_many_contiguous < 1 >({&pmid} );
393358 });
394359 };
395360
396- // Preprocess some homme states to get temperature and exner
397- compute_homme_states ();
361+ // Preprocess some homme states to get temperature
362+ compute_temperature ();
398363 Kokkos::fence ();
399364
400365 // Apply IOP forcing
401- Kokkos::parallel_for (" apply_iop_forcing" , policy_eamxx , KOKKOS_LAMBDA (const KT::MemberType& team) {
366+ Kokkos::parallel_for (" apply_iop_forcing" , policy_iop , KOKKOS_LAMBDA (const KT::MemberType& team) {
402367 const int ie = team.league_rank ()/(NGP*NGP);
403368 const int igp = (team.league_rank ()/NGP)%NGP;
404369 const int jgp = team.league_rank ()%NGP;
405370
406371 // Get temp views from workspace
407- auto ws = eamxx_wsm .get_workspace (team);
372+ auto ws = iop_wsm .get_workspace (team);
408373 uview_1d<Pack> pmid, pint, pdel;
409374 ws.take_many_contiguous_unsafe <3 >({" pmid" , " pint" , " pdel" },
410375 {&pmid, &pint, &pdel});
@@ -449,53 +414,66 @@ apply_iop_forcing(const Real dt)
449414 Kokkos::fence ();
450415
451416 // Postprocess homme states Qdp and vtheta_dp
452- Kokkos::parallel_for (" compute_qdp_and_vtheta_dp" , policy_homme, KOKKOS_LAMBDA (const KT::MemberType& team) {
453- KV kv (team);
454- const int ie = team.league_rank ();
417+ Kokkos::parallel_for (" compute_qdp_and_vtheta_dp" , policy_iop, KOKKOS_LAMBDA (const KT::MemberType& team) {
418+ const int ie = team.league_rank ()/(NGP*NGP);
419+ const int igp = (team.league_rank ()/NGP)%NGP;
420+ const int jgp = team.league_rank ()%NGP;
455421
456- Kokkos::parallel_for (Kokkos::TeamThreadRange (kv.team , NGP*NGP), [&] (const int idx) {
457- const int igp = idx/NGP;
458- const int jgp = idx%NGP;
422+ // Get temp views from workspace
423+ auto ws = iop_wsm.get_workspace (team);
424+ uview_1d<Pack> pmid, pint, pdel;
425+ ws.take_many_contiguous_unsafe <3 >({" pmid" , " pint" , " pdel" },
426+ {&pmid, &pint, &pdel});
459427
460- auto dp3d_i = ekat::subview (dp3d_dyn, ie, igp, jgp);
461- auto vtheta_dp_i = ekat::subview (vtheta_dp_dyn, ie, igp, jgp);
462- auto qv_i = ekat::subview (Q_dyn, ie, 0 , igp, jgp);
463- auto Q_i = Kokkos::subview (Q_dyn, ie, Kokkos::ALL (), igp, jgp, Kokkos::ALL ());
464- auto Qdp_i = Kokkos::subview (Qdp_dyn, ie, Kokkos::ALL (), igp, jgp, Kokkos::ALL ());
465- auto rstar_i = ekat::subview (rstar, ie, igp, jgp);
466- auto exner_i = ekat::subview (exner, ie, igp, jgp);
467- auto temperature_i = ekat::subview (temperature, ie, igp, jgp);
428+ auto ps_i = ps_dyn (ie, igp, jgp);
429+ auto dp3d_i = ekat::subview (dp3d_dyn, ie, igp, jgp);
430+ auto vtheta_dp_i = ekat::subview (vtheta_dp_dyn, ie, igp, jgp);
431+ auto qv_i = ekat::subview (Q_dyn, ie, 0 , igp, jgp);
432+ auto Q_i = Kokkos::subview (Q_dyn, ie, Kokkos::ALL (), igp, jgp, Kokkos::ALL ());
433+ auto Qdp_i = Kokkos::subview (Qdp_dyn, ie, Kokkos::ALL (), igp, jgp, Kokkos::ALL ());
434+ auto temperature_i = ekat::subview (temperature, ie, igp, jgp);
435+
436+ // Compute reference pressures and layer thickness.
437+ // TODO: Allow geometry data to allocate packsize
438+ auto s_pmid = ekat::scalarize (pmid);
439+ auto s_pint = ekat::scalarize (pint);
440+ Kokkos::parallel_for (Kokkos::TeamVectorRange (team, total_levels+1 ), [&](const int & k) {
441+ s_pint (k) = hyai (k)*ps0 + hybi (k)*ps_i;
442+ if (k < total_levels) {
443+ s_pmid (k) = hyam (k)*ps0 + hybm (k)*ps_i;
444+ }
445+ });
468446
469- // Reinterperate into views of Homme::Scalar for calling Hommexx function.
470- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> qv_scalar (reinterpret_cast <Homme::Scalar*>(qv_i.data ()), NLEV);
471- Homme::ExecViewUnmanaged<Homme::Scalar[NLEV]> rstar_scalar (reinterpret_cast <Homme::Scalar*>(rstar_i.data ()), NLEV);
447+ team.team_barrier ();
472448
473- // Compute Qdp from updated Q
474- Kokkos::parallel_for (Kokkos::ThreadVectorRange (team, NLEV*qsize), [&] (const int k) {
475- const int ilev = k/qsize;
476- const int q = k%qsize;
449+ // Compute Qdp from updated Q
450+ Kokkos::parallel_for (Kokkos::TeamVectorRange (team, NLEV*qsize), [&] (const int k) {
451+ const int ilev = k/qsize;
452+ const int q = k%qsize;
477453
478- Qdp_i (q, ilev) = Q_i (q, ilev)*dp3d_i (ilev);
479- // For BFB on restarts, Q needs to be updated after we compute Qdp
480- Q_i (q, ilev) = Qdp_i (q, ilev)/dp3d_i (ilev);
481- });
454+ Qdp_i (q, ilev) = Q_i (q, ilev)*dp3d_i (ilev);
455+ // For BFB on restarts, Q needs to be updated after we compute Qdp
456+ Q_i (q, ilev) = Qdp_i (q, ilev)/dp3d_i (ilev);
457+ });
482458 team.team_barrier ();
483459
484- // Recompute rstar with updated qv, and convert updated temperature back to potential temperature
485- elem_ops.get_R_star (kv, use_moisture, qv_scalar, rstar_scalar);
486- Kokkos::parallel_for (Kokkos::ThreadVectorRange (team, NLEV), [&] (const int k) {
487- vtheta_dp_i (k) = temperature_i (k)*rstar_i (k)*dp3d_i (k)/(Rair*exner_i (k));
488- });
460+ // Convert updated temperature back to psuedo density virtual potential temperature
461+ Kokkos::parallel_for (Kokkos::TeamVectorRange (team, NLEV), [&] (const int k) {
462+ const auto th = PF::calculate_theta_from_T (temperature_i (k),pmid (k));
463+ vtheta_dp_i (k) = PF::calculate_virtual_temperature (th,qv_i (k))*dp3d_i (k);
489464 });
465+
466+ // Release WS views
467+ ws.release_many_contiguous <3 >({&pmid, &pint, &pdel});
490468 });
491469
492470 if (iop_nudge_tq or iop_nudge_uv) {
493471 // Nudge the domain based on the domain mean
494472 // and observed quantities of T, Q, u, and
495473
496474 if (iop_nudge_tq) {
497- // Compute rstar, exner and temperature from Hommexx
498- compute_homme_states ();
475+ // Compute temperature
476+ compute_temperature ();
499477 Kokkos::fence ();
500478 }
501479
@@ -571,50 +549,63 @@ apply_iop_forcing(const Real dt)
571549 // Apply relaxation
572550 const auto rtau = std::max (dt, iop_nudge_tscale);
573551 Kokkos::parallel_for (" apply_domain_relaxation" ,
574- policy_homme ,
552+ policy_iop ,
575553 KOKKOS_LAMBDA (const KT::MemberType& team) {
576- KV kv (team);
577- const int ie = team.league_rank ();
578-
579- Kokkos::parallel_for (Kokkos::TeamThreadRange (kv.team , NGP*NGP), [&] (const int idx) {
580- const int igp = idx/NGP;
581- const int jgp = idx%NGP;
582-
583- auto dp3d_i = ekat::subview (dp3d_dyn, ie, igp, jgp);
584- auto vtheta_dp_i = ekat::subview (vtheta_dp_dyn, ie, igp, jgp);
585- auto rstar_i = ekat::subview (rstar, ie, igp, jgp);
586- auto exner_i = ekat::subview (exner, ie, igp, jgp);
587- auto qv_i = ekat::subview (Q_dyn, ie, 0 , igp, jgp);
588- auto temperature_i = ekat::subview (temperature, ie, igp, jgp);
589- auto u_i = ekat::subview (v_dyn, ie, 0 , igp, jgp);
590- auto v_i = ekat::subview (v_dyn, ie, 1 , igp, jgp);
591-
592- Kokkos::parallel_for (Kokkos::ThreadVectorRange (team, NLEV), [&](const int & k) {
593- if (iop_nudge_tq) {
594- // Restrict nudging of T and qv to certain levels if requested by user
595- // IOP pressure variable is in unitis of [Pa], while iop_nudge_tq_low/high
596- // is in units of [hPa], thus convert iop_nudge_tq_low/high
597- Mask nudge_level (false );
598- int max_size = hyam.size ();
599- for (int lev=k*Pack::n, p = 0 ; p < Pack::n && lev < max_size; ++lev, ++p) {
600- const auto pressure_from_iop = hyam (lev)*ps0 + hybm (lev)*ps_iop;
601- nudge_level.set (p, pressure_from_iop <= iop_nudge_tq_low*100
602- and
603- pressure_from_iop >= iop_nudge_tq_high*100 );
604- }
605-
606- qv_i (k).update (nudge_level, qv_mean (k) - qv_iop (k), -dt/rtau, 1.0 );
607- temperature_i (k).update (nudge_level, t_mean (k) - t_iop (k), -dt/rtau, 1.0 );
608-
609- // Convert updated temperature back to potential temperature
610- vtheta_dp_i (k) = temperature_i (k)*rstar_i (k)*dp3d_i (k)/(Rair*exner_i (k));
611- }
612- if (iop_nudge_uv) {
613- u_i (k).update (u_mean (k) - u_iop (k), -dt/rtau, 1.0 );
614- v_i (k).update (v_mean (k) - v_iop (k), -dt/rtau, 1.0 );
554+
555+ const int ie = team.league_rank ()/(NGP*NGP);
556+ const int igp = (team.league_rank ()/NGP)%NGP;
557+ const int jgp = team.league_rank ()%NGP;
558+
559+ // Get temp views from workspace
560+ auto ws = iop_wsm.get_workspace (team);
561+ uview_1d<Pack> pmid;
562+ ws.take_many_contiguous_unsafe <1 >({" pmid" },{&pmid});
563+
564+ auto ps_i = ps_dyn (ie, igp, jgp);
565+ auto dp3d_i = ekat::subview (dp3d_dyn, ie, igp, jgp);
566+ auto vtheta_dp_i = ekat::subview (vtheta_dp_dyn, ie, igp, jgp);
567+ auto qv_i = ekat::subview (Q_dyn, ie, 0 , igp, jgp);
568+ auto temperature_i = ekat::subview (temperature, ie, igp, jgp);
569+ auto u_i = ekat::subview (v_dyn, ie, 0 , igp, jgp);
570+ auto v_i = ekat::subview (v_dyn, ie, 1 , igp, jgp);
571+
572+ // Compute reference pressures and layer thickness.
573+ // TODO: Allow geometry data to allocate packsize
574+ auto s_pmid = ekat::scalarize (pmid);
575+ Kokkos::parallel_for (Kokkos::TeamVectorRange (team, total_levels), [&](const int & k) {
576+ s_pmid (k) = hyam (k)*ps0 + hybm (k)*ps_i;
577+ });
578+ team.team_barrier ();
579+
580+ Kokkos::parallel_for (Kokkos::ThreadVectorRange (team, NLEV), [&](const int & k) {
581+ if (iop_nudge_tq) {
582+ // Restrict nudging of T and qv to certain levels if requested by user
583+ // IOP pressure variable is in unitis of [Pa], while iop_nudge_tq_low/high
584+ // is in units of [hPa], thus convert iop_nudge_tq_low/high
585+ Mask nudge_level (false );
586+ int max_size = hyam.size ();
587+ for (int lev=k*Pack::n, p = 0 ; p < Pack::n && lev < max_size; ++lev, ++p) {
588+ const auto pressure_from_iop = hyam (lev)*ps0 + hybm (lev)*ps_iop;
589+ nudge_level.set (p, pressure_from_iop <= iop_nudge_tq_low*100
590+ and
591+ pressure_from_iop >= iop_nudge_tq_high*100 );
615592 }
616- });
593+
594+ qv_i (k).update (nudge_level, qv_mean (k) - qv_iop (k), -dt/rtau, 1.0 );
595+ temperature_i (k).update (nudge_level, t_mean (k) - t_iop (k), -dt/rtau, 1.0 );
596+
597+ // Convert updated temperature back to virtual potential temperature
598+ const auto th = PF::calculate_theta_from_T (temperature_i (k),pmid (k));
599+ vtheta_dp_i (k) = PF::calculate_virtual_temperature (th,qv_i (k))*dp3d_i (k);
600+ }
601+ if (iop_nudge_uv) {
602+ u_i (k).update (u_mean (k) - u_iop (k), -dt/rtau, 1.0 );
603+ v_i (k).update (v_mean (k) - v_iop (k), -dt/rtau, 1.0 );
604+ }
617605 });
606+
607+ // Release WS views
608+ ws.release_many_contiguous <1 >({&pmid});
618609 });
619610 }
620611}
0 commit comments