diff --git a/.github/workflows/cpuarch.yml b/.github/workflows/cpuarch.yml index 672d2639..56184e03 100644 --- a/.github/workflows/cpuarch.yml +++ b/.github/workflows/cpuarch.yml @@ -2,6 +2,8 @@ name: CPU Compilation/Unit Tests on: push: + pull_request: + types: [ready_for_review] jobs: check-commit: @@ -14,6 +16,10 @@ jobs: - name: Check commit message id: check_message run: | + if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.action }}" == "ready_for_review" ]]; then + echo "run_tests=true" >> "$GITHUB_OUTPUT" + exit 0 + fi if git log -1 --pretty=%B | grep -q "CPUTEST"; then echo "run_tests=true" >> "$GITHUB_OUTPUT" else diff --git a/CMakeLists.txt b/CMakeLists.txt index 260c3e87..109a1f2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(PROJECT_NAME entity) project( ${PROJECT_NAME} - VERSION 1.3.0 + VERSION 1.4.0 LANGUAGES CXX C) add_compile_options("-D ENTITY_VERSION=\"${PROJECT_VERSION}\"") set(hash_cmd "git diff --quiet src/ && echo $(git rev-parse HEAD) ") @@ -62,7 +62,7 @@ set(gpu_aware_mpi CACHE BOOL "Enable GPU-aware MPI") # -------------------------- Compilation settings -------------------------- # -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -162,9 +162,9 @@ if(${output}) find_or_fetch_dependency(adios2 FALSE QUIET) add_compile_options("-D OUTPUT_ENABLED") if(${mpi}) - set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx11_mpi) + set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx_mpi) else() - set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx11) + set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx) endif() endif() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 1f3ed3c6..6561c304 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -58,12 +58,12 @@ function(find_or_fetch_dependency package_name header_only mode) FetchContent_Declare( ${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY} - GIT_TAG 4.7.01) + GIT_TAG 5.0.0) elseif(${package_name} STREQUAL "adios2") FetchContent_Declare( ${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY} - GIT_TAG v2.10.2) + GIT_TAG v2.11.0) else() FetchContent_Declare(${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY}) diff --git a/dev/nix/adios2.nix b/dev/nix/adios2.nix index a3890b78..810c228d 100644 --- a/dev/nix/adios2.nix +++ b/dev/nix/adios2.nix @@ -6,9 +6,9 @@ let name = "adios2"; - version = "2.10.2"; + version = "2.11.0"; cmakeFlags = { - CMAKE_CXX_STANDARD = "17"; + CMAKE_CXX_STANDARD = "20"; CMAKE_CXX_EXTENSIONS = "OFF"; CMAKE_POSITION_INDEPENDENT_CODE = "TRUE"; BUILD_SHARED_LIBS = "ON"; @@ -30,7 +30,7 @@ stdenv.mkDerivation { src = pkgs.fetchgit { url = "https://github.com/ornladios/ADIOS2/"; rev = "v${version}"; - sha256 = "sha256-NVyw7xoPutXeUS87jjVv1YxJnwNGZAT4QfkBLzvQbwg="; + sha256 = "sha256-yHPI///17poiCEb7Luu5qfqxTWm9Nh+o9r57mZT26U0="; }; nativeBuildInputs = with pkgs; [ diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index 7d86e665..d8ae115c 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -7,10 +7,10 @@ let name = "kokkos"; - pversion = "4.7.01"; + pversion = "5.0.0"; compilerPkgs = { "HIP" = with pkgs.rocmPackages; [ - llvm.rocm-merged-llvm + llvm.llvm rocm-core clr rocthrust @@ -39,7 +39,7 @@ let "HIP" = [ "-D Kokkos_ENABLE_HIP=ON" "-D Kokkos_ARCH_${getArch { }}=ON" - "-D AMDGPU_TARGETS=${builtins.replaceStrings [ "amd_" ] [ "" ] (pkgs.lib.toLower (getArch { }))}" + "-D GPU_TARGETS=${builtins.replaceStrings [ "amd_" ] [ "" ] (pkgs.lib.toLower (getArch { }))}" "-D CMAKE_CXX_COMPILER=hipcc" ]; "CUDA" = [ @@ -56,7 +56,7 @@ pkgs.stdenv.mkDerivation rec { src = pkgs.fetchgit { url = "https://github.com/kokkos/kokkos/"; rev = "${pversion}"; - sha256 = "sha256-MgphOsKE8umgYxVQZzex+elgvDDC09JaMCoU5YXaLco="; + sha256 = "sha256-C4DarqnEcdF3+19TPqcM0A9bcQSkKTJkB8b7OkzC7T8="; }; nativeBuildInputs = with pkgs; [ @@ -78,7 +78,7 @@ pkgs.stdenv.mkDerivation rec { configurePhase = '' cmake -B build -D CMAKE_BUILD_TYPE=Release \ - -D CMAKE_CXX_STANDARD=17 \ + -D CMAKE_CXX_STANDARD=20 \ -D CMAKE_CXX_EXTENSIONS=OFF \ -D CMAKE_POSITION_INDEPENDENT_CODE=TRUE \ ${pkgs.lib.concatStringsSep " " cmakeExtraFlags.${gpu}} \ diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index 0d4cc911..5ff7a389 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -45,8 +45,7 @@ pkgs.mkShell { adios2Pkg kokkosPkg - python312 - python312Packages.jupyter + python314 cmake-format cmake-lint diff --git a/extern/Kokkos b/extern/Kokkos index 1b1383c6..37f70304 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit 1b1383c6001f3bfe9fe309ca923c2d786600cc79 +Subproject commit 37f70304dc3676691af88d3ac3ba50cddbfa337f diff --git a/extern/adios2 b/extern/adios2 index a19dad6c..1ef0b579 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit a19dad6cecb00319825f20fd9f455ebbab903d34 +Subproject commit 1ef0b5797aeb8a1cc1bb36ec4089eaec19a2eea0 diff --git a/extern/plog b/extern/plog index e21baecd..7881eeac 160000 --- a/extern/plog +++ b/extern/plog @@ -1 +1 @@ -Subproject commit e21baecd4753f14da64ede979c5a19302618b752 +Subproject commit 7881eeacf0f31b7862f90b88e62be7ecf0dd0a45 diff --git a/minimal/CMakeLists.txt b/minimal/CMakeLists.txt index b21dd0fe..72e30026 100644 --- a/minimal/CMakeLists.txt +++ b/minimal/CMakeLists.txt @@ -89,7 +89,7 @@ if("ADIOS2_NOMPI" IN_LIST MODES) find_kokkos() find_adios2() - list(APPEND libs Kokkos::kokkos adios2::cxx11) + list(APPEND libs Kokkos::kokkos adios2::cxx) add_executable(${exec} ${src}) @@ -104,7 +104,7 @@ if("ADIOS2_MPI" IN_LIST MODES) find_package(MPI REQUIRED) find_kokkos() find_adios2() - list(APPEND libs MPI::MPI_CXX Kokkos::kokkos adios2::cxx11_mpi) + list(APPEND libs MPI::MPI_CXX Kokkos::kokkos adios2::cxx_mpi) add_executable(${exec} ${src}) diff --git a/minimal/adios2.cpp b/minimal/adios2.cpp index cd4ca3d6..c89bf383 100644 --- a/minimal/adios2.cpp +++ b/minimal/adios2.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #if defined(MPI_ENABLED) #include diff --git a/pgens/magnetosphere/pgen.hpp b/pgens/magnetosphere/pgen.hpp index 1afc8ccc..eab55ffb 100644 --- a/pgens/magnetosphere/pgen.hpp +++ b/pgens/magnetosphere/pgen.hpp @@ -52,13 +52,13 @@ namespace user { template struct DriveFields : public InitFields { - DriveFields(real_t time, + DriveFields(simtime_t time, real_t bsurf, real_t rstar, real_t omega, const std::string& field_geometry) : InitFields { bsurf, rstar, field_geometry } - , time { time } + , time { (real_t)time } , Omega { omega } {} using InitFields::bx1; @@ -113,11 +113,11 @@ namespace user { inline PGen() {} - auto AtmFields(real_t time) const -> DriveFields { + auto AtmFields(simtime_t time) const -> DriveFields { return DriveFields { time, Bsurf, Rstar, Omega, field_geom }; } - auto MatchFields(real_t) const -> InitFields { + auto MatchFields(simtime_t) const -> InitFields { return InitFields { Bsurf, Rstar, field_geom }; } }; diff --git a/pgens/shock/pgen.hpp b/pgens/shock/pgen.hpp index fc579777..c3904f02 100644 --- a/pgens/shock/pgen.hpp +++ b/pgens/shock/pgen.hpp @@ -113,7 +113,7 @@ namespace user { inline PGen() {} - auto MatchFields(real_t time) const -> InitFields { + auto MatchFields(simtime_t) const -> InitFields { return init_flds; } diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index 56a79775..f387922d 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -22,6 +22,7 @@ #include "global.h" #include "arch/kokkos_aliases.h" +#include "arch/traits.h" #include "utils/comparators.h" #include "utils/error.h" #include "utils/numeric.h" @@ -33,10 +34,9 @@ namespace arch { using namespace ntt; template + requires traits::metric::HasD struct EnergyDistribution { static constexpr auto D = M::Dim; - static constexpr bool is_energy_dist { true }; - static_assert(M::is_metric, "M must be a metric class"); EnergyDistribution(const M& metric) : metric { metric } {} diff --git a/src/archetypes/field_setter.h b/src/archetypes/field_setter.h index 5c5c4dbe..56a24af1 100644 --- a/src/archetypes/field_setter.h +++ b/src/archetypes/field_setter.h @@ -33,6 +33,10 @@ namespace arch { using namespace ntt; template + requires traits::metric::HasD && + ((S == SimEngine::SRPIC && traits::metric::HasConvert && + traits::metric::HasTransform_i) || + (S == SimEngine::GRPIC && traits::metric::HasConvert_i)) class SetEMFields_kernel { static constexpr Dimension D = M::Dim; static constexpr bool defines_ex1 = traits::has_method::value; @@ -53,7 +57,6 @@ namespace arch { (defines_dx1 == defines_dx2 && defines_dx2 == defines_dx3 && defines_bx1 == defines_bx2 && defines_bx2 == defines_bx3), "In GR mode, all components must be defined or none"); - static_assert(M::is_metric, "M must be a metric class"); ndfield_t EM; const I finit; @@ -271,69 +274,24 @@ namespace arch { if constexpr (defines_dx1 && defines_dx2 && defines_dx3) { { // dx1 - vec_t d_PU { finit.dx1({ x1_H, x2_0, x3_0 }), - finit.dx2({ x1_H, x2_0, x3_0 }), - finit.dx3({ x1_H, x2_0, x3_0 }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_, i3_ }, - d_PU, - d_U); - EM(i1, i2, i3, em::dx1) = d_U[0]; + EM(i1, i2, i3, em::dx1) = finit.dx1({ x1_H, x2_0, x3_0 }); } { // dx2 - vec_t d_PU { finit.dx1({ x1_0, x2_H, x3_0 }), - finit.dx2({ x1_0, x2_H, x3_0 }), - finit.dx3({ x1_0, x2_H, x3_0 }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_, i2_ + HALF, i3_ }, - d_PU, - d_U); - EM(i1, i2, i3, em::dx2) = d_U[1]; + EM(i1, i2, i3, em::dx2) = finit.dx2({ x1_0, x2_H, x3_0 }); } { // dx3 - vec_t d_PU { finit.dx1({ x1_0, x2_0, x3_H }), - finit.dx2({ x1_0, x2_0, x3_H }), - finit.dx3({ x1_0, x2_0, x3_H }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_, i2_, i3_ + HALF }, - d_PU, - d_U); - EM(i1, i2, i3, em::dx3) = d_U[2]; + EM(i1, i2, i3, em::dx3) = finit.dx3({ x1_0, x2_0, x3_H }); } } if constexpr (defines_bx1 && defines_bx2 && defines_bx3) { { // bx1 - vec_t b_PU { finit.bx1({ x1_0, x2_H, x3_H }), - finit.bx2({ x1_0, x2_H, x3_H }), - finit.bx3({ x1_0, x2_H, x3_H }) }; - vec_t b_U { ZERO }; - metric.template transform( - { i1_, i2_ + HALF, i3_ + HALF }, - b_PU, - b_U); - EM(i1, i2, i3, em::bx1) = b_U[0]; + EM(i1, i2, i3, em::bx1) = finit.bx1({ x1_0, x2_H, x3_H }); } { // bx2 - vec_t b_PU { finit.bx1({ x1_H, x2_0, x3_H }), - finit.bx2({ x1_H, x2_0, x3_H }), - finit.bx3({ x1_H, x2_0, x3_H }) }; - vec_t b_U { ZERO }; - metric.template transform( - { i1_ + HALF, i2_, i3_ + HALF }, - b_PU, - b_U); - EM(i1, i2, i3, em::bx2) = b_U[1]; + EM(i1, i2, i3, em::bx2) = finit.bx2({ x1_H, x2_0, x3_H }); } { // bx3 - vec_t b_PU { finit.bx1({ x1_H, x2_H, x3_0 }), - finit.bx2({ x1_H, x2_H, x3_0 }), - finit.bx3({ x1_H, x2_H, x3_0 }) }; - vec_t b_U { ZERO }; - metric.template transform( - { i1_ + HALF, i2_ + HALF, i3_ }, - b_PU, - b_U); - EM(i1, i2, i3, em::bx3) = b_U[2]; + EM(i1, i2, i3, em::bx3) = finit.bx3({ x1_H, x2_H, x3_0 }); } } } else { diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 79743ce6..1543e265 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -53,6 +53,7 @@ namespace arch { * - array_t: maximum coordinates of the region in computational coords */ template + requires traits::metric::HasD && traits::metric::HasConvert auto DeduceRegion(const Domain& domain, const boundaries_t& box) -> std::tuple, array_t> { if (not domain.mesh.Intersects(box)) { @@ -107,6 +108,7 @@ namespace arch { * - array_t: maximum coordinates of the region in computational coords */ template + requires traits::metric::HasD auto ComputeNumInject(const SimulationParams& params, const Domain& domain, real_t number_density, @@ -198,6 +200,8 @@ namespace arch { * @tparam ED2 Energy distribution type for species 2 */ template + requires traits::metric::HasD && traits::energydist::IsValid && + traits::energydist::IsValid inline void InjectUniform(const SimulationParams& params, Domain& domain, const std::pair& species, @@ -205,9 +209,6 @@ namespace arch { real_t number_density, bool use_weights = false, const boundaries_t& box = {}) { - static_assert(M::is_metric, "M must be a metric class"); - static_assert(ED1::is_energy_dist, "ED1 must be an energy distribution class"); - static_assert(ED2::is_energy_dist, "ED2 must be an energy distribution class"); raise::ErrorIf((M::CoordType != Coord::Cart) && (not use_weights), "Weights must be used for non-Cartesian coordinates", HERE); @@ -278,7 +279,6 @@ namespace arch { spidx_t spidx, const std::map>& data, bool use_weights = false) { - static_assert(M::is_metric, "M must be a metric class"); const auto n_inject = data.at("ux1").size(); auto injector_kernel = kernel::GlobalInjector_kernel( local_domain.species[spidx - 1], @@ -309,6 +309,8 @@ namespace arch { * @tparam SD Spatial distribution type */ template + requires traits::metric::HasD && traits::energydist::IsValid && + traits::energydist::IsValid && traits::spatialdist::IsValid inline void InjectNonUniform(const SimulationParams& params, Domain& domain, const std::pair& species, @@ -317,10 +319,6 @@ namespace arch { real_t number_density, bool use_weights = false, const boundaries_t& box = {}) { - static_assert(M::is_metric, "M must be a metric class"); - static_assert(ED1::is_energy_dist, "ED1 must be an energy distribution class"); - static_assert(ED2::is_energy_dist, "ED2 must be an energy distribution class"); - static_assert(SD::is_spatial_dist, "SD must be a spatial distribution class"); raise::ErrorIf((M::CoordType != Coord::Cart) && (not use_weights), "Weights must be used for non-Cartesian coordinates", HERE); diff --git a/src/archetypes/problem_generator.h b/src/archetypes/problem_generator.h index da116672..efcec90a 100644 --- a/src/archetypes/problem_generator.h +++ b/src/archetypes/problem_generator.h @@ -23,15 +23,16 @@ #include "enums.h" #include "global.h" +#include "arch/traits.h" + #include "framework/parameters.h" namespace arch { using namespace ntt; template + requires traits::metric::HasD struct ProblemGenerator { - static_assert(M::is_metric, "M must be a metric class"); - static constexpr bool is_pgen { true }; static constexpr Dimension D { M::Dim }; static constexpr Coord C { M::CoordType }; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index 68477208..be42c3ba 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -27,9 +27,9 @@ namespace arch { using namespace ntt; template + requires traits::metric::HasD struct SpatialDistribution { - static constexpr bool is_spatial_dist { true }; - static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; SpatialDistribution(const M& metric) : metric { metric } {} diff --git a/src/archetypes/utils.h b/src/archetypes/utils.h index 3447558f..b3eb24ae 100644 --- a/src/archetypes/utils.h +++ b/src/archetypes/utils.h @@ -45,7 +45,6 @@ namespace arch { const std::pair, std::vector>& drift_four_vels = {{ ZERO, ZERO, ZERO }, { ZERO, ZERO, ZERO }}, bool use_weights = false, const boundaries_t& box = {}) { - static_assert(M::is_metric, "M must be a metric class"); const auto mass_1 = domain.species[species.first - 1].mass(); const auto mass_2 = domain.species[species.second - 1].mass(); @@ -93,7 +92,6 @@ namespace arch { const std::pair, std::vector>& drift_four_vels = {{ ZERO, ZERO, ZERO }, { ZERO, ZERO, ZERO }}, bool use_weights = false, const boundaries_t& box = {}) { - static_assert(M::is_metric, "M must be a metric class"); InjectUniformMaxwellians(params, domain, diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 17103f1d..3117b082 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -36,7 +36,7 @@ #if defined(OUTPUT_ENABLED) #include - #include + #include #endif // OUTPUT_ENABLED #if defined(MPI_ENABLED) @@ -49,9 +49,11 @@ namespace ntt { template + concept IsCompatibleWithEngine = traits::metric::HasD; + + template + requires IsCompatibleWithEngine class Engine { - static_assert(M::is_metric, "template arg for Engine class has to be a metric"); - static_assert(user::PGen::is_pgen, "unrecognized problem generator"); protected: #if defined(OUTPUT_ENABLED) @@ -83,7 +85,6 @@ namespace ntt { }; static constexpr Dimension D { M::Dim }; - static constexpr bool is_engine { true }; Engine(const SimulationParams& params) : m_params { params } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index f98b117d..e822ba3f 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -15,6 +15,7 @@ namespace ntt { template + requires IsCompatibleWithEngine void Engine::init() { if constexpr (pgen_is_ok) { m_metadomain.InitStatsWriter(m_params, is_resuming); @@ -26,8 +27,7 @@ namespace ntt { if (not is_resuming) { // start a new simulation with initial conditions logger::Checkpoint("Loading initial conditions", HERE); - if constexpr ( - traits::has_member>::value) { + if constexpr (traits::pgen::HasInitFlds>) { logger::Checkpoint("Initializing fields from problem generator", HERE); m_metadomain.runOnLocalDomains([&](auto& loc_dom) { Kokkos::parallel_for( @@ -39,8 +39,7 @@ namespace ntt { loc_dom.mesh.metric }); }); } - if constexpr ( - traits::has_member>::value) { + if constexpr (traits::pgen::HasInitPrtls, Domain>) { logger::Checkpoint("Initializing particles from problem generator", HERE); m_metadomain.runOnLocalDomains([&](auto& loc_dom) { m_pgen.InitPrtls(loc_dom); diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index f3d6f3b3..34df741c 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -115,6 +115,7 @@ namespace ntt { } // namespace template + requires IsCompatibleWithEngine void Engine::print_report() const { const auto colored_stdout = m_params.template get( "diagnostics.colored_stdout"); diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 961e3920..7d81fe4b 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -11,6 +11,7 @@ namespace ntt { template + requires IsCompatibleWithEngine void Engine::run() { if constexpr (pgen_is_ok) { init(); @@ -43,7 +44,7 @@ namespace ntt { }); // poststep (if defined) if constexpr ( - traits::has_method::value) { + traits::pgen::HasCustomPostStep>) { timers.start("Custom"); m_metadomain.runOnLocalDomains([&timers, this](auto& dom) { m_pgen.CustomPostStep(step, time, dom); @@ -62,7 +63,7 @@ namespace ntt { #if defined(OUTPUT_ENABLED) timers.start("Output"); if constexpr ( - traits::has_method::value) { + traits::pgen::HasCustomFieldOutput, M::Dim>) { auto lambda_custom_field_output = [&](const std::string& name, ndfield_t& buff, index_t idx, @@ -81,7 +82,7 @@ namespace ntt { print_output &= m_metadomain.Write(m_params, step, step - 1, time, time - dt); } if constexpr ( - traits::has_method::value) { + traits::pgen::HasCustomStatOutput>) { auto lambda_custom_stat = [&](const std::string& name, timestep_t step, simtime_t time, diff --git a/src/engines/engine_traits.h b/src/engines/engine_traits.h index 28a74bea..d26b0add 100644 --- a/src/engines/engine_traits.h +++ b/src/engines/engine_traits.h @@ -1,5 +1,3 @@ -// SPDX-License-Identifier: BSD-3-Clause - #ifndef ENGINES_ENGINE_TRAITS_H #define ENGINES_ENGINE_TRAITS_H diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 35e544a9..275c70b5 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -66,6 +66,7 @@ namespace ntt { }; template + requires IsCompatibleWithEngine class GRPICEngine : public Engine { using base_t = Engine; using pgen_t = user::PGen; @@ -696,17 +697,17 @@ namespace ntt { Kokkos::parallel_for( "OpenBCFields", range, - kernel::bc::gr::HorizonBoundaries_kernel(domain.fields.em, - i1_min, - tags, - nfilter)); + kernel::bc::gr::HorizonBoundaries_kernel(domain.fields.em, + i1_min, + tags, + nfilter)); Kokkos::parallel_for( "OpenBCFields", range, - kernel::bc::gr::HorizonBoundaries_kernel(domain.fields.em0, - i1_min, - tags, - nfilter)); + kernel::bc::gr::HorizonBoundaries_kernel(domain.fields.em0, + i1_min, + tags, + nfilter)); } } @@ -974,19 +975,19 @@ namespace ntt { } void TimeAverageDB(domain_t& domain) { - Kokkos::parallel_for("TimeAverageDB", - domain.mesh.rangeActiveCells(), - kernel::gr::TimeAverageDB_kernel(domain.fields.em, - domain.fields.em0, - domain.mesh.metric)); + Kokkos::parallel_for( + "TimeAverageDB", + domain.mesh.rangeActiveCells(), + kernel::gr::TimeAverageDB_kernel(domain.fields.em, + domain.fields.em0)); } void TimeAverageJ(domain_t& domain) { - Kokkos::parallel_for("TimeAverageJ", - domain.mesh.rangeActiveCells(), - kernel::gr::TimeAverageJ_kernel(domain.fields.cur, - domain.fields.cur0, - domain.mesh.metric)); + Kokkos::parallel_for( + "TimeAverageJ", + domain.mesh.rangeActiveCells(), + kernel::gr::TimeAverageJ_kernel(domain.fields.cur, + domain.fields.cur0)); } void CurrentsDeposit(domain_t& domain) { diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 9a4ec31f..fc95e6cf 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -49,6 +49,9 @@ namespace ntt { template + requires IsCompatibleWithEngine && + traits::metric::HasH_ij && traits::metric::HasConvert_i && + traits::metric::HasSqrtH_ij class SRPICEngine : public Engine { using base_t = Engine; @@ -369,7 +372,7 @@ namespace ntt { : ZERO; // toggle to indicate whether pgen defines the external force bool has_extforce = false; - if constexpr (traits::has_member::value) { + if constexpr (traits::pgen::HasExtForce) { has_extforce = true; // toggle to indicate whether the ext force applies to current species if (traits::has_member::value) { @@ -442,7 +445,7 @@ namespace ntt { gca_larmor_max, gca_eovrb_max, sync_coeff, comp_coeff )); } else if (not has_atmosphere and has_extforce) { - if constexpr (traits::has_member::value) { + if constexpr (traits::pgen::HasExtForce) { const auto force = kernel::sr::Force { m_pgen.ext_force @@ -474,7 +477,7 @@ namespace ntt { raise::Error("External force not implemented", HERE); } } else { // has_atmosphere and has_extforce - if constexpr (traits::has_member::value) { + if constexpr (traits::pgen::HasExtForce) { const auto force = kernel::sr::Force { m_pgen.ext_force, {gx1, gx2, gx3}, x_surf, ds @@ -570,8 +573,7 @@ namespace ntt { const auto V0 = m_params.template get("scales.V0"); const auto ppc0 = m_params.template get("particles.ppc0"); const auto coeff = -dt * q0 / (B0 * V0); - if constexpr ( - traits::has_member::value) { + if constexpr (traits::pgen::HasExtCurrent) { const std::vector xmin { domain.mesh.extent(in::x1).first, domain.mesh.extent(in::x2).first, domain.mesh.extent(in::x3).first }; @@ -720,8 +722,7 @@ namespace ntt { } if (dim == in::x1) { - if constexpr ( - traits::has_member::value) { + if constexpr (traits::pgen::HasMatchFields) { auto match_fields = m_pgen.MatchFields(time); call_match_fields(domain.fields.em, domain.mesh.flds_bc(), @@ -732,8 +733,7 @@ namespace ntt { tags, range_min, range_max); - } else if constexpr ( - traits::has_member::value) { + } else if constexpr (traits::pgen::HasMatchFieldsInX1) { auto match_fields = m_pgen.MatchFieldsInX1(time); call_match_fields(domain.fields.em, domain.mesh.flds_bc(), @@ -747,8 +747,7 @@ namespace ntt { } } else if (dim == in::x2) { if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - if constexpr ( - traits::has_member::value) { + if constexpr (traits::pgen::HasMatchFields) { auto match_fields = m_pgen.MatchFields(time); call_match_fields(domain.fields.em, domain.mesh.flds_bc(), @@ -759,8 +758,7 @@ namespace ntt { tags, range_min, range_max); - } else if constexpr ( - traits::has_member::value) { + } else if constexpr (traits::pgen::HasMatchFieldsInX2) { auto match_fields = m_pgen.MatchFieldsInX2(time); call_match_fields(domain.fields.em, domain.mesh.flds_bc(), @@ -777,8 +775,7 @@ namespace ntt { } } else if (dim == in::x3) { if constexpr (M::Dim == Dim::_3D) { - if constexpr ( - traits::has_member::value) { + if constexpr (traits::pgen::HasMatchFields) { auto match_fields = m_pgen.MatchFields(time); call_match_fields(domain.fields.em, domain.mesh.flds_bc(), @@ -789,8 +786,7 @@ namespace ntt { tags, range_min, range_max); - } else if constexpr ( - traits::has_member::value) { + } else if constexpr (traits::pgen::HasMatchFieldsInX3) { auto match_fields = m_pgen.MatchFieldsInX3(time); call_match_fields(domain.fields.em, domain.mesh.flds_bc(), @@ -900,22 +896,16 @@ namespace ntt { if (tags & BC::B) { comps.push_back(normal_b_comp); } - if constexpr (traits::has_member::value) { - raise::Error("Non-const fixed fields not implemented", HERE); - } else if constexpr ( - traits::has_member::value) { + if constexpr (traits::pgen::HasFixFieldsConst) { for (const auto& comp : comps) { - auto value = ZERO; - bool shouldset = false; - if constexpr ( - traits::has_member::value) { - // if fix field function present, read from it - const auto newset = m_pgen.FixFieldsConst( - (bc_in)(sign * ((short)dim + 1)), - (em)comp); - value = newset.first; - shouldset = newset.second; - } + auto value = ZERO; + bool shouldset = false; + // if fix field function present, read from it + const auto newset = m_pgen.FixFieldsConst( + (bc_in)(sign * ((short)dim + 1)), + (em)comp); + value = newset.first; + shouldset = newset.second; if (shouldset) { if constexpr (M::Dim == Dim::_1D) { Kokkos::deep_copy( @@ -1078,7 +1068,7 @@ namespace ntt { /** * atmosphere field boundaries */ - if constexpr (traits::has_member::value) { + if constexpr (traits::pgen::HasAtmFields) { const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); const auto dd = static_cast(dim); boundaries_t box; diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index cc4eac43..6e10eda2 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -14,6 +14,7 @@ namespace ntt { template + requires IsCompatibleWithMetadomain void Metadomain::InitCheckpointWriter(adios2::ADIOS* ptr_adios, const SimulationParams& params) { raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); @@ -64,6 +65,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain auto Metadomain::WriteCheckpoint(const SimulationParams& params, timestep_t current_step, timestep_t finished_step, @@ -110,6 +112,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::ContinueFromCheckpoint(adios2::ADIOS* ptr_adios, const SimulationParams& params) { raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index ae4ec83d..66ee4e06 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -197,6 +197,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::CommunicateFields(Domain& domain, CommTags tags) { // const auto comm_fields = (tags & Comm::E) or (tags & Comm::B) or // (tags & Comm::J) or (tags & Comm::D) or @@ -417,6 +418,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::SynchronizeFields(Domain& domain, CommTags tags, const range_tuple_t& components) { @@ -573,6 +575,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::CommunicateParticles(Domain& domain) { #if defined(MPI_ENABLED) logger::Checkpoint("Communicating particles\n", HERE); @@ -664,6 +667,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::RemoveDeadParticles(Domain& domain) { for (auto& species : domain.species) { species.RemoveDead(); diff --git a/src/framework/domain/domain.h b/src/framework/domain/domain.h index b6cbb985..c4546110 100644 --- a/src/framework/domain/domain.h +++ b/src/framework/domain/domain.h @@ -43,6 +43,7 @@ #include "global.h" #include "arch/directions.h" +#include "arch/traits.h" #include "utils/formatting.h" #include "utils/numeric.h" @@ -57,9 +58,10 @@ #include namespace ntt { + template + requires traits::metric::HasD struct Domain { - static_assert(M::is_metric, "template arg for Mesh class has to be a metric"); static constexpr Dimension D { M::Dim }; Mesh mesh; diff --git a/src/framework/domain/mesh.h b/src/framework/domain/mesh.h index 89f6a1b9..3cfd9117 100644 --- a/src/framework/domain/mesh.h +++ b/src/framework/domain/mesh.h @@ -17,6 +17,7 @@ #include "global.h" #include "arch/directions.h" +#include "arch/traits.h" #include "utils/comparators.h" #include "utils/error.h" #include "utils/numeric.h" @@ -31,8 +32,8 @@ namespace ntt { template + requires traits::metric::HasD && traits::metric::HasConvert_i struct Mesh : public Grid { - static_assert(M::is_metric, "template arg for Mesh class has to be a metric"); static constexpr bool is_mesh { true }; static constexpr Dimension D { M::Dim }; diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index cbea4084..e31015c2 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -26,6 +26,7 @@ namespace ntt { template + requires IsCompatibleWithMetadomain Metadomain::Metadomain(unsigned int global_ndomains, const std::vector& global_decomposition, const std::vector& global_ncells, @@ -57,6 +58,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::initialValidityCheck() const { // ensure everything has the correct shape raise::ErrorIf(g_decomposition.size() != (std::size_t)D, @@ -94,6 +96,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::createEmptyDomains() { /* decompose and compute cell & domain offsets ------------------------ */ auto d_ncells = tools::Decompose(g_ndomains, g_mesh.n_active(), g_decomposition); @@ -189,6 +192,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::redefineNeighbors() { for (unsigned int idx { 0 }; idx < g_ndomains; ++idx) { // offset of the subdomain[idx] @@ -229,6 +233,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::redefineBoundaries() { for (unsigned int idx { 0 }; idx < g_ndomains; ++idx) { // offset of the subdomain[idx] @@ -318,6 +323,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::finalValidityCheck() const { for (unsigned int idx { 0 }; idx < g_ndomains; ++idx) { const auto& current_domain = g_subdomains[idx]; @@ -363,6 +369,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::metricCompatibilityCheck() const { const auto epsilon = std::numeric_limits::epsilon() * static_cast(100.0); @@ -397,6 +404,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::setFldsBC(const bc_in& dir, const FldsBC& new_bcs) { if (dir == bc_in::Mx1) { if constexpr (M::Dim == Dim::_1D) { @@ -465,6 +473,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::setPrtlBC(const bc_in& dir, const PrtlBC& new_bcs) { if (dir == bc_in::Mx1) { if constexpr (M::Dim == Dim::_1D) { diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index a456879b..bd6ec864 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -19,6 +19,7 @@ #include "global.h" #include "arch/kokkos_aliases.h" +#include "arch/traits.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" @@ -35,7 +36,7 @@ #include "output/writer.h" #include - #include + #include #endif // OUTPUT_ENABLED #include @@ -46,10 +47,14 @@ namespace ntt { + template + concept IsCompatibleWithMetadomain = traits::metric::HasD && + traits::metric::HasConvert && + traits::metric::HasTotVolume; + template + requires IsCompatibleWithMetadomain struct Metadomain { - static_assert(M::is_metric, - "template arg for Metadomain class has to be a metric"); static constexpr Dimension D { M::Dim }; void initialValidityCheck() const; diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 4d625c4d..b4ff2123 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -31,6 +31,7 @@ namespace ntt { template + requires IsCompatibleWithMetadomain void Metadomain::InitWriter(adios2::ADIOS* ptr_adios, const SimulationParams& params) { raise::ErrorIf( @@ -263,6 +264,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain void Metadomain::CommunicateVectorPotential(unsigned short buff_idx) { if constexpr (M::Dim == Dim::_2D) { auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); @@ -316,6 +318,7 @@ namespace ntt { #endif template + requires IsCompatibleWithMetadomain auto Metadomain::Write( const SimulationParams& params, timestep_t current_step, diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 64690d69..83d65956 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -23,6 +23,7 @@ namespace ntt { template + requires IsCompatibleWithMetadomain void Metadomain::InitStatsWriter(const SimulationParams& params, bool is_resuming) { raise::ErrorIf( @@ -182,6 +183,7 @@ namespace ntt { } template + requires IsCompatibleWithMetadomain auto Metadomain::WriteStats( const SimulationParams& params, timestep_t current_step, diff --git a/src/framework/simulation.h b/src/framework/simulation.h index 33750030..d8696532 100644 --- a/src/framework/simulation.h +++ b/src/framework/simulation.h @@ -36,12 +36,9 @@ namespace ntt { ~Simulation(); template