diff --git a/components/eam/src/physics/cam/gw/gw_convect.F90 b/components/eam/src/physics/cam/gw/gw_convect.F90 index 8e3027e33442..8d18ee483bca 100644 --- a/components/eam/src/physics/cam/gw/gw_convect.F90 +++ b/components/eam/src/physics/cam/gw/gw_convect.F90 @@ -17,6 +17,11 @@ module gw_convect public :: gw_convect_init public :: gw_beres_src +! Only public for bridging/testing +public :: gw_convect_project_winds +public :: gw_heating_depth +public :: gw_storm_speed +public :: gw_convect_gw_sources ! Dimension for heating depth. integer :: maxh @@ -42,14 +47,19 @@ subroutine gw_convect_init( plev_src_wind, mfcc_in, errstring) real(r8), intent(in) :: mfcc_in(:,:,:) ! Source spectra to keep as table character(len=*), intent(out) :: errstring ! Report any errors from this routine integer :: ierr +#ifndef SCREAM_CONFIG_IS_CMAKE integer :: k +#endif errstring = "" -#ifndef SCREAM_CONFIG_IS_CMAKE +#ifdef SCREAM_CONFIG_IS_CMAKE + ! Just set k_src_wind to pver + k_src_wind = pver +#else do k = 0, pver - if ( pref_edge(k+1) < plev_src_wind ) k_src_wind = k+1 - end do + if ( pref_edge(k+1) < plev_src_wind ) k_src_wind = k+1 + end do #endif #ifndef SCREAM_CONFIG_IS_CMAKE diff --git a/components/eamxx/scripts/gen_boiler.py b/components/eamxx/scripts/gen_boiler.py index c3897cded416..6d0908521c1c 100644 --- a/components/eamxx/scripts/gen_boiler.py +++ b/components/eamxx/scripts/gen_boiler.py @@ -2494,10 +2494,14 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): }""" _, _, _, _, scalars, real_data, int_data, bool_data = group_data(arg_data, filter_out_intent="in") - check_scalars, check_arrays = "", "" + check_scalars, check_arrays, scalar_comments = "", "", "" for scalar in scalars: check_scalars += f" REQUIRE(d_baseline.{scalar[0]} == d_test.{scalar[0]});\n" + _, _, _, all_dims, input_scalars, _, _, _ = group_data(arg_data, filter_out_intent="out") + all_scalar_inputs = all_dims + [scalar_name for scalar_name, _ in input_scalars] + scalar_comments = "// " + ", ".join(all_scalar_inputs) + if has_array: c2f_transpose_code = "" if not need_transpose else \ """ @@ -2531,6 +2535,8 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): // Set up inputs {data_struct} baseline_data[] = {{ // TODO + {scalar_comments} + {data_struct}(), }}; static constexpr Int num_runs = sizeof(baseline_data) / sizeof({data_struct});{gen_random} @@ -2539,6 +2545,7 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): // inout data is in original state {data_struct} test_data[] = {{ // TODO + {data_struct}(baseline_data[0]), }}; // Read baseline data @@ -2567,6 +2574,7 @@ def gen_cxx_bfb_unit_impl(self, phys, sub, force_arg_data=None): }} }} }} // run_bfb""".format(data_struct=data_struct, + scalar_comments=scalar_comments, sub=sub, gen_random=gen_random, c2f_transpose_code=c2f_transpose_code, diff --git a/components/eamxx/src/physics/gw/CMakeLists.txt b/components/eamxx/src/physics/gw/CMakeLists.txt index de6c7c453cd3..f46a23a3a1b4 100644 --- a/components/eamxx/src/physics/gw/CMakeLists.txt +++ b/components/eamxx/src/physics/gw/CMakeLists.txt @@ -23,6 +23,14 @@ if (NOT EAMXX_ENABLE_GPU OR Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE OR Kokkos eti/gw_gw_front_project_winds.cpp eti/gw_gw_front_gw_sources.cpp eti/gw_gw_cm_src.cpp + eti/gw_gw_convect_project_winds.cpp + eti/gw_gw_heating_depth.cpp + eti/gw_gw_storm_speed.cpp + eti/gw_gw_convect_gw_sources.cpp + eti/gw_gw_beres_src.cpp + eti/gw_gw_ediff.cpp + eti/gw_gw_diff_tend.cpp + eti/gw_gw_oro_src.cpp ) # GW ETI SRCS endif() diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_beres_src.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_beres_src.cpp new file mode 100644 index 000000000000..407424dc0f48 --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_beres_src.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_beres_src_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_beres_src on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_convect_gw_sources.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_convect_gw_sources.cpp new file mode 100644 index 000000000000..936b882db8d9 --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_convect_gw_sources.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_convect_gw_sources_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_convect_gw_sources on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_convect_project_winds.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_convect_project_winds.cpp new file mode 100644 index 000000000000..41265c4e0a5e --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_convect_project_winds.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_convect_project_winds_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_convect_project_winds on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_diff_tend.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_diff_tend.cpp new file mode 100644 index 000000000000..03578f3655de --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_diff_tend.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_diff_tend_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_diff_tend on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_ediff.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_ediff.cpp new file mode 100644 index 000000000000..56e5c5a4cb28 --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_ediff.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_ediff_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_ediff on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_heating_depth.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_heating_depth.cpp new file mode 100644 index 000000000000..281ed672f520 --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_heating_depth.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_heating_depth_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_heating_depth on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_oro_src.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_oro_src.cpp new file mode 100644 index 000000000000..725dddbe6b61 --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_oro_src.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_oro_src_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_oro_src on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/eti/gw_gw_storm_speed.cpp b/components/eamxx/src/physics/gw/eti/gw_gw_storm_speed.cpp new file mode 100644 index 000000000000..34ec80431783 --- /dev/null +++ b/components/eamxx/src/physics/gw/eti/gw_gw_storm_speed.cpp @@ -0,0 +1,14 @@ +#include "impl/gw_gw_storm_speed_impl.hpp" + +namespace scream { +namespace gw { + +/* + * Explicit instantiation for doing gw_storm_speed on Reals using the + * default device. + */ + +template struct Functions; + +} // namespace gw +} // namespace scream diff --git a/components/eamxx/src/physics/gw/gw_functions.hpp b/components/eamxx/src/physics/gw/gw_functions.hpp index b64e0b1aa1fd..4128207b8b20 100644 --- a/components/eamxx/src/physics/gw/gw_functions.hpp +++ b/components/eamxx/src/physics/gw/gw_functions.hpp @@ -282,6 +282,160 @@ struct Functions const uview_1d& xv, const uview_1d& yv, const uview_1d& c); + + KOKKOS_FUNCTION + static void gw_convect_project_winds( + // Inputs + const Int& pver, + const Int& ncol, + const uview_1d& u, + const uview_1d& v, + // Outputs + const uview_1d& xv, + const uview_1d& yv, + const uview_1d& ubm, + const uview_1d& ubi); + + KOKKOS_FUNCTION + static void gw_heating_depth( + // Inputs + const Int& pver, + const Int& ncol, + const Spack& maxq0_conversion_factor, + const Spack& hdepth_scaling_factor, + const bool& use_gw_convect_old, + const uview_1d& zm, + const uview_1d& netdt, + // Outputs + const uview_1d& mini, + const uview_1d& maxi, + const uview_1d& hdepth, + const uview_1d& maxq0_out, + const uview_1d& maxq0); + + KOKKOS_FUNCTION + static void gw_storm_speed( + // Inputs + const Int& pver, + const Int& ncol, + const Spack& storm_speed_min, + const uview_1d& ubm, + const uview_1d& mini, + const uview_1d& maxi, + // Outputs + const uview_1d& storm_speed, + const uview_1d& uh, + const uview_1d& umin, + const uview_1d& umax); + + KOKKOS_FUNCTION + static void gw_convect_gw_sources( + // Inputs + const Int& pver, + const Int& pgwv, + const Int& ncol, + const Int& ngwv, + const uview_1d& lat, + const Spack& hdepth_min, + const uview_1d& hdepth, + const uview_1d& mini, + const uview_1d& maxi, + const uview_1d& netdt, + const uview_1d& uh, + const uview_1d& storm_speed, + const uview_1d& maxq0, + const uview_1d& umin, + const uview_1d& umax, + // Outputs + const uview_1d& tau); + + KOKKOS_FUNCTION + static void gw_beres_src( + // Inputs + const Int& pver, + const Int& pgwv, + const Int& ncol, + const Int& ngwv, + const uview_1d& lat, + const uview_1d& u, + const uview_1d& v, + const uview_1d& netdt, + const uview_1d& zm, + // Outputs + const uview_1d& src_level, + const uview_1d& tend_level, + const uview_1d& tau, + const uview_1d& ubm, + const uview_1d& ubi, + const uview_1d& xv, + const uview_1d& yv, + const uview_1d& c, + const uview_1d& hdepth, + const uview_1d& maxq0_out, + // Inputs + const Spack& maxq0_conversion_factor, + const Spack& hdepth_scaling_factor, + const Spack& hdepth_min, + const Spack& storm_speed_min, + const bool& use_gw_convect_old); + + KOKKOS_FUNCTION + static void gw_ediff( + // Inputs + const Int& ncol, + const Int& pver, + const Int& ngwv, + const Int& kbot, + const Int& ktop, + const uview_1d& tend_level, + const uview_1d& gwut, + const uview_1d& ubm, + const uview_1d& nm, + const uview_1d& rho, + const Spack& dt, + const Spack& gravit, + const uview_1d& pmid, + const uview_1d& rdpm, + const uview_1d& c, + // Outputs + const uview_1d& egwdffi); + + KOKKOS_FUNCTION + static void gw_diff_tend( + // Inputs + const Int& ncol, + const Int& pver, + const Int& kbot, + const Int& ktop, + const uview_1d& q, + const Spack& dt, + // Outputs + const uview_1d& dq); + + KOKKOS_FUNCTION + static void gw_oro_src( + // Inputs + const Int& pver, + const Int& pgwv, + const Int& ncol, + const uview_1d& u, + const uview_1d& v, + const uview_1d& t, + const uview_1d& sgh, + const uview_1d& pmid, + const uview_1d& pint, + const uview_1d& dpm, + const uview_1d& zm, + const uview_1d& nm, + // Outputs + const uview_1d& src_level, + const uview_1d& tend_level, + const uview_1d& tau, + const uview_1d& ubm, + const uview_1d& ubi, + const uview_1d& xv, + const uview_1d& yv, + const uview_1d& c); }; // struct Functions } // namespace gw @@ -301,5 +455,13 @@ struct Functions # include "impl/gw_gw_front_project_winds_impl.hpp" # include "impl/gw_gw_front_gw_sources_impl.hpp" # include "impl/gw_gw_cm_src_impl.hpp" +# include "impl/gw_gw_convect_project_winds_impl.hpp" +# include "impl/gw_gw_heating_depth_impl.hpp" +# include "impl/gw_gw_storm_speed_impl.hpp" +# include "impl/gw_gw_convect_gw_sources_impl.hpp" +# include "impl/gw_gw_beres_src_impl.hpp" +# include "impl/gw_gw_ediff_impl.hpp" +# include "impl/gw_gw_diff_tend_impl.hpp" +# include "impl/gw_gw_oro_src_impl.hpp" #endif // GPU && !KOKKOS_ENABLE_*_RELOCATABLE_DEVICE_CODE #endif // P3_FUNCTIONS_HPP diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_beres_src_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_beres_src_impl.hpp new file mode 100644 index 000000000000..3318c3f7d94d --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_beres_src_impl.hpp @@ -0,0 +1,52 @@ +#ifndef GW_GW_BERES_SRC_IMPL_HPP +#define GW_GW_BERES_SRC_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_beres_src. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_beres_src( +// Inputs +const Int& pver, +const Int& pgwv, +const Int& ncol, +const Int& ngwv, +const uview_1d& lat, +const uview_1d& u, +const uview_1d& v, +const uview_1d& netdt, +const uview_1d& zm, +// Outputs +const uview_1d& src_level, +const uview_1d& tend_level, +const uview_1d& tau, +const uview_1d& ubm, +const uview_1d& ubi, +const uview_1d& xv, +const uview_1d& yv, +const uview_1d& c, +const uview_1d& hdepth, +const uview_1d& maxq0_out, +// Inputs +const Spack& maxq0_conversion_factor, +const Spack& hdepth_scaling_factor, +const Spack& hdepth_min, +const Spack& storm_speed_min, +const bool& use_gw_convect_old) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_convect_gw_sources_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_convect_gw_sources_impl.hpp new file mode 100644 index 000000000000..24b2ba034c37 --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_convect_gw_sources_impl.hpp @@ -0,0 +1,43 @@ +#ifndef GW_GW_CONVECT_GW_SOURCES_IMPL_HPP +#define GW_GW_CONVECT_GW_SOURCES_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_convect_gw_sources. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_convect_gw_sources( +// Inputs +const Int& pver, +const Int& pgwv, +const Int& ncol, +const Int& ngwv, +const uview_1d& lat, +const Spack& hdepth_min, +const uview_1d& hdepth, +const uview_1d& mini, +const uview_1d& maxi, +const uview_1d& netdt, +const uview_1d& uh, +const uview_1d& storm_speed, +const uview_1d& maxq0, +const uview_1d& umin, +const uview_1d& umax, +// Outputs +const uview_1d& tau) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_convect_project_winds_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_convect_project_winds_impl.hpp new file mode 100644 index 000000000000..2939a41ddc82 --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_convect_project_winds_impl.hpp @@ -0,0 +1,35 @@ +#ifndef GW_GW_CONVECT_PROJECT_WINDS_IMPL_HPP +#define GW_GW_CONVECT_PROJECT_WINDS_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_convect_project_winds. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_convect_project_winds( +// Inputs +const Int& pver, +const Int& ncol, +const uview_1d& u, +const uview_1d& v, +// Outputs +const uview_1d& xv, +const uview_1d& yv, +const uview_1d& ubm, +const uview_1d& ubi) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_diff_tend_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_diff_tend_impl.hpp new file mode 100644 index 000000000000..8823fa452f40 --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_diff_tend_impl.hpp @@ -0,0 +1,34 @@ +#ifndef GW_GW_DIFF_TEND_IMPL_HPP +#define GW_GW_DIFF_TEND_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_diff_tend. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_diff_tend( +// Inputs +const Int& ncol, +const Int& pver, +const Int& kbot, +const Int& ktop, +const uview_1d& q, +const Spack& dt, +// Outputs +const uview_1d& dq) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_ediff_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_ediff_impl.hpp new file mode 100644 index 000000000000..ca92ff728273 --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_ediff_impl.hpp @@ -0,0 +1,43 @@ +#ifndef GW_GW_EDIFF_IMPL_HPP +#define GW_GW_EDIFF_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_ediff. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_ediff( +// Inputs +const Int& ncol, +const Int& pver, +const Int& ngwv, +const Int& kbot, +const Int& ktop, +const uview_1d& tend_level, +const uview_1d& gwut, +const uview_1d& ubm, +const uview_1d& nm, +const uview_1d& rho, +const Spack& dt, +const Spack& gravit, +const uview_1d& pmid, +const uview_1d& rdpm, +const uview_1d& c, +// Outputs +const uview_1d& egwdffi) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_heating_depth_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_heating_depth_impl.hpp new file mode 100644 index 000000000000..a3fbc97a3728 --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_heating_depth_impl.hpp @@ -0,0 +1,39 @@ +#ifndef GW_GW_HEATING_DEPTH_IMPL_HPP +#define GW_GW_HEATING_DEPTH_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_heating_depth. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_heating_depth( +// Inputs +const Int& pver, +const Int& ncol, +const Spack& maxq0_conversion_factor, +const Spack& hdepth_scaling_factor, +const bool& use_gw_convect_old, +const uview_1d& zm, +const uview_1d& netdt, +// Outputs +const uview_1d& mini, +const uview_1d& maxi, +const uview_1d& hdepth, +const uview_1d& maxq0_out, +const uview_1d& maxq0) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_oro_src_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_oro_src_impl.hpp new file mode 100644 index 000000000000..05f5b54818e5 --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_oro_src_impl.hpp @@ -0,0 +1,47 @@ +#ifndef GW_GW_ORO_SRC_IMPL_HPP +#define GW_GW_ORO_SRC_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_oro_src. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_oro_src( +// Inputs +const Int& pver, +const Int& pgwv, +const Int& ncol, +const uview_1d& u, +const uview_1d& v, +const uview_1d& t, +const uview_1d& sgh, +const uview_1d& pmid, +const uview_1d& pint, +const uview_1d& dpm, +const uview_1d& zm, +const uview_1d& nm, +// Outputs +const uview_1d& src_level, +const uview_1d& tend_level, +const uview_1d& tau, +const uview_1d& ubm, +const uview_1d& ubi, +const uview_1d& xv, +const uview_1d& yv, +const uview_1d& c) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/impl/gw_gw_storm_speed_impl.hpp b/components/eamxx/src/physics/gw/impl/gw_gw_storm_speed_impl.hpp new file mode 100644 index 000000000000..490a6f777e2a --- /dev/null +++ b/components/eamxx/src/physics/gw/impl/gw_gw_storm_speed_impl.hpp @@ -0,0 +1,37 @@ +#ifndef GW_GW_STORM_SPEED_IMPL_HPP +#define GW_GW_STORM_SPEED_IMPL_HPP + +#include "gw_functions.hpp" // for ETI only but harmless for GPU + +namespace scream { +namespace gw { + +/* + * Implementation of gw gw_storm_speed. Clients should NOT + * #include this file, but include gw_functions.hpp instead. + */ + +template +KOKKOS_FUNCTION +void Functions::gw_storm_speed( +// Inputs +const Int& pver, +const Int& ncol, +const Spack& storm_speed_min, +const uview_1d& ubm, +const uview_1d& mini, +const uview_1d& maxi, +// Outputs +const uview_1d& storm_speed, +const uview_1d& uh, +const uview_1d& umin, +const uview_1d& umax) +{ + // TODO + // Note, argument types may need tweaking. Generator is not always able to tell what needs to be packed +} + +} // namespace gw +} // namespace scream + +#endif diff --git a/components/eamxx/src/physics/gw/tests/CMakeLists.txt b/components/eamxx/src/physics/gw/tests/CMakeLists.txt index 7e6a523687a4..87071ad703c7 100644 --- a/components/eamxx/src/physics/gw/tests/CMakeLists.txt +++ b/components/eamxx/src/physics/gw/tests/CMakeLists.txt @@ -13,6 +13,14 @@ set(GW_TESTS_SRCS gw_gw_front_project_winds_tests.cpp gw_gw_front_gw_sources_tests.cpp gw_gw_cm_src_tests.cpp + gw_gw_convect_project_winds_tests.cpp + gw_gw_heating_depth_tests.cpp + gw_gw_storm_speed_tests.cpp + gw_gw_convect_gw_sources_tests.cpp + gw_gw_beres_src_tests.cpp + gw_gw_ediff_tests.cpp + gw_gw_diff_tend_tests.cpp + gw_gw_oro_src_tests.cpp ) # GW_TESTS_SRCS # All tests should understand the same baseline args diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_beres_src_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_beres_src_tests.cpp new file mode 100644 index 000000000000..b5eb862ecaea --- /dev/null +++ b/components/eamxx/src/physics/gw/tests/gw_gw_beres_src_tests.cpp @@ -0,0 +1,153 @@ +#include "catch2/catch.hpp" + +#include "share/eamxx_types.hpp" +#include "ekat/ekat_pack.hpp" +#include "ekat/kokkos/ekat_kokkos_utils.hpp" +#include "physics/gw/gw_functions.hpp" +#include "physics/gw/tests/infra/gw_test_data.hpp" + +#include "gw_unit_tests_common.hpp" + +namespace scream { +namespace gw { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestGwBeresSrc : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up convect init data + GwConvectInitData front_init_data[] = { + // maxh, maxuh, plev_src_wnd, init + GwConvectInitData( 10, 20, .10, init_data[0]), + GwConvectInitData( 11, 21, .11, init_data[1]), + GwConvectInitData( 12, 22, .12, init_data[2]), + GwConvectInitData( 13, 23, .13, init_data[3]), + }; + + for (auto& d : front_init_data) { + d.randomize(engine); + } + + // Set up inputs + GwBeresSrcData baseline_data[] = { + // ncol, ngwv, maxq0_conversion_factor, hdepth_scaling_factor, hdepth_min, storm_speed_min, use_gw_convect_old + GwBeresSrcData(10, 20, 0.1, 0.2, 2000., 1., false, front_init_data[0]), + GwBeresSrcData(11, 21, 0.2, 0.3, 3000., 2., false, front_init_data[1]), + GwBeresSrcData(12, 22, 0.3, 0.4, 4000., 3., true, front_init_data[2]), + GwBeresSrcData(13, 23, 0.4, 0.5, 5000., 4., true, front_init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwBeresSrcData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine, { + {d.lat, {-1., 1.}}, + {d.netdt, {-1.432438750782E-04, 1.432438750782E-04}}, + {d.u, {-6.355356031720E+01, 2.735168920349E+01}}, + {d.v, {-5.154620900385E+00, 2.358902991534E+00}}, + {d.zm, {5.444482895112E+01, 6.240534656097E+04}}, + }); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwBeresSrcData test_data[] = { + GwBeresSrcData(baseline_data[0]), + GwBeresSrcData(baseline_data[1]), + GwBeresSrcData(baseline_data[2]), + GwBeresSrcData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_beres_src(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwBeresSrcData& d_baseline = baseline_data[i]; + GwBeresSrcData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.tau); ++k) { + REQUIRE(d_baseline.total(d_baseline.tau) == d_test.total(d_test.tau)); + REQUIRE(d_baseline.tau[k] == d_test.tau[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.ubm); ++k) { + REQUIRE(d_baseline.total(d_baseline.ubm) == d_test.total(d_test.ubm)); + REQUIRE(d_baseline.ubm[k] == d_test.ubm[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.ubi); ++k) { + REQUIRE(d_baseline.total(d_baseline.ubi) == d_test.total(d_test.ubi)); + REQUIRE(d_baseline.ubi[k] == d_test.ubi[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.xv); ++k) { + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.xv)); + REQUIRE(d_baseline.xv[k] == d_test.xv[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.yv)); + REQUIRE(d_baseline.yv[k] == d_test.yv[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.hdepth)); + REQUIRE(d_baseline.hdepth[k] == d_test.hdepth[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.maxq0_out)); + REQUIRE(d_baseline.maxq0_out[k] == d_test.maxq0_out[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.src_level)); + REQUIRE(d_baseline.src_level[k] == d_test.src_level[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.tend_level)); + REQUIRE(d_baseline.tend_level[k] == d_test.tend_level[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.c); ++k) { + REQUIRE(d_baseline.total(d_baseline.c) == d_test.total(d_test.c)); + REQUIRE(d_baseline.c[k] == d_test.c[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_beres_src_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwBeresSrc; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_convect_gw_sources_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_convect_gw_sources_tests.cpp new file mode 100644 index 000000000000..f7a5f9a88063 --- /dev/null +++ b/components/eamxx/src/physics/gw/tests/gw_gw_convect_gw_sources_tests.cpp @@ -0,0 +1,121 @@ +#include "catch2/catch.hpp" + +#include "share/eamxx_types.hpp" +#include "ekat/ekat_pack.hpp" +#include "ekat/kokkos/ekat_kokkos_utils.hpp" +#include "physics/gw/gw_functions.hpp" +#include "physics/gw/tests/infra/gw_test_data.hpp" + +#include "gw_unit_tests_common.hpp" + +namespace scream { +namespace gw { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestGwConvectGwSources : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up convect init data + GwConvectInitData front_init_data[] = { + // maxh, maxuh, plev_src_wnd, init + GwConvectInitData( 10, 20, .10, init_data[0]), + GwConvectInitData( 11, 21, .11, init_data[1]), + GwConvectInitData( 12, 22, .12, init_data[2]), + GwConvectInitData( 13, 23, .13, init_data[3]), + }; + + for (auto& d : front_init_data) { + d.randomize(engine); + } + + // Set up inputs + GwConvectGwSourcesData baseline_data[] = { + // ncol, ngwv, hdepth_min + GwConvectGwSourcesData(10, 20, 2000., front_init_data[0]), + GwConvectGwSourcesData(11, 21, 3000., front_init_data[1]), + GwConvectGwSourcesData(12, 22, 4000., front_init_data[2]), + GwConvectGwSourcesData(13, 23, 5000., front_init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwConvectGwSourcesData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwConvectGwSourcesData test_data[] = { + GwConvectGwSourcesData(baseline_data[0]), + GwConvectGwSourcesData(baseline_data[1]), + GwConvectGwSourcesData(baseline_data[2]), + GwConvectGwSourcesData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_convect_gw_sources(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwConvectGwSourcesData& d_baseline = baseline_data[i]; + GwConvectGwSourcesData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.tau); ++k) { + REQUIRE(d_baseline.total(d_baseline.tau) == d_test.total(d_test.tau)); + REQUIRE(d_baseline.tau[k] == d_test.tau[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_convect_gw_sources_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwConvectGwSources; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_convect_project_winds_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_convect_project_winds_tests.cpp new file mode 100644 index 000000000000..86dc71a6621f --- /dev/null +++ b/components/eamxx/src/physics/gw/tests/gw_gw_convect_project_winds_tests.cpp @@ -0,0 +1,130 @@ +#include "catch2/catch.hpp" + +#include "share/eamxx_types.hpp" +#include "ekat/ekat_pack.hpp" +#include "ekat/kokkos/ekat_kokkos_utils.hpp" +#include "physics/gw/gw_functions.hpp" +#include "physics/gw/tests/infra/gw_test_data.hpp" + +#include "gw_unit_tests_common.hpp" + +namespace scream { +namespace gw { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestGwConvectProjectWinds : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up convect init data + GwConvectInitData front_init_data[] = { + // maxh, maxuh, plev_src_wnd, init + GwConvectInitData( 10, 20, .10, init_data[0]), + GwConvectInitData( 11, 21, .11, init_data[1]), + GwConvectInitData( 12, 22, .12, init_data[2]), + GwConvectInitData( 13, 23, .13, init_data[3]), + }; + + for (auto& d : front_init_data) { + d.randomize(engine); + } + + // Set up inputs + GwConvectProjectWindsData baseline_data[] = { + GwConvectProjectWindsData(10, front_init_data[0]), + GwConvectProjectWindsData(11, front_init_data[1]), + GwConvectProjectWindsData(12, front_init_data[2]), + GwConvectProjectWindsData(13, front_init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwConvectProjectWindsData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwConvectProjectWindsData test_data[] = { + GwConvectProjectWindsData(baseline_data[0]), + GwConvectProjectWindsData(baseline_data[1]), + GwConvectProjectWindsData(baseline_data[2]), + GwConvectProjectWindsData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_convect_project_winds(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwConvectProjectWindsData& d_baseline = baseline_data[i]; + GwConvectProjectWindsData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.xv); ++k) { + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.xv)); + REQUIRE(d_baseline.xv[k] == d_test.xv[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.yv)); + REQUIRE(d_baseline.yv[k] == d_test.yv[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.ubm); ++k) { + REQUIRE(d_baseline.total(d_baseline.ubm) == d_test.total(d_test.ubm)); + REQUIRE(d_baseline.ubm[k] == d_test.ubm[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.ubi); ++k) { + REQUIRE(d_baseline.total(d_baseline.ubi) == d_test.total(d_test.ubi)); + REQUIRE(d_baseline.ubi[k] == d_test.ubi[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_convect_project_winds_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwConvectProjectWinds; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_diff_tend_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_diff_tend_tests.cpp new file mode 100644 index 000000000000..0b69b4513f27 --- /dev/null +++ b/components/eamxx/src/physics/gw/tests/gw_gw_diff_tend_tests.cpp @@ -0,0 +1,108 @@ +#include "catch2/catch.hpp" + +#include "share/eamxx_types.hpp" +#include "ekat/ekat_pack.hpp" +#include "ekat/kokkos/ekat_kokkos_utils.hpp" +#include "physics/gw/gw_functions.hpp" +#include "physics/gw/tests/infra/gw_test_data.hpp" + +#include "gw_unit_tests_common.hpp" + +namespace scream { +namespace gw { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestGwDiffTend : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up inputs + GwDiffTendData baseline_data[] = { + // ncol, kbot, ktop, dt + GwDiffTendData(5, 20, 59, 0.1, init_data[0]), + GwDiffTendData(6, 21, 58, 0.2, init_data[1]), + GwDiffTendData(7, 22, 57, 0.3, init_data[2]), + GwDiffTendData(8, 23, 56, 0.4, init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwDiffTendData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwDiffTendData test_data[] = { + GwDiffTendData(baseline_data[0]), + GwDiffTendData(baseline_data[1]), + GwDiffTendData(baseline_data[2]), + GwDiffTendData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_diff_tend(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwDiffTendData& d_baseline = baseline_data[i]; + GwDiffTendData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.dq); ++k) { + REQUIRE(d_baseline.total(d_baseline.dq) == d_test.total(d_test.dq)); + REQUIRE(d_baseline.dq[k] == d_test.dq[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_diff_tend_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwDiffTend; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_ediff_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_ediff_tests.cpp new file mode 100644 index 000000000000..e9d5baf26c03 --- /dev/null +++ b/components/eamxx/src/physics/gw/tests/gw_gw_ediff_tests.cpp @@ -0,0 +1,118 @@ +#include "catch2/catch.hpp" + +#include "share/eamxx_types.hpp" +#include "ekat/ekat_pack.hpp" +#include "ekat/kokkos/ekat_kokkos_utils.hpp" +#include "physics/gw/gw_functions.hpp" +#include "physics/gw/tests/infra/gw_test_data.hpp" + +#include "gw_unit_tests_common.hpp" + +namespace scream { +namespace gw { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestGwEdiff : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up inputs + GwEdiffData baseline_data[] = { + // ncol, ngwv, kbot, ktop, dt + GwEdiffData(5, 2, 20, 59, 0.1, init_data[0]), + GwEdiffData(6, 3, 21, 58, 0.2, init_data[1]), + GwEdiffData(7, 4, 22, 57, 0.3, init_data[2]), + GwEdiffData(8, 5, 23, 56, 0.4, init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwEdiffData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwEdiffData test_data[] = { + GwEdiffData(baseline_data[0]), + GwEdiffData(baseline_data[1]), + GwEdiffData(baseline_data[2]), + GwEdiffData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_ediff(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwEdiffData& d_baseline = baseline_data[i]; + GwEdiffData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.decomp_ca); ++k) { + REQUIRE(d_baseline.total(d_baseline.decomp_ca) == d_test.total(d_test.decomp_ca)); + REQUIRE(d_baseline.decomp_ca[k] == d_test.decomp_ca[k]); + REQUIRE(d_baseline.total(d_baseline.decomp_cc) == d_test.total(d_test.decomp_cc)); + REQUIRE(d_baseline.decomp_cc[k] == d_test.decomp_cc[k]); + REQUIRE(d_baseline.total(d_baseline.decomp_dnom) == d_test.total(d_test.decomp_dnom)); + REQUIRE(d_baseline.decomp_dnom[k] == d_test.decomp_dnom[k]); + REQUIRE(d_baseline.total(d_baseline.decomp_ze) == d_test.total(d_test.decomp_ze)); + REQUIRE(d_baseline.decomp_ze[k] == d_test.decomp_ze[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.egwdffi); ++k) { + REQUIRE(d_baseline.total(d_baseline.egwdffi) == d_test.total(d_test.egwdffi)); + REQUIRE(d_baseline.egwdffi[k] == d_test.egwdffi[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_ediff_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwEdiff; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_front_gw_sources_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_front_gw_sources_tests.cpp index 13ce6be47c8b..66761b278761 100644 --- a/components/eamxx/src/physics/gw/tests/gw_gw_front_gw_sources_tests.cpp +++ b/components/eamxx/src/physics/gw/tests/gw_gw_front_gw_sources_tests.cpp @@ -32,7 +32,7 @@ struct UnitWrap::UnitTest::TestGwFrontGwSources : public UnitWrap::UnitTest +struct UnitWrap::UnitTest::TestGwHeatingDepth : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up convect init data + GwConvectInitData front_init_data[] = { + // maxh, maxuh, plev_src_wnd, init + GwConvectInitData( 10, 20, .10, init_data[0]), + GwConvectInitData( 11, 21, .11, init_data[1]), + GwConvectInitData( 12, 22, .12, init_data[2]), + GwConvectInitData( 13, 23, .13, init_data[3]), + }; + + for (auto& d : front_init_data) { + d.randomize(engine); + } + + // Set up inputs + GwHeatingDepthData baseline_data[] = { + // TODO + // ncol, maxq0_conversion_factor, hdepth_scaling_factor, use_gw_convect_old + GwHeatingDepthData(10, 0.42, 0.43, false, front_init_data[0]), + GwHeatingDepthData(11, 0.43, 0.44, false, front_init_data[1]), + GwHeatingDepthData(12, 0.44, 0.45, true, front_init_data[2]), + GwHeatingDepthData(13, 0.45, 0.46, true, front_init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwHeatingDepthData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine, { {d.zm, {5000., 21000.}}, {d.netdt, {-1.432438750782E-04, 1.432438750782E-04}} }); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwHeatingDepthData test_data[] = { + // TODO + GwHeatingDepthData(baseline_data[0]), + GwHeatingDepthData(baseline_data[1]), + GwHeatingDepthData(baseline_data[2]), + GwHeatingDepthData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_heating_depth(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwHeatingDepthData& d_baseline = baseline_data[i]; + GwHeatingDepthData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.hdepth); ++k) { + REQUIRE(d_baseline.total(d_baseline.hdepth) == d_test.total(d_test.hdepth)); + REQUIRE(d_baseline.hdepth[k] == d_test.hdepth[k]); + REQUIRE(d_baseline.total(d_baseline.hdepth) == d_test.total(d_test.maxq0_out)); + REQUIRE(d_baseline.maxq0_out[k] == d_test.maxq0_out[k]); + REQUIRE(d_baseline.total(d_baseline.hdepth) == d_test.total(d_test.maxq0)); + REQUIRE(d_baseline.maxq0[k] == d_test.maxq0[k]); + REQUIRE(d_baseline.total(d_baseline.hdepth) == d_test.total(d_test.mini)); + REQUIRE(d_baseline.mini[k] == d_test.mini[k]); + REQUIRE(d_baseline.total(d_baseline.hdepth) == d_test.total(d_test.maxi)); + REQUIRE(d_baseline.maxi[k] == d_test.maxi[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_heating_depth_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwHeatingDepth; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_oro_src_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_oro_src_tests.cpp new file mode 100644 index 000000000000..209018804014 --- /dev/null +++ b/components/eamxx/src/physics/gw/tests/gw_gw_oro_src_tests.cpp @@ -0,0 +1,130 @@ +#include "catch2/catch.hpp" + +#include "share/eamxx_types.hpp" +#include "ekat/ekat_pack.hpp" +#include "ekat/kokkos/ekat_kokkos_utils.hpp" +#include "physics/gw/gw_functions.hpp" +#include "physics/gw/tests/infra/gw_test_data.hpp" + +#include "gw_unit_tests_common.hpp" + +namespace scream { +namespace gw { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestGwOroSrc : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up inputs + GwOroSrcData baseline_data[] = { + // ncol + GwOroSrcData(5, init_data[0]), + GwOroSrcData(6, init_data[1]), + GwOroSrcData(7, init_data[2]), + GwOroSrcData(8, init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwOroSrcData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwOroSrcData test_data[] = { + GwOroSrcData(baseline_data[0]), + GwOroSrcData(baseline_data[1]), + GwOroSrcData(baseline_data[2]), + GwOroSrcData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_oro_src(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwOroSrcData& d_baseline = baseline_data[i]; + GwOroSrcData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.tau); ++k) { + REQUIRE(d_baseline.total(d_baseline.tau) == d_test.total(d_test.tau)); + REQUIRE(d_baseline.tau[k] == d_test.tau[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.ubm); ++k) { + REQUIRE(d_baseline.total(d_baseline.ubm) == d_test.total(d_test.ubm)); + REQUIRE(d_baseline.ubm[k] == d_test.ubm[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.ubi); ++k) { + REQUIRE(d_baseline.total(d_baseline.ubi) == d_test.total(d_test.ubi)); + REQUIRE(d_baseline.ubi[k] == d_test.ubi[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.xv); ++k) { + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.xv)); + REQUIRE(d_baseline.xv[k] == d_test.xv[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.yv)); + REQUIRE(d_baseline.yv[k] == d_test.yv[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.src_level)); + REQUIRE(d_baseline.src_level[k] == d_test.src_level[k]); + REQUIRE(d_baseline.total(d_baseline.xv) == d_test.total(d_test.tend_level)); + REQUIRE(d_baseline.tend_level[k] == d_test.tend_level[k]); + } + for (Int k = 0; k < d_baseline.total(d_baseline.c); ++k) { + REQUIRE(d_baseline.total(d_baseline.c) == d_test.total(d_test.c)); + REQUIRE(d_baseline.c[k] == d_test.c[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_oro_src_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwOroSrc; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/gw_gw_storm_speed_tests.cpp b/components/eamxx/src/physics/gw/tests/gw_gw_storm_speed_tests.cpp new file mode 100644 index 000000000000..528b4d81d03f --- /dev/null +++ b/components/eamxx/src/physics/gw/tests/gw_gw_storm_speed_tests.cpp @@ -0,0 +1,127 @@ +#include "catch2/catch.hpp" + +#include "share/eamxx_types.hpp" +#include "ekat/ekat_pack.hpp" +#include "ekat/kokkos/ekat_kokkos_utils.hpp" +#include "physics/gw/gw_functions.hpp" +#include "physics/gw/tests/infra/gw_test_data.hpp" + +#include "gw_unit_tests_common.hpp" + +namespace scream { +namespace gw { +namespace unit_test { + +template +struct UnitWrap::UnitTest::TestGwStormSpeed : public UnitWrap::UnitTest::Base { + + void run_bfb() + { + auto engine = Base::get_engine(); + + // Set up init data + GwInit init_data[] = { + // pver, pgwv, dc, orog_only, molec_diff, tau_0_ubc, nbot_molec, ktop, kbotbg, fcrit2, kwv + GwInit( 72, 20, 0.75, false, false, false, 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , false, true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, false, true , true , 16, 60, 16, .67, 6.28e-5), + GwInit( 72, 20, 0.75, true , true , false, 16, 60, 16, .67, 6.28e-5), + }; + + for (auto& d : init_data) { + d.randomize(engine); + } + + // Set up convect init data + GwConvectInitData front_init_data[] = { + // maxh, maxuh, plev_src_wnd, init + GwConvectInitData( 10, 20, .10, init_data[0]), + GwConvectInitData( 11, 21, .11, init_data[1]), + GwConvectInitData( 12, 22, .12, init_data[2]), + GwConvectInitData( 13, 23, .13, init_data[3]), + }; + + for (auto& d : front_init_data) { + d.randomize(engine); + } + + // Set up inputs + GwStormSpeedData baseline_data[] = { + // ncol, storm_speed_min + GwStormSpeedData(10, .5, front_init_data[0]), + GwStormSpeedData(11, 1.5, front_init_data[1]), + GwStormSpeedData(12, 2.5, front_init_data[2]), + GwStormSpeedData(13, 3.5, front_init_data[3]), + }; + + static constexpr Int num_runs = sizeof(baseline_data) / sizeof(GwStormSpeedData); + + // Generate random input data + // Alternatively, you can use the baseline_data construtors/initializer lists to hardcode data + for (auto& d : baseline_data) { + d.randomize(engine, { {d.mini, {10, 20}}, {d.maxi, {40, 50}}, {d.ubm, {5., 20.}} }); + } + + // Create copies of data for use by test. Needs to happen before read calls so that + // inout data is in original state + GwStormSpeedData test_data[] = { + GwStormSpeedData(baseline_data[0]), + GwStormSpeedData(baseline_data[1]), + GwStormSpeedData(baseline_data[2]), + GwStormSpeedData(baseline_data[3]), + }; + + // Read baseline data + if (this->m_baseline_action == COMPARE) { + for (auto& d : baseline_data) { + d.read(Base::m_fid); + } + } + + // Get data from test + for (auto& d : test_data) { + gw_storm_speed(d); + } + + // Verify BFB results, all data should be in C layout + if (SCREAM_BFB_TESTING && this->m_baseline_action == COMPARE) { + for (Int i = 0; i < num_runs; ++i) { + GwStormSpeedData& d_baseline = baseline_data[i]; + GwStormSpeedData& d_test = test_data[i]; + for (Int k = 0; k < d_baseline.total(d_baseline.uh); ++k) { + REQUIRE(d_baseline.total(d_baseline.uh) == d_test.total(d_test.uh)); + REQUIRE(d_baseline.uh[k] == d_test.uh[k]); + REQUIRE(d_baseline.total(d_baseline.uh) == d_test.total(d_test.umin)); + REQUIRE(d_baseline.umin[k] == d_test.umin[k]); + REQUIRE(d_baseline.total(d_baseline.uh) == d_test.total(d_test.umax)); + REQUIRE(d_baseline.umax[k] == d_test.umax[k]); + REQUIRE(d_baseline.total(d_baseline.uh) == d_test.total(d_test.storm_speed)); + REQUIRE(d_baseline.storm_speed[k] == d_test.storm_speed[k]); + } + + } + } + else if (this->m_baseline_action == GENERATE) { + for (Int i = 0; i < num_runs; ++i) { + test_data[i].write(Base::m_fid); + } + } + } // run_bfb + +}; + +} // namespace unit_test +} // namespace gw +} // namespace scream + +namespace { + +TEST_CASE("gw_storm_speed_bfb", "[gw]") +{ + using TestStruct = scream::gw::unit_test::UnitWrap::UnitTest::TestGwStormSpeed; + + TestStruct t; + t.run_bfb(); +} + +} // empty namespace diff --git a/components/eamxx/src/physics/gw/tests/infra/gw_iso_c.f90 b/components/eamxx/src/physics/gw/tests/infra/gw_iso_c.f90 index 7dc4ca33bd83..43ee4e2ee248 100644 --- a/components/eamxx/src/physics/gw/tests/infra/gw_iso_c.f90 +++ b/components/eamxx/src/physics/gw/tests/infra/gw_iso_c.f90 @@ -192,4 +192,165 @@ subroutine gw_cm_src_c(ncol, ngwv, kbot, u, v, frontgf, src_level, tend_level, t call gw_cm_src(ncol, ngwv, kbot, u, v, frontgf, src_level, tend_level, tau, ubm, ubi, xv, yv, c) end subroutine gw_cm_src_c + + subroutine gw_convect_init_c(maxh, maxuh, plev_src_wind, mfcc_in) bind(C) + use gw_common, only : pgwv + use gw_convect, only : gw_convect_init + + integer(kind=c_int) , value, intent(in) :: maxh, maxuh + real(kind=c_real) , value, intent(in) :: plev_src_wind + real(kind=c_real) , intent(in), dimension(maxh, -maxuh:maxuh, -pgwv:pgwv) :: mfcc_in + + character(len=128) :: errstring + + call gw_convect_init(plev_src_wind, mfcc_in, errstring) + end subroutine gw_convect_init_c + + subroutine gw_convect_project_winds_c(ncol, u, v, xv, yv, ubm, ubi) bind(C) + use gw_common, only : pver + use gw_convect, only : gw_convect_project_winds + + integer(kind=c_int) , value, intent(in) :: ncol + real(kind=c_real) , intent(in), dimension(ncol, pver) :: u, v + real(kind=c_real) , intent(out), dimension(ncol) :: xv, yv + real(kind=c_real) , intent(out), dimension(ncol, pver) :: ubm + real(kind=c_real) , intent(out), dimension(ncol, 0:pver) :: ubi + + call gw_convect_project_winds(ncol, u, v, xv, yv, ubm, ubi) + end subroutine gw_convect_project_winds_c + + subroutine gw_heating_depth_c(ncol, maxq0_conversion_factor, hdepth_scaling_factor, use_gw_convect_old, zm, netdt, mini, maxi, hdepth, maxq0_out, maxq0) bind(C) + use gw_common, only : pver + use gw_convect, only : gw_heating_depth + + integer(kind=c_int) , value, intent(in) :: ncol + real(kind=c_real) , value, intent(in) :: maxq0_conversion_factor, hdepth_scaling_factor + logical(kind=c_bool) , value, intent(in) :: use_gw_convect_old + real(kind=c_real) , intent(in), dimension(ncol, pver) :: zm + real(kind=c_real) , intent(in), dimension(ncol, pver) :: netdt + integer(kind=c_int) , intent(out), dimension(ncol) :: mini, maxi + real(kind=c_real) , intent(out), dimension(ncol) :: hdepth, maxq0_out, maxq0 + + call gw_heating_depth(ncol, maxq0_conversion_factor, hdepth_scaling_factor, use_gw_convect_old, zm, netdt, mini, maxi, hdepth, maxq0_out, maxq0) + end subroutine gw_heating_depth_c + + subroutine gw_storm_speed_c(ncol, storm_speed_min, ubm, mini, maxi, storm_speed, uh, umin, umax) bind(C) + use gw_common, only : pver + use gw_convect, only : gw_storm_speed + + integer(kind=c_int) , value, intent(in) :: ncol + real(kind=c_real) , value, intent(in) :: storm_speed_min + real(kind=c_real) , intent(in), dimension(ncol, pver) :: ubm + integer(kind=c_int) , intent(in), dimension(ncol) :: mini, maxi + integer(kind=c_int) , intent(out), dimension(ncol) :: storm_speed + real(kind=c_real) , intent(out), dimension(ncol) :: uh, umin, umax + + call gw_storm_speed(ncol, storm_speed_min, ubm, mini, maxi, storm_speed, uh, umin, umax) + end subroutine gw_storm_speed_c + + subroutine gw_convect_gw_sources_c(ncol, ngwv, lat, hdepth_min, hdepth, mini, maxi, netdt, uh, storm_speed, maxq0, umin, umax, tau) bind(C) + use gw_common, only : pver, pgwv + use gw_convect, only : gw_convect_gw_sources + + integer(kind=c_int) , value, intent(in) :: ncol, ngwv + real(kind=c_real) , intent(in), dimension(ncol) :: lat, hdepth, uh, maxq0, umin, umax + real(kind=c_real) , value, intent(in) :: hdepth_min + integer(kind=c_int) , intent(in), dimension(ncol) :: mini, maxi, storm_speed + real(kind=c_real) , intent(in), dimension(ncol, pver) :: netdt + real(kind=c_real) , intent(out), dimension(ncol, -pgwv:pgwv, 0:pver) :: tau + + call gw_convect_gw_sources(ncol, ngwv, lat, hdepth_min, hdepth, mini, maxi, netdt, uh, storm_speed, maxq0, umin, umax, tau) + end subroutine gw_convect_gw_sources_c + + subroutine gw_beres_src_c(ncol, ngwv, lat, u, v, netdt, zm, src_level, tend_level, tau, ubm, ubi, xv, yv, c, hdepth, maxq0_out, maxq0_conversion_factor, hdepth_scaling_factor, hdepth_min, storm_speed_min, use_gw_convect_old) bind(C) + use gw_common, only : pver, pgwv + use gw_convect, only : gw_beres_src + + integer(kind=c_int) , value, intent(in) :: ncol, ngwv + real(kind=c_real) , intent(in), dimension(ncol) :: lat + real(kind=c_real) , intent(in), dimension(ncol, pver) :: u, v, zm + real(kind=c_real) , intent(in), dimension(ncol, pver) :: netdt + integer(kind=c_int) , intent(out), dimension(ncol) :: src_level, tend_level + real(kind=c_real) , intent(out), dimension(ncol, -pgwv:pgwv, 0:pver) :: tau + real(kind=c_real) , intent(out), dimension(ncol, pver) :: ubm + real(kind=c_real) , intent(out), dimension(ncol, 0:pver) :: ubi + real(kind=c_real) , intent(out), dimension(ncol) :: xv, yv, hdepth, maxq0_out + real(kind=c_real) , intent(out), dimension(ncol, -pgwv:pgwv) :: c + real(kind=c_real) , value, intent(in) :: maxq0_conversion_factor, hdepth_scaling_factor, hdepth_min, storm_speed_min + logical(kind=c_bool) , value, intent(in) :: use_gw_convect_old + + call gw_beres_src(ncol, ngwv, lat, u, v, netdt, zm, src_level, tend_level, tau, ubm, ubi, xv, yv, c, hdepth, maxq0_out, maxq0_conversion_factor, hdepth_scaling_factor, hdepth_min, storm_speed_min, use_gw_convect_old) + end subroutine gw_beres_src_c + + subroutine gw_ediff_c(ncol, ngwv, kbot, ktop, tend_level, gwut, ubm, nm, rho, dt, gravit, pmid, rdpm, c, egwdffi, decomp_ca, decomp_cc, decomp_dnom, decomp_ze) bind(C) + use gw_common, only : pver + use gw_diffusion, only : gw_ediff + use vdiff_lu_solver, only: lu_decomp + + integer(kind=c_int) , value, intent(in) :: ncol, ngwv, kbot, ktop + integer(kind=c_int) , intent(in), dimension(ncol) :: tend_level + real(kind=c_real) , intent(in), dimension(ncol, pver, -ngwv:ngwv) :: gwut + real(kind=c_real) , intent(in), dimension(ncol, pver) :: ubm, nm, pmid, rdpm + real(kind=c_real) , intent(in), dimension(ncol, pver+1) :: rho + real(kind=c_real) , value, intent(in) :: dt, gravit + real(kind=c_real) , intent(in), dimension(ncol, -ngwv:ngwv) :: c + real(kind=c_real) , intent(out), dimension(ncol, 0:pver) :: egwdffi + real(kind=c_real) , intent(out), dimension(ncol, pver) :: decomp_ca, decomp_cc, decomp_dnom, decomp_ze + + type(lu_decomp) :: decomp + + call gw_ediff(ncol, pver, ngwv, kbot, ktop, tend_level, gwut, ubm, nm, rho, dt, gravit, pmid, rdpm, c, egwdffi, decomp) + decomp_ca = decomp%ca + decomp_cc = decomp%cc + decomp_dnom = decomp%dnom + decomp_ze = decomp%ze + + call decomp%finalize() + + end subroutine gw_ediff_c + + subroutine gw_diff_tend_c(ncol, kbot, ktop, q, dt, decomp_ca, decomp_cc, decomp_dnom, decomp_ze, dq) bind(C) + use gw_common, only : pver + use gw_diffusion, only : gw_diff_tend + use vdiff_lu_solver, only: lu_decomp + + integer(kind=c_int) , value, intent(in) :: ncol, kbot, ktop + real(kind=c_real) , intent(in), dimension(ncol, pver) :: q + real(kind=c_real) , value, intent(in) :: dt + real(kind=c_real) , intent(in), dimension(ncol, pver) :: decomp_ca, decomp_cc, decomp_dnom, decomp_ze + real(kind=c_real) , intent(out), dimension(ncol, pver) :: dq + + type(lu_decomp) :: decomp + decomp = lu_decomp(ncol, pver) + + call gw_diff_tend(ncol, pver, kbot, ktop, q, dt, decomp, dq) + + call decomp%finalize() + end subroutine gw_diff_tend_c + + subroutine gw_oro_init_c() bind(C) + use gw_oro, only : gw_oro_init + + character(len=128) :: errstring + + call gw_oro_init(errstring) + end subroutine gw_oro_init_c + + subroutine gw_oro_src_c(ncol, u, v, t, sgh, pmid, pint, dpm, zm, nm, src_level, tend_level, tau, ubm, ubi, xv, yv, c) bind(C) + use gw_common, only : pver, pgwv + use gw_oro, only : gw_oro_src + + integer(kind=c_int) , value, intent(in) :: ncol + real(kind=c_real) , intent(in), dimension(ncol, pver) :: u, v, t, pmid, dpm, zm, nm + real(kind=c_real) , intent(in), dimension(ncol) :: sgh + real(kind=c_real) , intent(in), dimension(ncol, 0:pver) :: pint + integer(kind=c_int) , intent(out), dimension(ncol) :: src_level, tend_level + real(kind=c_real) , intent(out), dimension(ncol, -pgwv:pgwv, 0:pver) :: tau + real(kind=c_real) , intent(out), dimension(ncol, pver) :: ubm + real(kind=c_real) , intent(out), dimension(ncol, 0:pver) :: ubi + real(kind=c_real) , intent(out), dimension(ncol) :: xv, yv + real(kind=c_real) , intent(out), dimension(ncol, -pgwv:pgwv) :: c + + call gw_oro_src(ncol, u, v, t, sgh, pmid, pint, dpm, zm, nm, src_level, tend_level, tau, ubm, ubi, xv, yv, c) + end subroutine gw_oro_src_c end module gw_iso_c diff --git a/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp b/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp index 34696c292ce1..4a62466a6e07 100644 --- a/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp +++ b/components/eamxx/src/physics/gw/tests/infra/gw_test_data.cpp @@ -46,6 +46,26 @@ void gw_front_gw_sources_c(Int ncol, Int ngwv, Int kbot, Real* frontgf, Real* ta void gw_cm_src_c(Int ncol, Int ngwv, Int kbot, Real* u, Real* v, Real* frontgf, Int* src_level, Int* tend_level, Real* tau, Real* ubm, Real* ubi, Real* xv, Real* yv, Real* c); +void gw_convect_init_c(Int maxh, Int maxuh, Real plev_src_wind, Real* mfcc_in); + +void gw_convect_project_winds_c(Int ncol, Real* u, Real* v, Real* xv, Real* yv, Real* ubm, Real* ubi); + +void gw_heating_depth_c(Int ncol, Real maxq0_conversion_factor, Real hdepth_scaling_factor, bool use_gw_convect_old, Real* zm, Real* netdt, Int* mini, Int* maxi, Real* hdepth, Real* maxq0_out, Real* maxq0); + +void gw_storm_speed_c(Int ncol, Real storm_speed_min, Real* ubm, Int* mini, Int* maxi, Int* storm_speed, Real* uh, Real* umin, Real* umax); + +void gw_convect_gw_sources_c(Int ncol, Int ngwv, Real* lat, Real hdepth_min, Real* hdepth, Int* mini, Int* maxi, Real* netdt, Real* uh, Int* storm_speed, Real* maxq0, Real* umin, Real* umax, Real* tau); + +void gw_beres_src_c(Int ncol, Int ngwv, Real* lat, Real* u, Real* v, Real* netdt, Real* zm, Int* src_level, Int* tend_level, Real* tau, Real* ubm, Real* ubi, Real* xv, Real* yv, Real* c, Real* hdepth, Real* maxq0_out, Real maxq0_conversion_factor, Real hdepth_scaling_factor, Real hdepth_min, Real storm_speed_min, bool use_gw_convect_old); + +void gw_ediff_c(Int ncol, Int ngwv, Int kbot, Int ktop, Int* tend_level, Real* gwut, Real* ubm, Real* nm, Real* rho, Real dt, Real gravit, Real* pmid, Real* rdpm, Real* c, Real* egwdffi, Real *decomp_ca, Real *decomp_cc, Real *decomp_dnom, Real *decomp_ze); + +void gw_diff_tend_c(Int ncol, Int kbot, Int ktop, Real* q, Real dt, Real *decomp_ca, Real *decomp_cc, Real *decomp_dnom, Real *decomp_ze, Real* dq); + +void gw_oro_init_c(); + +void gw_oro_src_c(Int ncol, Real* u, Real* v, Real* t, Real* sgh, Real* pmid, Real* pint, Real* dpm, Real* zm, Real* nm, Int* src_level, Int* tend_level, Real* tau, Real* ubm, Real* ubi, Real* xv, Real* yv, Real* c); + } // extern "C" : end _c decls // Wrapper around gw_init @@ -140,6 +160,79 @@ void gw_cm_src(GwCmSrcData& d) d.transpose(); } +void gw_convect_init(GwConvectInitData& d) +{ + gw_init(d.init); + d.transpose(); + gw_convect_init_c(d.maxh, d.maxuh, d.plev_src_wind, d.mfcc_in); + d.transpose(); +} + +void gw_convect_project_winds(GwConvectProjectWindsData& d) +{ + gw_convect_init(d.init); + d.transpose(); + gw_convect_project_winds_c(d.ncol, d.u, d.v, d.xv, d.yv, d.ubm, d.ubi); + d.transpose(); +} + +void gw_heating_depth(GwHeatingDepthData& d) +{ + gw_convect_init(d.init); + d.transpose(); + gw_heating_depth_c(d.ncol, d.maxq0_conversion_factor, d.hdepth_scaling_factor, d.use_gw_convect_old, d.zm, d.netdt, d.mini, d.maxi, d.hdepth, d.maxq0_out, d.maxq0); + d.transpose(); +} + +void gw_storm_speed(GwStormSpeedData& d) +{ + gw_convect_init(d.init); + d.transpose(); + gw_storm_speed_c(d.ncol, d.storm_speed_min, d.ubm, d.mini, d.maxi, d.storm_speed, d.uh, d.umin, d.umax); + d.transpose(); +} + +void gw_convect_gw_sources(GwConvectGwSourcesData& d) +{ + gw_convect_init(d.init); + d.transpose(); + gw_convect_gw_sources_c(d.ncol, d.ngwv, d.lat, d.hdepth_min, d.hdepth, d.mini, d.maxi, d.netdt, d.uh, d.storm_speed, d.maxq0, d.umin, d.umax, d.tau); + d.transpose(); +} + +void gw_beres_src(GwBeresSrcData& d) +{ + gw_convect_init(d.init); + d.transpose(); + gw_beres_src_c(d.ncol, d.ngwv, d.lat, d.u, d.v, d.netdt, d.zm, d.src_level, d.tend_level, d.tau, d.ubm, d.ubi, d.xv, d.yv, d.c, d.hdepth, d.maxq0_out, d.maxq0_conversion_factor, d.hdepth_scaling_factor, d.hdepth_min, d.storm_speed_min, d.use_gw_convect_old); + d.transpose(); +} + +void gw_ediff(GwEdiffData& d) +{ + gw_init(d.init); + d.transpose(); + gw_ediff_c(d.ncol, d.ngwv, d.kbot, d.ktop, d.tend_level, d.gwut, d.ubm, d.nm, d.rho, d.dt, GWC::gravit, d.pmid, d.rdpm, d.c, d.egwdffi, d.decomp_ca, d.decomp_cc, d.decomp_dnom, d.decomp_ze); + d.transpose(); +} + +void gw_diff_tend(GwDiffTendData& d) +{ + gw_init(d.init); + d.transpose(); + gw_diff_tend_c(d.ncol, d.kbot, d.ktop, d.q, d.dt, d.decomp_ca, d.decomp_cc, d.decomp_dnom, d.decomp_ze, d.dq); + d.transpose(); +} + +void gw_oro_src(GwOroSrcData& d) +{ + gw_init(d.init); + gw_oro_init_c(); + d.transpose(); + gw_oro_src_c(d.ncol, d.u, d.v, d.t, d.sgh, d.pmid, d.pint, d.dpm, d.zm, d.nm, d.src_level, d.tend_level, d.tau, d.ubm, d.ubi, d.xv, d.yv, d.c); + d.transpose(); +} + // end _c impls } // namespace gw diff --git a/components/eamxx/src/physics/gw/tests/infra/gw_test_data.hpp b/components/eamxx/src/physics/gw/tests/infra/gw_test_data.hpp index e81b2b2cbf6b..5d0147ebd07c 100644 --- a/components/eamxx/src/physics/gw/tests/infra/gw_test_data.hpp +++ b/components/eamxx/src/physics/gw/tests/infra/gw_test_data.hpp @@ -399,6 +399,277 @@ struct GwCmSrcData : public PhysicsTestData { PTD_STD_DEF_INIT(GwCmSrcData, 3, ncol, ngwv, kbot); }; +struct GwConvectInitData : public PhysicsTestData{ + // Inputs + Int maxh, maxuh; + Real plev_src_wind; + Real *mfcc_in; + GwInit init; + + GwConvectInitData(Int maxh_, Int maxuh_, Real plev_src_wind_, GwInit init_) : + PhysicsTestData({ + {maxh_, maxuh_*2 + 1, init_.pgwv*2 + 1} + }, + { + {&mfcc_in} + }), + maxh(maxh_), maxuh(maxuh_), plev_src_wind(plev_src_wind_), init(init_) + {} + + PTD_STD_DEF_INIT(GwConvectInitData, 3, maxh, maxuh, plev_src_wind); +}; + +struct GwConvectProjectWindsData : public PhysicsTestData { + // Inputs + Int ncol; + Real *u, *v; + GwConvectInitData init; + + // Outputs + Real *xv, *yv, *ubm, *ubi; + + GwConvectProjectWindsData(Int ncol_, GwConvectInitData init_) : + PhysicsTestData({ + {ncol_, init_.init.pver}, + {ncol_}, + {ncol_, init_.init.pver + 1} + }, + { + {&u, &v, &ubm}, + {&xv, &yv}, + {&ubi} + }), + ncol(ncol_), init(init_) + {} + + PTD_STD_DEF_INIT(GwConvectProjectWindsData, 1, ncol); +}; + +struct GwHeatingDepthData : public PhysicsTestData { + // Inputs + Int ncol; + Real maxq0_conversion_factor, hdepth_scaling_factor; + bool use_gw_convect_old; + Real *zm, *netdt; + GwConvectInitData init; + + // Outputs + Int *mini, *maxi; + Real *hdepth, *maxq0_out, *maxq0; + + GwHeatingDepthData(Int ncol_, Real maxq0_conversion_factor_, Real hdepth_scaling_factor_, bool use_gw_convect_old_, GwConvectInitData init_) : + PhysicsTestData({ + {ncol_, init_.init.pver}, + {ncol_}, + {ncol_} + }, + { + {&zm, &netdt}, + {&hdepth, &maxq0_out, &maxq0} + }, + { + {&mini, &maxi} + }), + ncol(ncol_), maxq0_conversion_factor(maxq0_conversion_factor_), hdepth_scaling_factor(hdepth_scaling_factor_), use_gw_convect_old(use_gw_convect_old_), init(init_) + {} + + PTD_STD_DEF_INIT(GwHeatingDepthData, 4, ncol, maxq0_conversion_factor, hdepth_scaling_factor, use_gw_convect_old); +}; + +struct GwStormSpeedData : public PhysicsTestData { + // Inputs + Int ncol; + Real storm_speed_min; + Real *ubm; + Int *mini, *maxi; + GwConvectInitData init; + + // Outputs + Int *storm_speed; + Real *uh, *umin, *umax; + + GwStormSpeedData(Int ncol_, Real storm_speed_min_, GwConvectInitData init_) : + PhysicsTestData({ + {ncol_, init_.init.pver}, + {ncol_}, + {ncol_} + }, + { + {&ubm}, + {&uh, &umin, &umax} + }, + { + {&mini, &maxi, &storm_speed} + }), + ncol(ncol_), storm_speed_min(storm_speed_min_), init(init_) + {} + + PTD_STD_DEF_INIT(GwStormSpeedData, 2, ncol, storm_speed_min); +}; + +struct GwConvectGwSourcesData : public PhysicsTestData { + // Inputs + Int ncol, ngwv; + Real *lat, *hdepth, *netdt, *uh, *maxq0, *umin, *umax; + Real hdepth_min; + Int *mini, *maxi, *storm_speed; + GwConvectInitData init; + + // Outputs + Real *tau; + + GwConvectGwSourcesData(Int ncol_, Int ngwv_, Real hdepth_min_, GwConvectInitData init_) : + PhysicsTestData({ + {ncol_}, + {ncol_, init_.init.pver}, + {ncol_, init_.init.pgwv*2 + 1, init_.init.pver + 1}, + {ncol_} + }, + { + {&lat, &hdepth, &uh, &maxq0, &umin, &umax}, + {&netdt}, + {&tau} + }, + { + {&mini, &maxi, &storm_speed} + }), + ncol(ncol_), ngwv(ngwv_), hdepth_min(hdepth_min_), init(init_) + {} + + PTD_STD_DEF_INIT(GwConvectGwSourcesData, 3, ncol, ngwv, hdepth_min); +}; + +struct GwBeresSrcData : public PhysicsTestData { + // Inputs + Int ncol, ngwv; + Real *lat, *u, *v, *netdt, *zm; + Real maxq0_conversion_factor, hdepth_scaling_factor, hdepth_min, storm_speed_min; + bool use_gw_convect_old; + GwConvectInitData init; + + // Outputs + Int *src_level, *tend_level; + Real *tau, *ubm, *ubi, *xv, *yv, *c, *hdepth, *maxq0_out; + + GwBeresSrcData(Int ncol_, Int ngwv_, Real maxq0_conversion_factor_, Real hdepth_scaling_factor_, Real hdepth_min_, Real storm_speed_min_, bool use_gw_convect_old_, GwConvectInitData init_) : + PhysicsTestData({ + {ncol_}, + {ncol_, init_.init.pver}, + {ncol_, init_.init.pgwv*2 + 1, init_.init.pver + 1}, + {ncol_, init_.init.pver + 1}, + {ncol_, init_.init.pgwv*2 + 1}, + {ncol_} + }, + { + {&lat, &xv, &yv, &hdepth, &maxq0_out}, + {&u, &v, &zm, &ubm, &netdt}, + {&tau}, + {&ubi}, + {&c} + }, + { + {&src_level, &tend_level} + }), + ncol(ncol_), ngwv(ngwv_), maxq0_conversion_factor(maxq0_conversion_factor_), hdepth_scaling_factor(hdepth_scaling_factor_), hdepth_min(hdepth_min_), storm_speed_min(storm_speed_min_), use_gw_convect_old(use_gw_convect_old_), init(init_) + {} + + PTD_STD_DEF_INIT(GwBeresSrcData, 7, ncol, ngwv, maxq0_conversion_factor, hdepth_scaling_factor, hdepth_min, storm_speed_min, use_gw_convect_old); +}; + +struct GwEdiffData : public PhysicsTestData { + // Inputs + Int ncol, ngwv, kbot, ktop; + Int *tend_level; + Real *gwut, *ubm, *nm, *rho, *pmid, *rdpm, *c; + Real dt; + GwInit init; + + // Outputs + Real *egwdffi; + Real *decomp_ca, *decomp_cc, *decomp_dnom, *decomp_ze; + + GwEdiffData(Int ncol_, Int ngwv_, Int kbot_, Int ktop_, Real dt_, GwInit init_) : + PhysicsTestData({ + {ncol_, init_.pver, 2*ngwv_ + 1}, + {ncol_, init_.pver}, + {ncol_, init_.pver + 1}, + {ncol_, 2*ngwv_ + 1}, + {ncol_} + }, + { + {&gwut}, + {&ubm, &nm, &pmid, &rdpm, &decomp_ca, &decomp_cc, &decomp_dnom, &decomp_ze}, + {&rho, &egwdffi}, + {&c} + }, + { + {&tend_level} + }), + ncol(ncol_), ngwv(ngwv_), kbot(kbot_), ktop(ktop_), dt(dt_), init(init_) + {} + + PTD_STD_DEF_INIT(GwEdiffData, 5, ncol, ngwv, kbot, ktop, dt); +}; + +struct GwDiffTendData : public PhysicsTestData { + // Inputs + Int ncol, kbot, ktop; + Real *q; + Real dt; + Real *decomp_ca, *decomp_cc, *decomp_dnom, *decomp_ze; + GwInit init; + + // Outputs + Real *dq; + + GwDiffTendData(Int ncol_, Int kbot_, Int ktop_, Real dt_, GwInit init_) : + PhysicsTestData({ + {ncol_, init_.pver} + }, + { + {&q, &dq, &decomp_ca, &decomp_cc, &decomp_dnom, &decomp_ze} + }), + ncol(ncol_), kbot(kbot_), ktop(ktop_), dt(dt_), init(init_) + {} + + PTD_STD_DEF_INIT(GwDiffTendData, 4, ncol, kbot, ktop, dt); +}; + +struct GwOroSrcData : public PhysicsTestData { + // Inputs + Int ncol; + Real *u, *v, *t, *sgh, *pmid, *pint, *dpm, *zm, *nm; + GwInit init; + + // Outputs + Int *src_level, *tend_level; + Real *tau, *ubm, *ubi, *xv, *yv, *c; + + GwOroSrcData(Int ncol_, GwInit init_) : + PhysicsTestData({ + {ncol_, init_.pver}, + {ncol_}, + {ncol_, init_.pver + 1}, + {ncol_, init_.pgwv*2 + 1, init_.pver + 1}, + {ncol_, init_.pgwv*2 + 1}, + {ncol_} + }, + { + {&u, &v, &t, &pmid, &dpm, &zm, &nm, &ubm}, + {&sgh, &xv, &yv}, + {&pint, &ubi}, + {&tau}, + {&c} + }, + { + {&src_level, &tend_level} + }), + ncol(ncol_), init(init_) + {} + + PTD_STD_DEF_INIT(GwOroSrcData, 1, ncol); +}; + // Glue functions to call fortran from from C++ with the Data struct void gwd_compute_tendencies_from_stress_divergence(GwdComputeTendenciesFromStressDivergenceData& d); void gw_prof(GwProfData& d); @@ -410,6 +681,14 @@ void gw_drag_prof(GwDragProfData& d); void gw_front_project_winds(GwFrontProjectWindsData& d); void gw_front_gw_sources(GwFrontGwSourcesData& d); void gw_cm_src(GwCmSrcData& d); +void gw_convect_project_winds(GwConvectProjectWindsData& d); +void gw_heating_depth(GwHeatingDepthData& d); +void gw_storm_speed(GwStormSpeedData& d); +void gw_convect_gw_sources(GwConvectGwSourcesData& d); +void gw_beres_src(GwBeresSrcData& d); +void gw_ediff(GwEdiffData& d); +void gw_diff_tend(GwDiffTendData& d); +void gw_oro_src(GwOroSrcData& d); extern "C" { // _f function decls } diff --git a/components/eamxx/src/physics/gw/tests/infra/gw_unit_tests_common.hpp b/components/eamxx/src/physics/gw/tests/infra/gw_unit_tests_common.hpp index 164749ea1eaa..a03fbde1ff5d 100644 --- a/components/eamxx/src/physics/gw/tests/infra/gw_unit_tests_common.hpp +++ b/components/eamxx/src/physics/gw/tests/infra/gw_unit_tests_common.hpp @@ -86,6 +86,14 @@ struct UnitWrap { struct TestGwFrontProjectWinds; struct TestGwFrontGwSources; struct TestGwCmSrc; + struct TestGwConvectProjectWinds; + struct TestGwHeatingDepth; + struct TestGwStormSpeed; + struct TestGwConvectGwSources; + struct TestGwBeresSrc; + struct TestGwEdiff; + struct TestGwDiffTend; + struct TestGwOroSrc; }; // UnitWrap };